custom themes: auto remove unused css variables

This commit is contained in:
SethBurkart123
2024-03-31 21:56:20 +11:00
parent 93e97d3c21
commit 3373590a1d
2 changed files with 81 additions and 47 deletions
+16 -10
View File
@@ -26,7 +26,7 @@ export default function ThemeCreator() {
reader.onload = () => { reader.onload = () => {
const imageUrl = reader.result as string; const imageUrl = reader.result as string;
const imageId = generateImageId(); const imageId = generateImageId();
const variableName = `--custom-image-${theme.CustomImages.length}`; const variableName = `custom-image-${theme.CustomImages.length}`;
const updatedTheme = { const updatedTheme = {
...theme, ...theme,
CustomImages: [...theme.CustomImages, { id: imageId, url: imageUrl, variableName }], CustomImages: [...theme.CustomImages, { id: imageId, url: imageUrl, variableName }],
@@ -57,8 +57,10 @@ export default function ThemeCreator() {
}; };
function CodeUpdate(value: string) { function CodeUpdate(value: string) {
const updatedTheme = { ...theme, CustomCSS: value }; setTheme((prevTheme) => ({
setTheme(updatedTheme); ...prevTheme,
CustomCSS: value,
}));
} }
useEffect(() => { useEffect(() => {
@@ -113,25 +115,29 @@ export default function ThemeCreator() {
<div className='h-4'></div> <div className='h-4'></div>
<Accordion defaultOpened title='Custom Images'>
{theme.CustomImages.map((image, index) => ( {theme.CustomImages.map((image, index) => (
<div key={image.id}> <div key={image.id} className="flex items-center p-2 mb-4 bg-white rounded-lg shadow dark:bg-zinc-900">
<img src={image.url} alt={`Custom Image ${index + 1}`} /> <div className="flex-grow mr-4">
<img src={image.url} alt={`Custom Image ${index + 1}`} className="object-contain w-auto rounded max-h-32" />
</div>
<input <input
type='text' type="text"
value={image.variableName} value={image.variableName}
onChange={(e) => handleImageVariableChange(image.id, e.target.value)} onChange={(e) => handleImageVariableChange(image.id, e.target.value)}
placeholder='CSS Variable Name' placeholder="CSS Variable Name"
className="flex-grow w-full p-2 transition-all duration-300 rounded-lg focus:outline-none ring-0 focus:ring-1 ring-zinc-100 dark:ring-zinc-700 dark:bg-zinc-900 dark:text-white"
/> />
<button onClick={() => handleRemoveImage(image.id)}>Remove</button> <button onClick={() => handleRemoveImage(image.id)} className="px-4 py-2 ml-4 text-sm text-white transition bg-red-500 rounded hover:bg-red-600 dark:text-white">
Remove
</button>
</div> </div>
))} ))}
<input <input
type='file' type='file'
accept='image/*' accept='image/*'
onChange={handleImageUpload} onChange={handleImageUpload}
/> />
</Accordion>
<div className='h-4'></div> <div className='h-4'></div>
+53 -25
View File
@@ -161,51 +161,80 @@ export const disableTheme = async () => {
localforage.removeItem('selectedTheme'); localforage.removeItem('selectedTheme');
}; };
let imageData: CustomImage[] = []; const imageData: Record<string, { url: string; variableName: string }> = {};
let previousTheme: CustomTheme = null;
export const UpdateThemePreview = async (updatedTheme: CustomTheme) => { export const UpdateThemePreview = async (updatedTheme: CustomTheme) => {
console.log(updatedTheme) console.log(updatedTheme);
if (updatedTheme.CustomImages.length !== imageData.length) {
updatedTheme.CustomImages.forEach((image) => {
updateImage(image.id, image.url);
})
}
const { CustomCSS, CustomImages, defaultColour } = updatedTheme; const { CustomCSS, CustomImages, defaultColour } = updatedTheme;
// Apply custom CSS // Update image data
let styleElement = document.getElementById('theme-preview-styles'); const currentImageIds = Object.keys(imageData);
if (!styleElement) { const updatedImageIds = CustomImages.map((image) => image.id);
styleElement = document.createElement('style');
styleElement.id = 'theme-preview-styles'; // Remove unused images from imageData and document
document.head.appendChild(styleElement); currentImageIds.forEach((imageId) => {
if (!updatedImageIds.includes(imageId)) {
const { variableName } = imageData[imageId];
removeImageFromDocument(variableName);
delete imageData[imageId];
} }
styleElement.textContent = CustomCSS; });
// Update or add new images to imageData
CustomImages.forEach((image) => {
const existingImage = imageData[image.id];
if (existingImage && existingImage.variableName !== image.variableName) {
// Remove the previous variableName from the document
removeImageFromDocument(existingImage.variableName);
}
imageData[image.id] = {
url: updateImage(image),
variableName: image.variableName,
};
});
// Apply custom CSS
applyCustomCSS(CustomCSS);
// Apply default color // Apply default color
if (defaultColour !== '') { if (defaultColour !== '') {
browser.storage.local.set({ selectedColor: defaultColour }); browser.storage.local.set({ selectedColor: defaultColour });
} }
// Apply custom images
CustomImages.forEach((image) => { CustomImages.forEach((image) => {
// @ts-expect-error - not sure why its yelling at me :( const imageUrl = imageData[image.id]?.url;
const imageUrl = imageData[image.id];
if (imageUrl) { if (imageUrl) {
document.documentElement.style.setProperty(image.variableName, `url(${imageUrl})`); document.documentElement.style.setProperty('--' + image.variableName, `url(${imageUrl})`);
} }
}); });
};
function applyCustomCSS(customCSS: string) {
let styleElement = document.getElementById('theme-preview-styles');
if (!styleElement) {
styleElement = document.createElement('style');
styleElement.id = 'theme-preview-styles';
document.head.appendChild(styleElement);
}
styleElement.textContent = customCSS;
} }
export function updateImage(imageId: string, imageDataURI: string) { function removeImageFromDocument(variableName: string) {
document.documentElement.style.removeProperty('--' + variableName);
}
export function updateImage(image: CustomImage) {
// Extract base64 data from the data URI // Extract base64 data from the data URI
const base64Index = imageDataURI.indexOf(',') + 1; const base64Index = image.url.indexOf(',') + 1;
const imageBase64 = imageDataURI.substring(base64Index); const imageBase64 = image.url.substring(base64Index);
// Convert base64 to blob // Convert base64 to blob
const byteCharacters = atob(imageBase64); const byteCharacters = atob(imageBase64);
const byteNumbers = new Array(byteCharacters.length); const byteNumbers = new Uint8Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) { for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i); byteNumbers[i] = byteCharacters.charCodeAt(i);
} }
@@ -215,6 +244,5 @@ export function updateImage(imageId: string, imageDataURI: string) {
// Convert blob to blob URL // Convert blob to blob URL
const imageUrl = URL.createObjectURL(blob); const imageUrl = URL.createObjectURL(blob);
// @ts-expect-error - same problem 😭 return imageUrl;
imageData[imageId] = imageUrl;
} }