diff --git a/src/main/events/index.ts b/src/main/events/index.ts index 25882c3f..c4dc0202 100644 --- a/src/main/events/index.ts +++ b/src/main/events/index.ts @@ -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"); diff --git a/src/main/events/themes/add-custom-theme.ts b/src/main/events/themes/add-custom-theme.ts new file mode 100644 index 00000000..8e9c4c98 --- /dev/null +++ b/src/main/events/themes/add-custom-theme.ts @@ -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); diff --git a/src/main/events/themes/delete-all-custom-themes.ts b/src/main/events/themes/delete-all-custom-themes.ts new file mode 100644 index 00000000..a3c6018e --- /dev/null +++ b/src/main/events/themes/delete-all-custom-themes.ts @@ -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); diff --git a/src/main/events/themes/delete-custom-theme.ts b/src/main/events/themes/delete-custom-theme.ts new file mode 100644 index 00000000..604053e0 --- /dev/null +++ b/src/main/events/themes/delete-custom-theme.ts @@ -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); diff --git a/src/main/events/themes/get-all-custom-themes.ts b/src/main/events/themes/get-all-custom-themes.ts new file mode 100644 index 00000000..87a9c02a --- /dev/null +++ b/src/main/events/themes/get-all-custom-themes.ts @@ -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); diff --git a/src/main/helpers/index.ts b/src/main/helpers/index.ts index 163fb23a..99393d6c 100644 --- a/src/main/helpers/index.ts +++ b/src/main/helpers/index.ts @@ -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); +}; diff --git a/src/main/level/sublevels/keys.ts b/src/main/level/sublevels/keys.ts index 53eae44b..3f0a09ea 100644 --- a/src/main/level/sublevels/keys.ts +++ b/src/main/level/sublevels/keys.ts @@ -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}`, diff --git a/src/main/level/sublevels/themes.ts b/src/main/level/sublevels/themes.ts new file mode 100644 index 00000000..3967c510 --- /dev/null +++ b/src/main/level/sublevels/themes.ts @@ -0,0 +1,7 @@ +import type { Theme } from "@types"; +import { db } from "../level"; +import { levelKeys } from "./keys"; + +export const themes = db.sublevel(levelKeys.themes, { + valueEncoding: "json", +}); diff --git a/src/preload/index.ts b/src/preload/index.ts index 588becdc..e49b76ef 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -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), }); diff --git a/src/renderer/src/declaration.d.ts b/src/renderer/src/declaration.d.ts index 390b8c5e..7017f018 100644 --- a/src/renderer/src/declaration.d.ts +++ b/src/renderer/src/declaration.d.ts @@ -269,6 +269,12 @@ declare global { /* Notifications */ publishNewRepacksNotification: (newRepacksCount: number) => Promise; + + /* Themes */ + addCustomTheme: (theme: Theme) => Promise; + getAllCustomThemes: () => Promise; + deleteAllCustomThemes: () => Promise; + deleteCustomTheme: (themeId: string) => Promise; } interface Window { diff --git a/src/types/index.ts b/src/types/index.ts index fdca8009..1168a584 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -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"; diff --git a/src/types/theme.types.ts b/src/types/theme.types.ts new file mode 100644 index 00000000..bd77bb75 --- /dev/null +++ b/src/types/theme.types.ts @@ -0,0 +1,23 @@ +import { isValidHexColor } from "@main/helpers"; +import { z } from "zod"; + +const hexColorSchema = z.string().refine(isValidHexColor); +type HexColorType = z.infer; + +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; +}