Merge branch 'feature/custom-themes' of github.com:hydralauncher/hydra into feature/custom-themes

This commit is contained in:
Chubby Granny Chaser 2025-02-16 04:29:27 +00:00
commit 9449d7cdcd
No known key found for this signature in database
8 changed files with 181 additions and 35 deletions

View file

@ -1,4 +1,4 @@
import { useCallback, useEffect, useRef } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import achievementSound from "@renderer/assets/audio/achievement.wav";
import { Sidebar, BottomPanel, Header, Toast } from "@renderer/components";
@ -30,6 +30,7 @@ import { HydraCloudModal } from "./pages/shared-modals/hydra-cloud/hydra-cloud-m
import { injectCustomCss } from "./helpers";
import "./app.scss";
import { ImportThemeModal } from "./pages/settings/aparence/modals/import-theme-modal";
export interface AppProps {
children: React.ReactNode;
@ -38,6 +39,12 @@ export interface AppProps {
export function App() {
const contentRef = useRef<HTMLDivElement>(null);
const { updateLibrary, library } = useLibrary();
const [isImportThemeModalVisible, setIsImportThemeModalVisible] =
useState(false);
const [importTheme, setImportTheme] = useState<{
theme: string;
author: string;
} | null>(null);
const { t } = useTranslation("app");
@ -271,6 +278,15 @@ export function App() {
return () => unsubscribe();
}, []);
useEffect(() => {
const unsubscribe = window.electron.onImportTheme((theme, author) => {
setImportTheme({ theme, author });
setIsImportThemeModalVisible(true);
});
return () => unsubscribe();
}, []);
const handleToastClose = useCallback(() => {
dispatch(closeToast());
}, [dispatch]);
@ -312,6 +328,16 @@ export function App() {
/>
)}
{importTheme && (
<ImportThemeModal
visible={isImportThemeModalVisible}
onClose={() => setIsImportThemeModalVisible(false)}
onThemeImported={() => setIsImportThemeModalVisible(false)}
themeName={importTheme.theme}
authorCode={importTheme.author}
/>
)}
<main>
<Sidebar />

View file

@ -289,6 +289,9 @@ declare global {
updateCustomTheme: (themeId: string, theme: Theme) => Promise<void>;
getCustomThemeById: (themeId: string) => Promise<Theme | null>;
getActiveCustomTheme: () => Promise<Theme | null>;
onImportTheme: (
cb: (theme: string, author: string) => void
) => () => Electron.IpcRenderer;
/* Editor */
openEditorWindow: (themeId: string) => Promise<void>;

View file

@ -0,0 +1,92 @@
import { Button } from "@renderer/components/button/button";
import { Modal } from "@renderer/components/modal/modal";
import { useTranslation } from "react-i18next";
import "./modals.scss";
import { Theme } from "@types";
import { injectCustomCss, removeCustomCss } from "@renderer/helpers";
import { useToast } from "@renderer/hooks";
interface ImportThemeModalProps {
visible: boolean;
onClose: () => void;
onThemeImported: () => void;
themeName: string;
authorCode: string;
}
export const ImportThemeModal = ({
visible,
onClose,
onThemeImported,
themeName,
authorCode,
}: ImportThemeModalProps) => {
const { t } = useTranslation("settings");
const { showSuccessToast, showErrorToast } = useToast();
const handleImportTheme = async () => {
const theme: Theme = {
id: crypto.randomUUID(),
name: themeName,
isActive: false,
author: authorCode,
authorName: "spectre",
code: `https://hydrathemes.shop/themes/${themeName}.css`,
createdAt: new Date(),
updatedAt: new Date(),
};
try {
await window.electron.addCustomTheme(theme);
const currentTheme = await window.electron.getCustomThemeById(theme.id);
if (!currentTheme) return;
const activeTheme = await window.electron.getActiveCustomTheme();
if (activeTheme) {
removeCustomCss();
await window.electron.updateCustomTheme(activeTheme.id, {
...activeTheme,
isActive: false,
});
}
if (currentTheme.code) {
injectCustomCss(currentTheme.code);
}
await window.electron.updateCustomTheme(currentTheme.id, {
...currentTheme,
isActive: true,
});
onThemeImported();
showSuccessToast(t("theme_imported"));
onClose();
} catch (error) {
console.error(error);
showErrorToast(t("error_importing_theme"));
onClose();
}
};
return (
<Modal
visible={visible}
title={t("import_theme")}
description={t("import_theme_description")}
onClose={onClose}
>
<div className="delete-all-themes-modal__container">
<Button theme="outline" onClick={handleImportTheme}>
{t("import_theme")}
</Button>
<Button theme="primary" onClick={onClose}>
{t("cancel")}
</Button>
</div>
</Modal>
);
};