feat: implement custom theme management

This commit is contained in:
Hachi-R 2025-01-24 15:27:46 -03:00
parent 6bf049d136
commit 58f63cab44
12 changed files with 95 additions and 0 deletions

View file

@ -74,6 +74,10 @@ import "./cloud-save/upload-save-game";
import "./cloud-save/delete-game-artifact";
import "./cloud-save/select-game-backup-path";
import "./notifications/publish-new-repacks-notification";
import "./themes/add-custom-theme";
import "./themes/delete-custom-theme";
import "./themes/get-all-custom-themes";
import "./themes/delete-all-custom-themes";
import { isPortableVersion } from "@main/helpers";
ipcMain.handle("ping", () => "pong");

View file

@ -0,0 +1,12 @@
import { Theme } from "@types";
import { themes } from "@main/level/sublevels/themes";
import { registerEvent } from "../register-event";
const addCustomTheme = async (
_event: Electron.IpcMainInvokeEvent,
theme: Theme
) => {
await themes.put(theme.id, theme);
};
registerEvent("addCustomTheme", addCustomTheme);

View file

@ -0,0 +1,9 @@
import { themes } from "@main/level/sublevels/themes";
import { registerEvent } from "../register-event";
const deleteAllCustomThemes = async (_event: Electron.IpcMainInvokeEvent) => {
console.log("sexo2");
await themes.clear();
};
registerEvent("deleteAllCustomThemes", deleteAllCustomThemes);

View file

@ -0,0 +1,11 @@
import { themes } from "@main/level/sublevels/themes";
import { registerEvent } from "../register-event";
const deleteCustomTheme = async (
_event: Electron.IpcMainInvokeEvent,
themeId: string
) => {
await themes.del(themeId);
};
registerEvent("deleteCustomTheme", deleteCustomTheme);

View file

@ -0,0 +1,8 @@
import { themes } from "@main/level/sublevels/themes";
import { registerEvent } from "../register-event";
const getAllCustomThemes = async (_event: Electron.IpcMainInvokeEvent) => {
return await themes.values().all();
};
registerEvent("getAllCustomThemes", getAllCustomThemes);

View file

@ -32,3 +32,8 @@ export const isPortableVersion = () => {
export const normalizePath = (str: string) =>
path.posix.normalize(str).replace(/\\/g, "/");
export const isValidHexColor = (color: string): boolean => {
const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
return hexColorRegex.test(color);
};

View file

@ -5,6 +5,7 @@ export const levelKeys = {
game: (shop: GameShop, objectId: string) => `${shop}:${objectId}`,
user: "user",
auth: "auth",
themes: "themes",
gameShopCache: "gameShopCache",
gameShopCacheItem: (shop: GameShop, objectId: string, language: string) =>
`${shop}:${objectId}:${language}`,

View file

@ -0,0 +1,7 @@
import type { Theme } from "@types";
import { db } from "../level";
import { levelKeys } from "./keys";
export const themes = db.sublevel<string, Theme>(levelKeys.themes, {
valueEncoding: "json",
});

View file

@ -14,6 +14,7 @@ import type {
CatalogueSearchPayload,
SeedingStatus,
GameAchievement,
Theme,
} from "@types";
import type { AuthPage, CatalogueCategory } from "@shared";
import type { AxiosProgressEvent } from "axios";
@ -334,4 +335,11 @@ contextBridge.exposeInMainWorld("electron", {
/* Notifications */
publishNewRepacksNotification: (newRepacksCount: number) =>
ipcRenderer.invoke("publishNewRepacksNotification", newRepacksCount),
/* Themes */
addCustomTheme: (theme: Theme) => ipcRenderer.invoke("addCustomTheme", theme),
getAllCustomThemes: () => ipcRenderer.invoke("getAllCustomThemes"),
deleteAllCustomThemes: () => ipcRenderer.invoke("deleteAllCustomThemes"),
deleteCustomTheme: (themeId: string) =>
ipcRenderer.invoke("deleteCustomTheme", themeId),
});

View file

@ -269,6 +269,12 @@ declare global {
/* Notifications */
publishNewRepacksNotification: (newRepacksCount: number) => Promise<void>;
/* Themes */
addCustomTheme: (theme: Theme) => Promise<void>;
getAllCustomThemes: () => Promise<Theme[]>;
deleteAllCustomThemes: () => Promise<void>;
deleteCustomTheme: (themeId: string) => Promise<void>;
}
interface Window {

View file

@ -294,3 +294,4 @@ export * from "./download.types";
export * from "./ludusavi.types";
export * from "./how-long-to-beat.types";
export * from "./level.types";
export * from "./theme.types";

23
src/types/theme.types.ts Normal file
View file

@ -0,0 +1,23 @@
import { isValidHexColor } from "@main/helpers";
import { z } from "zod";
const hexColorSchema = z.string().refine(isValidHexColor);
type HexColorType = z.infer<typeof hexColorSchema>;
export interface Theme {
id: string;
name: string;
colors: {
accent: HexColorType;
background: HexColorType;
surface: HexColorType;
optional1?: HexColorType;
optional2?: HexColorType;
};
description?: string;
author: number;
isActive: boolean;
code: string;
createdAt: Date;
updatedAt: Date;
}