mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-05 19:24:39 +00:00
add theme saving and indexing
This commit is contained in:
@@ -45,6 +45,7 @@
|
|||||||
"@types/react": "^18.2.55",
|
"@types/react": "^18.2.55",
|
||||||
"@types/react-dom": "^18.2.19",
|
"@types/react-dom": "^18.2.19",
|
||||||
"@types/sortablejs": "^1.15.7",
|
"@types/sortablejs": "^1.15.7",
|
||||||
|
"@types/uuid": "^9.0.8",
|
||||||
"@types/webextension-polyfill": "^0.10.7",
|
"@types/webextension-polyfill": "^0.10.7",
|
||||||
"@uiw/codemirror-extensions-color": "^4.21.25",
|
"@uiw/codemirror-extensions-color": "^4.21.25",
|
||||||
"@uiw/codemirror-theme-github": "^4.21.25",
|
"@uiw/codemirror-theme-github": "^4.21.25",
|
||||||
@@ -72,6 +73,7 @@
|
|||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"ts-loader": "^9.5.1",
|
"ts-loader": "^9.5.1",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
|
"uuid": "^9.0.1",
|
||||||
"vite": "^5.2.2",
|
"vite": "^5.2.2",
|
||||||
"webextension-polyfill": "^0.10.0"
|
"webextension-polyfill": "^0.10.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,10 +57,43 @@ export const deleteTheme = async (themeName: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const sendThemeUpdate = debounce((updatedTheme: CustomTheme) => {
|
export const sendThemeUpdate = debounce((updatedTheme: CustomTheme) => {
|
||||||
// Send the updated theme to the content script for live preview
|
// Create a copy of the updatedTheme object
|
||||||
browser.runtime.sendMessage({
|
const updatedThemeCopy: CustomTheme = { ...updatedTheme };
|
||||||
type: 'currentTab',
|
|
||||||
info: 'UpdateThemePreview',
|
// Convert image blobs to base64
|
||||||
body: updatedTheme,
|
const base64ConversionPromises = updatedThemeCopy.CustomImages.map(async (image) => {
|
||||||
|
const base64 = await blobToBase64(image.blob);
|
||||||
|
return { ...image, base64 };
|
||||||
});
|
});
|
||||||
}, 100);
|
|
||||||
|
Promise.all(base64ConversionPromises)
|
||||||
|
.then((convertedImages) => {
|
||||||
|
// Update the CustomImages array with the converted base64 images
|
||||||
|
updatedThemeCopy.CustomImages = convertedImages;
|
||||||
|
|
||||||
|
// Send the updated theme to the content script for live preview
|
||||||
|
browser.runtime.sendMessage({
|
||||||
|
type: 'currentTab',
|
||||||
|
info: 'UpdateThemePreview',
|
||||||
|
body: updatedThemeCopy,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error converting image blobs to base64:', error);
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
// Helper function to convert a Blob to base64
|
||||||
|
const blobToBase64 = (blob: Blob): Promise<string> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onloadend = () => {
|
||||||
|
const base64 = reader.result as string;
|
||||||
|
resolve(base64);
|
||||||
|
};
|
||||||
|
reader.onerror = (error) => {
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -5,9 +5,12 @@ import Accordion from '../components/Accordian';
|
|||||||
import Switch from '../components/Switch';
|
import Switch from '../components/Switch';
|
||||||
import { sendThemeUpdate } from '../hooks/ThemeManagment';
|
import { sendThemeUpdate } from '../hooks/ThemeManagment';
|
||||||
import { XMarkIcon } from '@heroicons/react/24/outline';
|
import { XMarkIcon } from '@heroicons/react/24/outline';
|
||||||
|
import localforage from 'localforage';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
function ThemeCreator() {
|
function ThemeCreator({ themeID }: { themeID?: string }) {
|
||||||
const [theme, setTheme] = useState<CustomTheme>({
|
const [theme, setTheme] = useState<CustomTheme>({
|
||||||
|
id: uuidv4(),
|
||||||
name: '',
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
defaultColour: '',
|
defaultColour: '',
|
||||||
@@ -16,28 +19,38 @@ function ThemeCreator() {
|
|||||||
CustomImages: []
|
CustomImages: []
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (themeID) {
|
||||||
|
localforage.getItem(themeID).then((theme) => {
|
||||||
|
if (theme) {
|
||||||
|
setTheme(theme as CustomTheme);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const generateImageId = () => {
|
const generateImageId = () => {
|
||||||
return '_' + Math.random().toString(36).substr(2, 9);
|
return '_' + Math.random().toString(36).substr(2, 9);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleImageUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleImageUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const file = event.target.files?.[0];
|
const file = event.target.files?.[0];
|
||||||
if (file) {
|
if (file) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = () => {
|
reader.onload = async () => {
|
||||||
const imageUrl = reader.result as string;
|
const imageBlob = await fetch(reader.result as string).then(res => res.blob());
|
||||||
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, blob: imageBlob, variableName }],
|
||||||
};
|
};
|
||||||
setTheme(updatedTheme);
|
setTheme(updatedTheme);
|
||||||
sendThemeUpdate(updatedTheme);
|
sendThemeUpdate(updatedTheme);
|
||||||
};
|
};
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveImage = (imageId: string) => {
|
const handleRemoveImage = (imageId: string) => {
|
||||||
const updatedTheme = {
|
const updatedTheme = {
|
||||||
@@ -64,9 +77,25 @@ function ThemeCreator() {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveTheme = () => {
|
const saveTheme = async () => {
|
||||||
// Save the theme to the database
|
try {
|
||||||
}
|
await localforage.setItem(theme.id, theme);
|
||||||
|
await localforage.getItem('customThemes').then((themes: unknown) => {
|
||||||
|
const themeList = themes as string[] | null;
|
||||||
|
if (themeList) {
|
||||||
|
if (!themeList.includes(theme.id)) {
|
||||||
|
themeList.push(theme.id);
|
||||||
|
localforage.setItem('customThemes', themeList);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
localforage.setItem('customThemes', [theme.id]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log('Theme saved successfully!');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error saving theme:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
sendThemeUpdate(theme);
|
sendThemeUpdate(theme);
|
||||||
@@ -131,7 +160,7 @@ function ThemeCreator() {
|
|||||||
{theme.CustomImages.map((image) => (
|
{theme.CustomImages.map((image) => (
|
||||||
<div key={image.id} className="flex items-center h-16 py-2 mb-4 bg-white rounded-lg shadow-lg dark:bg-zinc-900">
|
<div key={image.id} className="flex items-center h-16 py-2 mb-4 bg-white rounded-lg shadow-lg dark:bg-zinc-900">
|
||||||
<div className="flex-1 h-full ">
|
<div className="flex-1 h-full ">
|
||||||
<img src={image.url} alt={image.variableName} className="object-contain h-full rounded" />
|
<img src={URL.createObjectURL(image.blob)} alt={image.variableName} className="object-contain h-full rounded" />
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
type CustomTheme = {
|
type CustomTheme = {
|
||||||
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
defaultColour: string;
|
defaultColour: string;
|
||||||
@@ -9,6 +10,6 @@ type CustomTheme = {
|
|||||||
|
|
||||||
type CustomImage = {
|
type CustomImage = {
|
||||||
id: string;
|
id: string;
|
||||||
url: string;
|
blob: Blob;
|
||||||
variableName: string;
|
variableName: string;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user