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) => (
-
))}
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);