diff --git a/bin/index.mts b/bin/index.mts index 553c5fc6a..5db814a2e 100755 --- a/bin/index.mts +++ b/bin/index.mts @@ -421,7 +421,9 @@ async function buildTheme({ watch, noInstall, production, noReload, addon }: Arg const distPath = addon ? `dist/${manifest.id}` : "dist"; const folderPath = addon ? path.join(directory, "themes", addon) : directory; - const main = path.join(folderPath, manifest.main || "src/main.css"); + const main = existsSync(path.join(folderPath, manifest.main || "src/main.css")) + ? path.join(folderPath, manifest.main || "src/main.css") + : undefined; const splash = existsSync(path.join(folderPath, manifest.splash || "src/main.css")) ? path.join(folderPath, manifest.splash || "src/main.css") : undefined; @@ -485,6 +487,21 @@ async function buildTheme({ watch, noInstall, production, noReload, addon }: Arg manifest.plaintextPatches = "splash.css"; } + if (manifest.presets) { + targets.push( + esbuild.context({ + ...common, + entryPoints: manifest.presets.map((p: Record) => p.path), + outdir: `${distPath}/presets`, + }), + ); + + manifest.presets = manifest.presets?.map((p: Record) => ({ + ...p, + path: `presets/${path.basename(p.path).split(".")[0]}.css`, + })); + } + if (!existsSync(distPath)) mkdirSync(distPath, { recursive: true }); writeFileSync(`${distPath}/manifest.json`, JSON.stringify(manifest)); diff --git a/cspell.json b/cspell.json index 2e4895344..f1a6b0cf6 100644 --- a/cspell.json +++ b/cspell.json @@ -45,6 +45,7 @@ "notif", "notrack", "outfile", + "outdir", "popout", "postpublish", "Promisable", diff --git a/src/main/ipc/themes.ts b/src/main/ipc/themes.ts index 84f24b563..77ba14f77 100644 --- a/src/main/ipc/themes.ts +++ b/src/main/ipc/themes.ts @@ -30,6 +30,7 @@ async function getTheme(path: string): Promise { encoding: "utf-8", }), ); + console.log(manifest); return { path, diff --git a/src/renderer/coremods/settings/pages/Addons.tsx b/src/renderer/coremods/settings/pages/Addons.tsx index 614775b22..eec695734 100644 --- a/src/renderer/coremods/settings/pages/Addons.tsx +++ b/src/renderer/coremods/settings/pages/Addons.tsx @@ -7,6 +7,7 @@ import { ErrorBoundary, Flex, Notice, + SelectItem, Switch, Text, TextInput, @@ -84,6 +85,28 @@ function getSettingsElement(id: string, type: AddonType): React.ComponentType | return plugins.getExports(id)?.Settings; } if (type === AddonType.Theme) { + let settings = themes.settings.get(id, { chosenPreset: undefined }); + const theme = themes.themes.get(id)!; + if (theme.manifest.presets?.length) { + return () => ( + ({ + label: preset.label, + value: preset.path, + }))} + onChange={(val) => { + settings.chosenPreset = val; + themes.settings.set(id, settings); + if (!themes.getDisabled().includes(id)) { + themes.reload(id); + } + }} + isSelected={(val) => settings.chosenPreset === val} + closeOnSelect={true}> + Choose Theme Flavor + + ); + } return undefined; } @@ -679,7 +702,7 @@ export const Addons = (type: AddonType): React.ReactElement => { ) : null ) : ( - (SettingsElement = getSettingsElement(section.slice(`rp_${type}_`.length), type)) && ( + (SettingsElement = getSettingsElement(section.slice(`rp_${type}_`.length + 1), type)) && ( diff --git a/src/renderer/managers/themes.ts b/src/renderer/managers/themes.ts index eea566689..e0254db05 100644 --- a/src/renderer/managers/themes.ts +++ b/src/renderer/managers/themes.ts @@ -1,6 +1,6 @@ import { loadStyleSheet } from "../util"; import type { RepluggedTheme } from "../../types"; -import type { AddonSettings } from "src/types/addon"; +import type { ThemeSettings } from "src/types/addon"; import { init } from "../apis/settings"; import * as logger from "../modules/logger"; @@ -11,7 +11,7 @@ const themeElements = new Map(); */ export const themes = new Map(); let disabled: string[]; -const settings = await init("themes"); +export const settings = await init("themes"); /** * Load metadata for all themes that are added to the themes folder but not yet loaded, such as newly added themes. @@ -47,13 +47,21 @@ export function load(id: string): void { } const theme = themes.get(id)!; - if (!theme.manifest.main) { - logger.error("Manager", `Theme ${id} does not have a main variant.`); - return; + let themeSettings = settings.get(theme.manifest.id); + if (!themeSettings) themeSettings = {}; + if (!themeSettings.chosenPreset) { + themeSettings.chosenPreset = theme.manifest.presets?.find((x) => x.default)?.path; + settings.set(theme.manifest.id, themeSettings); } - unload(id); - const el = loadStyleSheet(`replugged://theme/${theme.path}/${theme.manifest.main}`); + let el; + if (theme.manifest.main) { + el = loadStyleSheet(`replugged://theme/${theme.path}/${theme.manifest.main}`); + } else if (themeSettings.chosenPreset) { + el = loadStyleSheet(`replugged://theme/${theme.path}/${themeSettings.chosenPreset}`); + } else { + throw new Error(`Theme ${id} does not have a main variant.`); + } themeElements.set(id, el); } diff --git a/src/types/addon.ts b/src/types/addon.ts index b29ce9751..a9824725b 100644 --- a/src/types/addon.ts +++ b/src/types/addon.ts @@ -54,6 +54,14 @@ export const theme = common.extend({ type: z.literal("replugged-theme"), main: z.string().optional(), splash: z.string().optional(), + presets: z + .object({ + label: z.string(), + path: z.string(), + default: z.boolean().optional(), + }) + .array() + .optional(), }); export type ThemeManifest = z.infer; @@ -86,3 +94,9 @@ export interface PluginExports { export type AddonSettings = { disabled?: string[]; }; + +export type ThemeSettings = AddonSettings & { + [x: string]: { + chosenPreset?: string; + }; +};