add theme saving (This took hours)

This commit is contained in:
SethBurkart123
2024-04-01 20:24:51 +11:00
parent c9431de33f
commit 6c799ba346
8 changed files with 427 additions and 407 deletions
+86 -157
View File
@@ -1,177 +1,106 @@
import { memo, useEffect, useState } from "react";
import themesList from '../assets/themes';
import { listThemes, disableTheme, downloadTheme, setTheme, deleteTheme } from "../hooks/ThemeManagment";
import Browser from "webextension-polyfill";
interface Theme {
name: string;
url: string;
isDownloaded: boolean;
isLoading: boolean;
coverImage: JSX.Element;
}
import React, { useEffect, useState, useCallback } from 'react';
import { listThemes, deleteTheme, setTheme, disableTheme } from '../hooks/ThemeManagment';
import { ThemeCover } from './ThemeCover';
import Browser from 'webextension-polyfill';
import { CustomTheme } from '../types/CustomThemes';
interface ThemeSelectorProps {
selectedType: "background" | "theme";
setSelectedType: (type: "background" | "theme") => void;
setSelectedType: React.Dispatch<React.SetStateAction<'background' | 'theme'>>;
selectedType: 'background' | 'theme';
isEditMode: boolean;
}
const ThemeSelector = ({ selectedType, setSelectedType, isEditMode }: ThemeSelectorProps) => {
const [themes, setThemes] = useState<Theme[]>([]);
const [enabledThemeName, setEnabledThemeName] = useState<string>('');
useEffect(() => {
const initializeThemes = async () => {
const downloaded = (await listThemes());
const initializedThemes = themesList.map(theme => ({
...theme,
isDownloaded: downloaded.themes.includes(theme.name),
isLoading: false
}));
if (downloaded.selectedTheme !== '') {
setEnabledThemeName(downloaded.selectedTheme);
}
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 =>
theme.name === name ? { ...theme, isLoading: true } : theme
))
);
// Stop loading for the selected theme.
const stopLoading = (name: string) => (
setThemes(prevThemes => prevThemes.map(theme =>
theme.name === name ? { ...theme, isLoading: false } : theme
))
);
// Update the theme as downloaded.
const markAsDownloaded = (name: string) => (
setThemes(prevThemes => prevThemes.map(theme =>
theme.name === name ? { ...theme, isDownloaded: true } : theme
))
);
startLoading(themeName);
// Early return if theme is not found.
const theme = themes.find(t => t.name === themeName);
if (!theme) {
stopLoading(themeName);
return;
}
// If theme is downloaded and is the currently enabled theme, disable it.
if (theme.isDownloaded && themeName === enabledThemeName) {
await disableTheme();
setEnabledThemeName('');
setSelectedType('background');
stopLoading(themeName);
return;
}
// If theme is downloaded but not enabled, enable it.
if (theme.isDownloaded && themeName !== enabledThemeName) {
await setTheme(themeName, themeURL);
setEnabledThemeName(themeName);
setSelectedType('theme');
stopLoading(themeName);
return;
}
// If theme is not downloaded, download and enable it.
if (!theme.isDownloaded) {
await downloadTheme(themeName, themeURL);
markAsDownloaded(themeName);
setSelectedType('theme');
setEnabledThemeName(themeName);
}
stopLoading(themeName);
};
const ThemeSelector: React.FC<ThemeSelectorProps> = ({
setSelectedType,
selectedType,
isEditMode,
}) => {
const [themes, setThemes] = useState<Omit<CustomTheme, 'CustomImages'>[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [selectedThemeId, setSelectedThemeId] = useState<string | null>(null);
useEffect(() => {
if (selectedType === 'background') {
setEnabledThemeName('');
setSelectedThemeId(null);
}
}, [selectedType]);
useEffect(() => {
const fetchThemes = async () => {
try {
const { themes, selectedTheme } = await listThemes();
console.log(await listThemes());
setThemes(themes);
setSelectedThemeId(selectedTheme ? selectedTheme : null);
} catch (error) {
console.error('Error fetching themes:', error);
} finally {
setIsLoading(false);
}
};
fetchThemes();
}, []);
const handleThemeSelect = useCallback(
async (themeId: string) => {
if (themeId === selectedThemeId) {
await disableTheme();
setSelectedThemeId(null);
setSelectedType('background');
} else {
const selectedTheme = themes.find((theme) => theme.id === themeId);
if (selectedTheme) {
await setTheme(selectedTheme.id);
setSelectedThemeId(themeId);
setSelectedType('theme');
}
}
},
[selectedThemeId, themes, setSelectedType]
);
const handleThemeDelete = useCallback(
async (themeId: string) => {
try {
await deleteTheme(themeId);
setThemes((prevThemes) => prevThemes.filter((theme) => theme.id !== themeId));
if (themeId === selectedThemeId) {
setSelectedThemeId(null);
setSelectedType('background');
}
} catch (error) {
console.error('Error deleting theme:', error);
}
},
[selectedThemeId, setSelectedType]
);
if (isLoading) {
return <div>Loading themes...</div>;
}
return (
<div className="my-2">
{(isEditMode ? themes.some(theme => theme.isDownloaded) : themes.length > 0) && (
<h2 className="pb-2 text-lg font-bold">Themes</h2>
)}
<h2 className="pb-2 text-lg font-bold">Themes</h2>
<div className="flex flex-col gap-4">
{themes
.filter(theme => !isEditMode || theme.isDownloaded) // Only show downloaded themes in edit mode
.map((theme) => (
<button
key={theme.name}
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)}
disabled={theme.isLoading}
>
{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={(e) => { e.stopPropagation(); handleDeleteTheme(theme.name); }}>
<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">
{ theme.isDownloaded || theme.isLoading ? '' : ''}
</span>
{ theme.isLoading &&
<div className="z-10 inline-block w-6 h-6 border-4 border-current rounded-full animate-spin border-t-transparent" role="status">
<span className="sr-only">Loading...</span>
</div> }
</div>
<div className="absolute inset-0 z-0 overflow-hidden rounded-lg">
{theme.coverImage}
</div>
</button>
{themes.map((theme) => (
<ThemeCover
key={theme.id}
theme={theme}
isSelected={theme.id === selectedThemeId}
isEditMode={isEditMode}
onThemeSelect={handleThemeSelect}
onThemeDelete={handleThemeDelete}
/>
))}
<button
onClick={() => Browser.runtime.sendMessage({ type: 'currentTab', info: 'OpenThemeCreator' })}
className="flex items-center justify-center w-full h-16 transition rounded-lg bg-zinc-700">
className="flex items-center justify-center w-full h-16 transition rounded-xl bg-zinc-100 dark:bg-zinc-900 dark:text-white"
>
<span className="text-xl font-IconFamily">{'\uec60'}</span>
<span className="ml-2">Create Theme</span>
</button>
@@ -180,4 +109,4 @@ const ThemeSelector = ({ selectedType, setSelectedType, isEditMode }: ThemeSelec
);
};
export default memo(ThemeSelector);
export default ThemeSelector;