diff --git a/interface/src/components/BackgroundSelector.tsx b/interface/src/components/BackgroundSelector.tsx index 654b0960..60b9ed6d 100644 --- a/interface/src/components/BackgroundSelector.tsx +++ b/interface/src/components/BackgroundSelector.tsx @@ -95,6 +95,7 @@ export default function BackgroundSelector({ selectedType, setSelectedType, isEd }; const selectNoBackground = (): void => { + setSelectedType('background'); disableTheme(); setSelectedBackground(null); localStorage.removeItem('selectedBackground'); diff --git a/interface/src/components/ThemeSelector.tsx b/interface/src/components/ThemeSelector.tsx index 8a67a305..5e012922 100644 --- a/interface/src/components/ThemeSelector.tsx +++ b/interface/src/components/ThemeSelector.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from "react"; import themesList from '../assets/themes'; -import { listThemes, disableTheme, downloadTheme, setTheme } from "../hooks/ThemeManagment"; +import { listThemes, disableTheme, downloadTheme, setTheme, deleteTheme } from "../hooks/ThemeManagment"; interface Theme { name: string; @@ -30,12 +30,38 @@ const ThemeSelector = ({ selectedType, setSelectedType, isEditMode }: ThemeSelec isLoading: false })); + initializedThemes.sort((a, b) => Number(b.isDownloaded) - Number(a.isDownloaded)); + setThemes(initializedThemes); }; initializeThemes(); }, []); + const handleDeleteTheme = async (themeName: string) => { + await deleteTheme(themeName); + setThemes(prevThemes => { + // Update the theme's isDownloaded property to false + const updatedThemes = prevThemes.map(theme => { + if (theme.name === themeName) { + return { ...theme, isDownloaded: false }; + } + return theme; + }); + + // Sort themes so non-downloaded ones appear last + updatedThemes.sort((a, b) => Number(b.isDownloaded) - Number(a.isDownloaded)); + + return updatedThemes; + }); + + // Reset the enabled theme name if the deleted theme was the currently enabled one + if (enabledThemeName === themeName) { + setEnabledThemeName(''); + setSelectedType('background'); + } + }; + const handleThemeAction = async (themeName: string, themeURL: string) => { const startLoading = (name: string) => ( setThemes(prevThemes => prevThemes.map(theme => @@ -103,36 +129,39 @@ const ThemeSelector = ({ selectedType, setSelectedType, isEditMode }: ThemeSelec return (
-

Themes

+ {(isEditMode ? themes.some(theme => theme.isDownloaded) : themes.length > 0) && ( +

Themes

)}
- {themes.map((theme) => ( - +
+
+ {theme.coverImage} +
+ ))}
diff --git a/interface/src/hooks/ThemeManagment.tsx b/interface/src/hooks/ThemeManagment.tsx index 9fc214ff..5bd45538 100644 --- a/interface/src/hooks/ThemeManagment.tsx +++ b/interface/src/hooks/ThemeManagment.tsx @@ -49,4 +49,14 @@ export const disableTheme = async () => { type: 'currentTab', info: 'DisableTheme', }); -}; \ No newline at end of file +}; + +export const deleteTheme = async (themeName: string) => { + await chrome.runtime.sendMessage({ + type: 'currentTab', + info: 'DeleteTheme', + body: { + themeName: themeName + } + }); +} \ No newline at end of file diff --git a/src/seqta/ui/Themes.js b/src/seqta/ui/Themes.js index 074d4d70..5f0266de 100644 --- a/src/seqta/ui/Themes.js +++ b/src/seqta/ui/Themes.js @@ -47,33 +47,26 @@ const saveToIndexedDB = async (theme, themeName) => { // Apply theme from storage via localForage to document const applyTheme = async (themeName) => { - // Remove previous theme's style if it exists - if (currentThemeStyle) { - document.head.removeChild(currentThemeStyle); - currentThemeStyle = null; - } - - // Remove previous theme's class if it exists - if (currentThemeClass) { - document.body.classList.remove(currentThemeClass); - currentThemeClass = ""; - } - const { css, className, images } = await localforage.getItem(`css_${themeName}`); - // Apply CSS - const style = document.createElement("style"); - style.innerHTML = css; - document.head.appendChild(style); - currentThemeStyle = style; // Keep track of the new style element - - // Apply className - if (className) { - document.body.classList.add(className); - currentThemeClass = className; // Keep track of the new class + const newStyle = document.createElement("style"); + newStyle.innerHTML = css; + document.head.appendChild(newStyle); + + if (window.currentThemeStyle) { + document.head.removeChild(window.currentThemeStyle); + } + + window.currentThemeStyle = newStyle; + + if (window.currentThemeClass) { + document.body.classList.remove(window.currentThemeClass); + } + if (className) { + document.body.classList.add(className); + window.currentThemeClass = className; } - // Apply images if (images) { await Promise.all( Object.keys(images).map(async (cssVar) => { @@ -101,6 +94,15 @@ export const downloadTheme = async (themeName, themeUrl) => { console.log(`Theme ${themeName} saved to IndexedDB`); }; +export const deleteTheme = async (themeName) => { + console.log(`Deleting theme ${themeName}...`); + await localforage.removeItem(`css_${themeName}`); + await Promise.all( + (await localforage.keys()).filter((key) => key.startsWith(`images_${themeName}`)).map((key) => localforage.removeItem(key)) + ); + console.log(`Theme ${themeName} deleted.`); +} + export const setTheme = async (themeName, themeUrl) => { if (!(await themeExistsInDB(themeName))) { await downloadTheme(themeName, themeUrl); diff --git a/src/seqta/utils/MessageListener.js b/src/seqta/utils/MessageListener.js index f4933839..70e1892c 100644 --- a/src/seqta/utils/MessageListener.js +++ b/src/seqta/utils/MessageListener.js @@ -1,7 +1,7 @@ /* global chrome */ import { MenuOptionsOpen, OpenMenuOptions, closeSettings } from "../../SEQTA.js"; -import { disableTheme, downloadTheme, listThemes, setTheme } from "../ui/Themes.js"; +import { deleteTheme, disableTheme, downloadTheme, listThemes, setTheme } from "../ui/Themes.js"; export class MessageHandler { constructor() { @@ -37,6 +37,11 @@ export class MessageHandler { sendResponse({ status: "success" }); }); return true; + case "DeleteTheme": + deleteTheme(request.body.themeName).then(() => { + sendResponse({ status: "success" }); + }); + return true; default: console.log("Unknown request info:", request.info);