only single selected theme or custom background at once

This commit is contained in:
SethBurkart123
2023-11-02 19:05:37 +11:00
parent 7b0fc29461
commit e332977e08
7 changed files with 55 additions and 22 deletions
@@ -17,10 +17,11 @@ export interface Background {
interface BackgroundSelectorProps { interface BackgroundSelectorProps {
selectedType: "background" | "theme"; selectedType: "background" | "theme";
setSelectedType: (type: "background" | "theme") => void;
isEditMode: boolean; isEditMode: boolean;
} }
export default function BackgroundSelector({ selectedType, isEditMode }: BackgroundSelectorProps) { export default function BackgroundSelector({ selectedType, setSelectedType, isEditMode }: BackgroundSelectorProps) {
const [backgrounds, setBackgrounds] = useState<Background[]>([]); const [backgrounds, setBackgrounds] = useState<Background[]>([]);
const [selectedBackground, setSelectedBackground] = useState<string | null>(localStorage.getItem('selectedBackground')); const [selectedBackground, setSelectedBackground] = useState<string | null>(localStorage.getItem('selectedBackground'));
const [downloadedPresetIds, setDownloadedPresetIds] = useState<string[]>([]); const [downloadedPresetIds, setDownloadedPresetIds] = useState<string[]>([]);
@@ -75,6 +76,7 @@ export default function BackgroundSelector({ selectedType, isEditMode }: Backgro
const selectBackground = (fileId: string): void => { const selectBackground = (fileId: string): void => {
disableTheme(); disableTheme();
setSelectedType('background');
setSelectedBackground(fileId); setSelectedBackground(fileId);
localStorage.setItem('selectedBackground', fileId); localStorage.setItem('selectedBackground', fileId);
}; };
+23 -7
View File
@@ -10,13 +10,19 @@ interface Theme {
coverImage: JSX.Element; coverImage: JSX.Element;
} }
const ThemeSelector = () => { interface ThemeSelectorProps {
selectedType: "background" | "theme";
setSelectedType: (type: "background" | "theme") => void;
isEditMode: boolean;
}
const ThemeSelector = ({ selectedType, setSelectedType, isEditMode }: ThemeSelectorProps) => {
const [themes, setThemes] = useState<Theme[]>([]); const [themes, setThemes] = useState<Theme[]>([]);
const [enabledThemeName, setEnabledThemeName] = useState<string>(''); const [enabledThemeName, setEnabledThemeName] = useState<string>('');
useEffect(() => { useEffect(() => {
const initializeThemes = async () => { const initializeThemes = async () => {
const downloaded = await listThemes(); const downloaded = (await listThemes()).themes;
const initializedThemes = themesList.map(theme => ({ const initializedThemes = themesList.map(theme => ({
...theme, ...theme,
@@ -31,7 +37,6 @@ const ThemeSelector = () => {
}, []); }, []);
const handleThemeAction = async (themeName: string, themeURL: string) => { const handleThemeAction = async (themeName: string, themeURL: string) => {
// Start loading for the selected theme.
const startLoading = (name: string) => ( const startLoading = (name: string) => (
setThemes(prevThemes => prevThemes.map(theme => setThemes(prevThemes => prevThemes.map(theme =>
theme.name === name ? { ...theme, isLoading: true } : theme theme.name === name ? { ...theme, isLoading: true } : theme
@@ -51,7 +56,7 @@ const ThemeSelector = () => {
theme.name === name ? { ...theme, isDownloaded: true } : theme theme.name === name ? { ...theme, isDownloaded: true } : theme
)) ))
); );
startLoading(themeName); startLoading(themeName);
// Early return if theme is not found. // Early return if theme is not found.
@@ -60,11 +65,14 @@ const ThemeSelector = () => {
stopLoading(themeName); stopLoading(themeName);
return; return;
} }
console.log("Theme: ", theme);
// If theme is downloaded and is the currently enabled theme, disable it. // If theme is downloaded and is the currently enabled theme, disable it.
if (theme.isDownloaded && themeName === enabledThemeName) { if (theme.isDownloaded && themeName === enabledThemeName) {
await disableTheme(); await disableTheme();
setEnabledThemeName(''); setEnabledThemeName('');
setSelectedType('background');
stopLoading(themeName); stopLoading(themeName);
return; return;
} }
@@ -73,6 +81,7 @@ const ThemeSelector = () => {
if (theme.isDownloaded && themeName !== enabledThemeName) { if (theme.isDownloaded && themeName !== enabledThemeName) {
await setTheme(themeName, themeURL); await setTheme(themeName, themeURL);
setEnabledThemeName(themeName); setEnabledThemeName(themeName);
setSelectedType('theme');
stopLoading(themeName); stopLoading(themeName);
return; return;
} }
@@ -81,6 +90,7 @@ const ThemeSelector = () => {
if (!theme.isDownloaded) { if (!theme.isDownloaded) {
await downloadTheme(themeName, themeURL); await downloadTheme(themeName, themeURL);
markAsDownloaded(themeName); markAsDownloaded(themeName);
setSelectedType('theme');
setEnabledThemeName(themeName); setEnabledThemeName(themeName);
} }
@@ -94,11 +104,17 @@ const ThemeSelector = () => {
{themes.map((theme) => ( {themes.map((theme) => (
<button <button
key={theme.name} key={theme.name}
className={`relative w-full h-16 flex justify-center items-center rounded-lg overflow-hidden bg-zinc-700 transition ring dark:ring-white ring-zinc-300 ${enabledThemeName == theme.name ? 'dark:ring-2 ring-4' : 'ring-0'} ${theme.isLoading ? 'cursor-not-allowed' : ''}`} className={`relative w-full h-16 flex justify-center items-center rounded-lg bg-zinc-700 transition ring dark:ring-white ring-zinc-300 ${enabledThemeName == theme.name && selectedType == "theme" ? 'dark:ring-2 ring-4' : 'ring-0'}`}
onClick={() => handleThemeAction(theme.name, theme.url)} onClick={() => handleThemeAction(theme.name, theme.url)}
disabled={theme.isLoading} disabled={theme.isLoading}
> >
<div className={`relative transition top-0 z-10 flex justify-center w-full h-full text-white group place-items-center ${ theme.isDownloaded ? '' : 'hover:bg-black/20'}`}> {isEditMode && (
<div className="absolute top-0 right-0 z-10 flex w-6 h-6 p-2 text-white translate-x-1/2 -translate-y-1/2 bg-red-600 rounded-full place-items-center"
onClick={() => console.log("Deleted!")}>
<div className="w-4 h-0.5 bg-white"></div>
</div>
)}
<div className={`relative transition rounded-lg overflow-hidden top-0 z-10 flex justify-center w-full h-full text-white group place-items-center ${ theme.isDownloaded ? '' : 'hover:bg-black/20'}`}>
<span className="absolute z-10 text-3xl transition opacity-0 font-IconFamily group-hover:opacity-100"> <span className="absolute z-10 text-3xl transition opacity-0 font-IconFamily group-hover:opacity-100">
{ theme.isDownloaded || theme.isLoading ? '' : ''} { theme.isDownloaded || theme.isLoading ? '' : ''}
</span> </span>
@@ -109,7 +125,7 @@ const ThemeSelector = () => {
</div> } </div> }
</div> </div>
<div className="absolute inset-0 z-0"> <div className="absolute inset-0 z-0 overflow-hidden rounded-lg">
{theme.coverImage} {theme.coverImage}
</div> </div>
</button> </button>
+3 -3
View File
@@ -1,5 +1,6 @@
interface ThemeList { interface ThemeList {
themes: string[]; themes: string[];
selectedTheme: string;
} }
export const downloadTheme = async (themeName: string, themeURL: string) => { export const downloadTheme = async (themeName: string, themeURL: string) => {
@@ -34,14 +35,13 @@ export const listThemes = async () => {
// send message to the background script // send message to the background script
const response: ThemeList = await chrome.runtime.sendMessage({ const response: ThemeList = await chrome.runtime.sendMessage({
type: 'currentTab', type: 'currentTab',
info: 'ListThemes', info: 'ListThemes'
body: {}
}); });
// response.themes is an array of strings that are identical to the theme names that we loop over. Use this list to see which ones are downloaded and which ones need to see the download icon. // response.themes is an array of strings that are identical to the theme names that we loop over. Use this list to see which ones are downloaded and which ones need to see the download icon.
console.log("Response: ", response); console.log("Response: ", response);
return response.themes; return response;
} }
export const disableTheme = async () => { export const disableTheme = async () => {
+11 -4
View File
@@ -1,22 +1,29 @@
import { FC, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import BackgroundSelector from '../components/BackgroundSelector'; import BackgroundSelector from '../components/BackgroundSelector';
import ThemeSelector from '../components/ThemeSelector'; import ThemeSelector from '../components/ThemeSelector';
import { listThemes } from '../hooks/ThemeManagment';
const Themes: FC = () => { const Themes: FC = () => {
const [isEditMode, setIsEditMode] = useState<boolean>(false); const [isEditMode, setIsEditMode] = useState<boolean>(false);
const [selectedType, setSelectedType] = useState<'background' | 'theme'>('background'); const [selectedType, setSelectedType] = useState<'background' | 'theme'>('background');
useEffect(() => { useEffect(() => {
setSelectedType('background'); listThemes().then(themes => {
if (themes.selectedTheme) {
setSelectedType('theme');
} else {
setSelectedType('background');
}
});
}, []) }, [])
return ( return (
<div> <div>
<button className="absolute top-0 right-0 p-2 text-[0.8rem] text-blue-500" onClick={() => setIsEditMode(!isEditMode)}> <button className="absolute top-12 z-10 right-0 p-2 text-[0.8rem] text-blue-500" onClick={() => setIsEditMode(!isEditMode)}>
{isEditMode ? 'Done' : 'Edit'} {isEditMode ? 'Done' : 'Edit'}
</button> </button>
<BackgroundSelector selectedType={selectedType} isEditMode={isEditMode} /> <BackgroundSelector setSelectedType={setSelectedType} selectedType={selectedType} isEditMode={isEditMode} />
<ThemeSelector selectedType={selectedType} isEditMode={isEditMode} /> <ThemeSelector setSelectedType={setSelectedType} selectedType={selectedType} isEditMode={isEditMode} />
</div> </div>
); );
}; };
+1 -1
View File
@@ -772,9 +772,9 @@ document.addEventListener(
link.rel = "stylesheet"; link.rel = "stylesheet";
document.getElementsByTagName("html")[0].appendChild(link); document.getElementsByTagName("html")[0].appendChild(link);
enableCurrentTheme();
chrome.storage.local.get(null, function (items) { chrome.storage.local.get(null, function (items) {
main(items); main(items);
enableCurrentTheme();
}); });
} }
if ( if (
+10 -4
View File
@@ -84,9 +84,14 @@ const applyTheme = async (themeName) => {
); );
} }
}; };
export const listThemes = async () => { export const listThemes = async () => {
const themes = await localforage.keys(); const themes = await localforage.keys();
return themes.filter((key) => key.startsWith("css_")).map((key) => key.replace("css_", "")); console.log("Themes in IndexedDB:", themes);
return {
themes: themes.filter((key) => key.startsWith("css_")).map((key) => key.replace("css_", "")),
selectedTheme: await localforage.getItem("selectedTheme")
};
}; };
export const downloadTheme = async (themeName, themeUrl) => { export const downloadTheme = async (themeName, themeUrl) => {
@@ -101,14 +106,15 @@ export const setTheme = async (themeName, themeUrl) => {
await downloadTheme(themeName, themeUrl); await downloadTheme(themeName, themeUrl);
} }
localforage.setItem("selectedTheme", themeName); await localforage.setItem("selectedTheme", themeName);
await applyTheme(themeName).catch((error) => { await applyTheme(themeName).catch((error) => {
console.error(`Failed to apply theme: ${error}`); console.error(`Failed to apply theme: ${error}`);
}); });
}; };
export const enableCurrentTheme = async () => { export const enableCurrentTheme = async () => {
const currentTheme = localforage.getItem("selectedTheme"); console.log("Enabling current theme...");
const currentTheme = await localforage.getItem("selectedTheme");
if (currentTheme) { if (currentTheme) {
console.log(`Enabling current theme: ${currentTheme}`); console.log(`Enabling current theme: ${currentTheme}`);
@@ -136,7 +142,7 @@ export const disableTheme = async () => {
} }
// Remove any applied image URLs from the root element // Remove any applied image URLs from the root element
const currentTheme = localforage.getItem("selectedTheme"); const currentTheme = await localforage.getItem("selectedTheme");
if (currentTheme) { if (currentTheme) {
const themeData = await localforage.getItem(`css_${currentTheme}`); const themeData = await localforage.getItem(`css_${currentTheme}`);
if (themeData && themeData.images) { if (themeData && themeData.images) {
+4 -2
View File
@@ -14,6 +14,8 @@ export class MessageHandler {
case "EditSidebar": case "EditSidebar":
this.editSidebar(); this.editSidebar();
break; break;
/* Theme related */
case "SetTheme": case "SetTheme":
console.log(request); console.log(request);
setTheme(request.body.themeName, request.body.themeURL).then(() => { setTheme(request.body.themeName, request.body.themeURL).then(() => {
@@ -26,8 +28,8 @@ export class MessageHandler {
}); });
return true; return true;
case "ListThemes": case "ListThemes":
listThemes().then((themes) => { listThemes().then((response) => {
sendResponse({ themes }); sendResponse(response);
}); });
return true; return true;
case "DisableTheme": case "DisableTheme":