mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 03:34:40 +00:00
separate thems into separate files
This commit is contained in:
+1
-1
@@ -21,7 +21,7 @@ import assessmentsicon from './seqta/icons/assessmentsIcon'
|
|||||||
import browser from 'webextension-polyfill'
|
import browser from 'webextension-polyfill'
|
||||||
import coursesicon from './seqta/icons/coursesIcon'
|
import coursesicon from './seqta/icons/coursesIcon'
|
||||||
import { delay } from "./seqta/utils/delay"
|
import { delay } from "./seqta/utils/delay"
|
||||||
import { enableCurrentTheme } from './seqta/ui/Themes'
|
import { enableCurrentTheme } from "./seqta/ui/themes/enableCurrent";
|
||||||
import iframeCSS from "./css/iframe.scss?raw"
|
import iframeCSS from "./css/iframe.scss?raw"
|
||||||
import { onError } from './seqta/utils/onError'
|
import { onError } from './seqta/utils/onError'
|
||||||
import stringToHTML from './seqta/utils/stringToHTML'
|
import stringToHTML from './seqta/utils/stringToHTML'
|
||||||
|
|||||||
@@ -1,292 +0,0 @@
|
|||||||
import browser from 'webextension-polyfill'
|
|
||||||
import localforage from 'localforage';
|
|
||||||
import { CustomImage, CustomImageBase64, CustomTheme, CustomThemeBase64, ThemeList } from '../../interface/types/CustomThemes';
|
|
||||||
import { base64toblobURL } from '../utils/imageConversions';
|
|
||||||
|
|
||||||
const imageData: Record<string, { url: string; variableName: string }> = {};
|
|
||||||
|
|
||||||
export const enableCurrentTheme = async () => {
|
|
||||||
const themeId = await browser.storage.local.get('selectedTheme') as { selectedTheme: string };
|
|
||||||
if (themeId.selectedTheme) {
|
|
||||||
const theme = await localforage.getItem(themeId.selectedTheme) as CustomTheme;
|
|
||||||
if (theme) {
|
|
||||||
await applyTheme(theme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const deleteTheme = async (themeId: string) => {
|
|
||||||
try {
|
|
||||||
const theme = await localforage.getItem(themeId) as CustomTheme;
|
|
||||||
removeTheme(theme);
|
|
||||||
|
|
||||||
await localforage.removeItem(themeId);
|
|
||||||
const themeIds = await localforage.getItem('customThemes') as string[] | null;
|
|
||||||
if (themeIds) {
|
|
||||||
const updatedThemeIds = themeIds.filter((id) => id !== themeId);
|
|
||||||
await localforage.setItem('customThemes', updatedThemeIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
await browser.storage.local.set({ selectedTheme: '' });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error deleting theme:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAvailableThemes = async (): Promise<ThemeList | {}> => {
|
|
||||||
try {
|
|
||||||
const themeIds = await localforage.getItem('customThemes') as string[] | null;
|
|
||||||
console.log('Available themes:', themeIds);
|
|
||||||
if (themeIds) {
|
|
||||||
const themes = await Promise.all(
|
|
||||||
themeIds.map(async (id) => {
|
|
||||||
const theme = await localforage.getItem(id) as CustomTheme;
|
|
||||||
const { CustomImages, ...themeWithoutImages } = theme;
|
|
||||||
return themeWithoutImages;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectedTheme = await browser.storage.local.get('selectedTheme') as { selectedTheme: string };
|
|
||||||
|
|
||||||
return { themes, selectedTheme: selectedTheme.selectedTheme ? selectedTheme.selectedTheme : '' };
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
themes: [],
|
|
||||||
selectedTheme: '',
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error getting available themes:', error);
|
|
||||||
return {
|
|
||||||
themes: [],
|
|
||||||
selectedTheme: ''
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const saveTheme = async (theme: CustomThemeBase64) => {
|
|
||||||
try {
|
|
||||||
const updatedTheme: CustomTheme = {
|
|
||||||
...theme,
|
|
||||||
CustomImages: await Promise.all(
|
|
||||||
theme.CustomImages.map(async (image) => ({
|
|
||||||
id: image.id,
|
|
||||||
blob: await fetch(image.url).then((res) => res.blob()),
|
|
||||||
variableName: image.variableName,
|
|
||||||
}))
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
disableTheme();
|
|
||||||
|
|
||||||
console.debug('Theme to save:', updatedTheme)
|
|
||||||
|
|
||||||
await localforage.setItem(updatedTheme.id, updatedTheme);
|
|
||||||
await localforage.getItem('customThemes').then((themes: unknown) => {
|
|
||||||
const themeList = themes as string[] | null;
|
|
||||||
if (themeList) {
|
|
||||||
if (!themeList.includes(updatedTheme.id)) {
|
|
||||||
themeList.push(updatedTheme.id);
|
|
||||||
localforage.setItem('customThemes', themeList);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
localforage.setItem('customThemes', [updatedTheme.id]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
console.debug('Theme saved successfully!');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error saving theme:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const UpdateThemePreview = async (updatedTheme: CustomThemeBase64 /* Omit<CustomTheme, 'CustomImages'> & { CustomImages: Omit<CustomImage, 'blob'>[] } */) => {
|
|
||||||
const { CustomCSS, CustomImages, defaultColour } = updatedTheme;
|
|
||||||
|
|
||||||
// Update image data
|
|
||||||
const currentImageIds = Object.keys(imageData);
|
|
||||||
const updatedImageIds = CustomImages.map((image) => image.id);
|
|
||||||
|
|
||||||
// Remove unused images from imageData and document
|
|
||||||
currentImageIds.forEach((imageId) => {
|
|
||||||
if (!updatedImageIds.includes(imageId)) {
|
|
||||||
const { variableName } = imageData[imageId];
|
|
||||||
removeImageFromDocument(variableName);
|
|
||||||
delete imageData[imageId];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Update the variableName in imageData
|
|
||||||
imageData[image.id].variableName = image.variableName;
|
|
||||||
|
|
||||||
// Update the variableName in the document
|
|
||||||
document.documentElement.style.setProperty('--' + image.variableName, `url(${existingImage.url})`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (image.url) {
|
|
||||||
UpdateImageData({
|
|
||||||
id: image.id,
|
|
||||||
base64: image.url
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
imageData[image.id] = {
|
|
||||||
url: imageData[image.id]?.url || '',
|
|
||||||
variableName: image.variableName,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Apply custom CSS
|
|
||||||
applyCustomCSS(CustomCSS);
|
|
||||||
|
|
||||||
// Apply default color
|
|
||||||
if (defaultColour !== '') {
|
|
||||||
browser.storage.local.set({ selectedColor: defaultColour });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const UpdateImageData = (imageData2: { id: string; base64: string }) => {
|
|
||||||
const { id, base64 } = imageData2;
|
|
||||||
|
|
||||||
if (imageData[id]) {
|
|
||||||
imageData[id].url = base64toblobURL(base64);
|
|
||||||
const { variableName } = imageData[id];
|
|
||||||
document.documentElement.style.setProperty('--' + variableName, `url(${imageData[id].url})`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function applyCustomCSS(customCSS: string) {
|
|
||||||
let styleElement = document.getElementById('custom-theme');
|
|
||||||
if (!styleElement) {
|
|
||||||
styleElement = document.createElement('style');
|
|
||||||
styleElement.id = 'custom-theme';
|
|
||||||
document.head.appendChild(styleElement);
|
|
||||||
}
|
|
||||||
styleElement.textContent = customCSS;
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeImageFromDocument(variableName: string) {
|
|
||||||
document.documentElement.style.removeProperty('--' + variableName);
|
|
||||||
}
|
|
||||||
|
|
||||||
const applyTheme = async (theme: CustomTheme) => {
|
|
||||||
let CustomCSS = '';
|
|
||||||
let CustomImages: CustomImage[] = [];
|
|
||||||
let defaultColour = '';
|
|
||||||
|
|
||||||
if (theme?.CustomCSS) CustomCSS = theme.CustomCSS;
|
|
||||||
if (theme?.CustomImages) CustomImages = theme.CustomImages;
|
|
||||||
if (theme?.defaultColour) defaultColour = theme.defaultColour;
|
|
||||||
|
|
||||||
// Apply custom CSS
|
|
||||||
applyCustomCSS(CustomCSS);
|
|
||||||
|
|
||||||
// Apply default color
|
|
||||||
if (defaultColour !== '') {
|
|
||||||
browser.storage.local.set({ selectedColor: defaultColour });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply custom images
|
|
||||||
CustomImages.forEach((image) => {
|
|
||||||
const imageUrl = URL.createObjectURL(image.blob);
|
|
||||||
document.documentElement.style.setProperty('--' + image.variableName, `url(${imageUrl})`);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeTheme = (theme: CustomTheme) => {
|
|
||||||
// Remove custom CSS
|
|
||||||
const styleElement = document.getElementById('custom-theme');
|
|
||||||
if (styleElement) {
|
|
||||||
styleElement.parentNode?.removeChild(styleElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset default color
|
|
||||||
//browser.storage.local.set({ selectedColor: '' });
|
|
||||||
|
|
||||||
// Remove custom images
|
|
||||||
const customImageVariables = theme.CustomImages.map((image) => image.variableName);
|
|
||||||
customImageVariables.forEach((variableName) => {
|
|
||||||
document.documentElement.style.removeProperty('--' + variableName);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const blobToBase64 = (blob: Blob) => {
|
|
||||||
return new Promise<string>((resolve, reject) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = () => {
|
|
||||||
const base64 = reader.result as string;
|
|
||||||
resolve(base64);
|
|
||||||
};
|
|
||||||
reader.onerror = reject;
|
|
||||||
reader.readAsDataURL(blob);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getTheme = async (themeId: string): Promise<CustomThemeBase64 | null> => {
|
|
||||||
try {
|
|
||||||
const theme = await localforage.getItem(themeId) as CustomTheme;
|
|
||||||
|
|
||||||
const CustomImages: CustomImageBase64[] = await Promise.all(
|
|
||||||
theme.CustomImages.map(async (image) => {
|
|
||||||
const base64 = await blobToBase64(image.blob);
|
|
||||||
return {
|
|
||||||
id: image.id,
|
|
||||||
variableName: image.variableName,
|
|
||||||
url: base64,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...theme,
|
|
||||||
CustomImages,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error getting theme:', error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const setTheme = async (themeId: string) => {
|
|
||||||
try {
|
|
||||||
const enabledTheme = await browser.storage.local.get('selectedTheme') as { selectedTheme: string };
|
|
||||||
const theme = await localforage.getItem(themeId) as CustomTheme;
|
|
||||||
|
|
||||||
console.debug('Loading theme', theme)
|
|
||||||
|
|
||||||
// Remove the currently enabled theme
|
|
||||||
if (enabledTheme.selectedTheme) {
|
|
||||||
const currentTheme = await localforage.getItem(enabledTheme.selectedTheme) as CustomTheme;
|
|
||||||
if (currentTheme) {
|
|
||||||
removeTheme(currentTheme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await applyTheme(theme);
|
|
||||||
await browser.storage.local.set({ selectedTheme: themeId });
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error setting theme:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const disableTheme = async () => {
|
|
||||||
try {
|
|
||||||
const enabledTheme = await browser.storage.local.get('selectedTheme') as { selectedTheme: string };
|
|
||||||
if (enabledTheme.selectedTheme) {
|
|
||||||
const theme = await localforage.getItem(enabledTheme.selectedTheme) as CustomTheme;
|
|
||||||
if (theme) {
|
|
||||||
removeTheme(theme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await browser.storage.local.set({ selectedTheme: '' });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error disabling theme:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { base64toblobURL } from '../../utils/imageConversions';
|
||||||
|
|
||||||
|
export const imageData: Record<string, { url: string; variableName: string }> = {};
|
||||||
|
|
||||||
|
export const UpdateImageData = (image: { id: string; base64: string }) => {
|
||||||
|
const { id, base64 } = image;
|
||||||
|
|
||||||
|
if (imageData[id]) {
|
||||||
|
imageData[id].url = base64toblobURL(base64);
|
||||||
|
const { variableName } = imageData[id];
|
||||||
|
document.documentElement.style.setProperty('--' + variableName, `url(${imageData[id].url})`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export function applyCustomCSS(customCSS: string) {
|
||||||
|
let styleElement = document.getElementById('custom-theme');
|
||||||
|
if (!styleElement) {
|
||||||
|
styleElement = document.createElement('style');
|
||||||
|
styleElement.id = 'custom-theme';
|
||||||
|
document.head.appendChild(styleElement);
|
||||||
|
}
|
||||||
|
styleElement.textContent = customCSS;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeImageFromDocument(variableName: string) {
|
||||||
|
document.documentElement.style.removeProperty('--' + variableName);
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import browser from 'webextension-polyfill';
|
||||||
|
import { CustomThemeBase64 } from '../../../interface/types/CustomThemes';
|
||||||
|
import { imageData, removeImageFromDocument, UpdateImageData, applyCustomCSS } from './Themes';
|
||||||
|
|
||||||
|
|
||||||
|
export const UpdateThemePreview = async (updatedTheme: CustomThemeBase64 /* Omit<CustomTheme, 'CustomImages'> & { CustomImages: Omit<CustomImage, 'blob'>[] } */) => {
|
||||||
|
const { CustomCSS, CustomImages, defaultColour } = updatedTheme;
|
||||||
|
|
||||||
|
// Update image data
|
||||||
|
const currentImageIds = Object.keys(imageData);
|
||||||
|
const updatedImageIds = CustomImages.map((image) => image.id);
|
||||||
|
|
||||||
|
// Remove unused images from imageData and document
|
||||||
|
currentImageIds.forEach((imageId) => {
|
||||||
|
if (!updatedImageIds.includes(imageId)) {
|
||||||
|
const { variableName } = imageData[imageId];
|
||||||
|
removeImageFromDocument(variableName);
|
||||||
|
delete imageData[imageId];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Update the variableName in imageData
|
||||||
|
imageData[image.id].variableName = image.variableName;
|
||||||
|
|
||||||
|
// Update the variableName in the document
|
||||||
|
document.documentElement.style.setProperty('--' + image.variableName, `url(${existingImage.url})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image.url) {
|
||||||
|
UpdateImageData({
|
||||||
|
id: image.id,
|
||||||
|
base64: image.url
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
imageData[image.id] = {
|
||||||
|
url: imageData[image.id]?.url || '',
|
||||||
|
variableName: image.variableName,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Apply custom CSS
|
||||||
|
applyCustomCSS(CustomCSS);
|
||||||
|
|
||||||
|
// Apply default color
|
||||||
|
if (defaultColour !== '') {
|
||||||
|
browser.storage.local.set({ selectedColor: defaultColour });
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import browser from 'webextension-polyfill';
|
||||||
|
import { CustomImage, CustomTheme } from '../../../interface/types/CustomThemes';
|
||||||
|
import { applyCustomCSS } from './Themes';
|
||||||
|
|
||||||
|
|
||||||
|
export const applyTheme = async (theme: CustomTheme) => {
|
||||||
|
let CustomCSS = '';
|
||||||
|
let CustomImages: CustomImage[] = [];
|
||||||
|
let defaultColour = '';
|
||||||
|
|
||||||
|
if (theme?.CustomCSS) CustomCSS = theme.CustomCSS;
|
||||||
|
if (theme?.CustomImages) CustomImages = theme.CustomImages;
|
||||||
|
if (theme?.defaultColour) defaultColour = theme.defaultColour;
|
||||||
|
|
||||||
|
// Apply custom CSS
|
||||||
|
applyCustomCSS(CustomCSS);
|
||||||
|
|
||||||
|
// Apply default color
|
||||||
|
if (defaultColour !== '') {
|
||||||
|
browser.storage.local.set({ selectedColor: defaultColour });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply custom images
|
||||||
|
CustomImages.forEach((image) => {
|
||||||
|
const imageUrl = URL.createObjectURL(image.blob);
|
||||||
|
document.documentElement.style.setProperty('--' + image.variableName, `url(${imageUrl})`);
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import browser from 'webextension-polyfill';
|
||||||
|
import localforage from 'localforage';
|
||||||
|
import { CustomTheme } from '../../../interface/types/CustomThemes';
|
||||||
|
import { removeTheme } from './removeTheme';
|
||||||
|
|
||||||
|
|
||||||
|
export const deleteTheme = async (themeId: string) => {
|
||||||
|
try {
|
||||||
|
const theme = await localforage.getItem(themeId) as CustomTheme;
|
||||||
|
removeTheme(theme);
|
||||||
|
|
||||||
|
await localforage.removeItem(themeId);
|
||||||
|
const themeIds = await localforage.getItem('customThemes') as string[] | null;
|
||||||
|
if (themeIds) {
|
||||||
|
const updatedThemeIds = themeIds.filter((id) => id !== themeId);
|
||||||
|
await localforage.setItem('customThemes', updatedThemeIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
await browser.storage.local.set({ selectedTheme: '' });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting theme:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import browser from 'webextension-polyfill';
|
||||||
|
import localforage from 'localforage';
|
||||||
|
import { CustomTheme } from '../../../interface/types/CustomThemes';
|
||||||
|
import { removeTheme } from './removeTheme';
|
||||||
|
|
||||||
|
|
||||||
|
export const disableTheme = async () => {
|
||||||
|
try {
|
||||||
|
const enabledTheme = await browser.storage.local.get('selectedTheme') as { selectedTheme: string; };
|
||||||
|
if (enabledTheme.selectedTheme) {
|
||||||
|
const theme = await localforage.getItem(enabledTheme.selectedTheme) as CustomTheme;
|
||||||
|
if (theme) {
|
||||||
|
removeTheme(theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await browser.storage.local.set({ selectedTheme: '' });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error disabling theme:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import browser from 'webextension-polyfill';
|
||||||
|
import localforage from 'localforage';
|
||||||
|
import { CustomTheme } from '../../../interface/types/CustomThemes';
|
||||||
|
import { applyTheme } from './applyTheme';
|
||||||
|
|
||||||
|
|
||||||
|
export const enableCurrentTheme = async () => {
|
||||||
|
const themeId = await browser.storage.local.get('selectedTheme') as { selectedTheme: string; };
|
||||||
|
if (themeId.selectedTheme) {
|
||||||
|
const theme = await localforage.getItem(themeId.selectedTheme) as CustomTheme;
|
||||||
|
if (theme) {
|
||||||
|
await applyTheme(theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import browser from 'webextension-polyfill';
|
||||||
|
import localforage from 'localforage';
|
||||||
|
import { CustomTheme, ThemeList } from '../../../interface/types/CustomThemes';
|
||||||
|
|
||||||
|
|
||||||
|
export const getAvailableThemes = async (): Promise<ThemeList | {}> => {
|
||||||
|
try {
|
||||||
|
const themeIds = await localforage.getItem('customThemes') as string[] | null;
|
||||||
|
console.log('Available themes:', themeIds);
|
||||||
|
if (themeIds) {
|
||||||
|
const themes = await Promise.all(
|
||||||
|
themeIds.map(async (id) => {
|
||||||
|
const theme = await localforage.getItem(id) as CustomTheme;
|
||||||
|
const { CustomImages, ...themeWithoutImages } = theme;
|
||||||
|
return themeWithoutImages;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedTheme = await browser.storage.local.get('selectedTheme') as { selectedTheme: string; };
|
||||||
|
|
||||||
|
return { themes, selectedTheme: selectedTheme.selectedTheme ? selectedTheme.selectedTheme : '' };
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
themes: [],
|
||||||
|
selectedTheme: '',
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting available themes:', error);
|
||||||
|
return {
|
||||||
|
themes: [],
|
||||||
|
selectedTheme: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import localforage from 'localforage';
|
||||||
|
import { CustomImageBase64, CustomTheme, CustomThemeBase64 } from '../../../interface/types/CustomThemes';
|
||||||
|
import { blobToBase64 } from '../../utils/blobToBase64';
|
||||||
|
|
||||||
|
|
||||||
|
export const getTheme = async (themeId: string): Promise<CustomThemeBase64 | null> => {
|
||||||
|
try {
|
||||||
|
const theme = await localforage.getItem(themeId) as CustomTheme;
|
||||||
|
|
||||||
|
const CustomImages: CustomImageBase64[] = await Promise.all(
|
||||||
|
theme.CustomImages.map(async (image) => {
|
||||||
|
const base64 = await blobToBase64(image.blob);
|
||||||
|
return {
|
||||||
|
id: image.id,
|
||||||
|
variableName: image.variableName,
|
||||||
|
url: base64,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...theme,
|
||||||
|
CustomImages,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting theme:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { CustomTheme } from '../../../interface/types/CustomThemes';
|
||||||
|
|
||||||
|
|
||||||
|
export const removeTheme = (theme: CustomTheme) => {
|
||||||
|
// Remove custom CSS
|
||||||
|
const styleElement = document.getElementById('custom-theme');
|
||||||
|
if (styleElement) {
|
||||||
|
styleElement.parentNode?.removeChild(styleElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset default color
|
||||||
|
//browser.storage.local.set({ selectedColor: '' });
|
||||||
|
// Remove custom images
|
||||||
|
const customImageVariables = theme.CustomImages.map((image) => image.variableName);
|
||||||
|
customImageVariables.forEach((variableName) => {
|
||||||
|
document.documentElement.style.removeProperty('--' + variableName);
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import localforage from 'localforage';
|
||||||
|
import { CustomTheme, CustomThemeBase64 } from '../../../interface/types/CustomThemes';
|
||||||
|
import { disableTheme } from './disableTheme';
|
||||||
|
|
||||||
|
|
||||||
|
export const saveTheme = async (theme: CustomThemeBase64) => {
|
||||||
|
try {
|
||||||
|
const updatedTheme: CustomTheme = {
|
||||||
|
...theme,
|
||||||
|
CustomImages: await Promise.all(
|
||||||
|
theme.CustomImages.map(async (image) => ({
|
||||||
|
id: image.id,
|
||||||
|
blob: await fetch(image.url).then((res) => res.blob()),
|
||||||
|
variableName: image.variableName,
|
||||||
|
}))
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
disableTheme();
|
||||||
|
|
||||||
|
console.debug('Theme to save:', updatedTheme);
|
||||||
|
|
||||||
|
await localforage.setItem(updatedTheme.id, updatedTheme);
|
||||||
|
await localforage.getItem('customThemes').then((themes: unknown) => {
|
||||||
|
const themeList = themes as string[] | null;
|
||||||
|
if (themeList) {
|
||||||
|
if (!themeList.includes(updatedTheme.id)) {
|
||||||
|
themeList.push(updatedTheme.id);
|
||||||
|
localforage.setItem('customThemes', themeList);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
localforage.setItem('customThemes', [updatedTheme.id]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.debug('Theme saved successfully!');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error saving theme:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import browser from 'webextension-polyfill';
|
||||||
|
import localforage from 'localforage';
|
||||||
|
import { CustomTheme } from '../../../interface/types/CustomThemes';
|
||||||
|
import { applyTheme } from './applyTheme';
|
||||||
|
import { removeTheme } from './removeTheme';
|
||||||
|
|
||||||
|
|
||||||
|
export const setTheme = async (themeId: string) => {
|
||||||
|
try {
|
||||||
|
const enabledTheme = await browser.storage.local.get('selectedTheme') as { selectedTheme: string; };
|
||||||
|
const theme = await localforage.getItem(themeId) as CustomTheme;
|
||||||
|
|
||||||
|
console.debug('Loading theme', theme);
|
||||||
|
|
||||||
|
// Remove the currently enabled theme
|
||||||
|
if (enabledTheme.selectedTheme) {
|
||||||
|
const currentTheme = await localforage.getItem(enabledTheme.selectedTheme) as CustomTheme;
|
||||||
|
if (currentTheme) {
|
||||||
|
removeTheme(currentTheme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await applyTheme(theme);
|
||||||
|
await browser.storage.local.set({ selectedTheme: themeId });
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error setting theme:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export const blobToBase64 = (blob: Blob) => {
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = () => {
|
||||||
|
const base64 = reader.result as string;
|
||||||
|
resolve(base64);
|
||||||
|
};
|
||||||
|
reader.onerror = reject;
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,7 +1,13 @@
|
|||||||
import browser from 'webextension-polyfill'
|
import browser from 'webextension-polyfill'
|
||||||
|
|
||||||
import { MenuOptionsOpen, OpenMenuOptions, OpenWhatsNewPopup, closeSettings } from '../../../SEQTA';
|
import { MenuOptionsOpen, OpenMenuOptions, OpenWhatsNewPopup, closeSettings } from '../../../SEQTA';
|
||||||
import { UpdateThemePreview, deleteTheme, disableTheme, getAvailableThemes, getTheme, saveTheme, setTheme } from '../../ui/Themes';
|
import { deleteTheme } from '../../ui/themes/deleteTheme';
|
||||||
|
import { getAvailableThemes } from '../../ui/themes/getAvailableThemes';
|
||||||
|
import { saveTheme } from '../../ui/themes/saveTheme';
|
||||||
|
import { UpdateThemePreview } from '../../ui/themes/UpdateThemePreview';
|
||||||
|
import { getTheme } from '../../ui/themes/getTheme';
|
||||||
|
import { setTheme } from '../../ui/themes/setTheme';
|
||||||
|
import { disableTheme } from '../../ui/themes/disableTheme';
|
||||||
import { CloseThemeCreator, OpenThemeCreator } from '../../ui/ThemeCreator';
|
import { CloseThemeCreator, OpenThemeCreator } from '../../ui/ThemeCreator';
|
||||||
|
|
||||||
export class MessageHandler {
|
export class MessageHandler {
|
||||||
@@ -9,6 +15,8 @@ export class MessageHandler {
|
|||||||
browser.runtime.onMessage.addListener(this.routeMessage.bind(this));
|
browser.runtime.onMessage.addListener(this.routeMessage.bind(this));
|
||||||
}
|
}
|
||||||
routeMessage(request: any, _sender: any, sendResponse: any) {
|
routeMessage(request: any, _sender: any, sendResponse: any) {
|
||||||
|
console.debug('Message received:', request)
|
||||||
|
|
||||||
switch (request.info) {
|
switch (request.info) {
|
||||||
case 'EditSidebar':
|
case 'EditSidebar':
|
||||||
this.editSidebar();
|
this.editSidebar();
|
||||||
@@ -19,7 +27,6 @@ export class MessageHandler {
|
|||||||
case 'UpdateThemePreview':
|
case 'UpdateThemePreview':
|
||||||
if (request?.save == true) {
|
if (request?.save == true) {
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
console.log('Saving theme:', request.body)
|
|
||||||
await saveTheme(request.body)
|
await saveTheme(request.body)
|
||||||
await setTheme(request.body.id)
|
await setTheme(request.body.id)
|
||||||
sendResponse({ status: 'success' });
|
sendResponse({ status: 'success' });
|
||||||
|
|||||||
Reference in New Issue
Block a user