mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-10 01:03:36 -05:00
Merge pull request #225 from brecert/theme_shop
Fix theme shop themes not applying as a base
This commit is contained in:
commit
fc03336ea3
6 changed files with 86 additions and 18 deletions
|
@ -7,6 +7,8 @@ import { useEffect } from "preact/hooks";
|
|||
import { connectState } from "../redux/connector";
|
||||
|
||||
import { Children } from "../types/Preact";
|
||||
import { fetchManifest, fetchTheme } from "../pages/settings/panes/ThemeShop";
|
||||
import { getState } from "../redux";
|
||||
|
||||
export type Variables =
|
||||
| "accent"
|
||||
|
@ -72,7 +74,7 @@ export type Theme = {
|
|||
};
|
||||
|
||||
export interface ThemeOptions {
|
||||
preset?: string;
|
||||
base?: string;
|
||||
ligatures?: boolean;
|
||||
custom?: Partial<Theme>;
|
||||
}
|
||||
|
@ -275,6 +277,27 @@ export const PRESETS: Record<string, Theme> = {
|
|||
},
|
||||
};
|
||||
|
||||
// todo: store used themes locally
|
||||
export function getBaseTheme(name: string): Theme {
|
||||
if (name in PRESETS) {
|
||||
return PRESETS[name]
|
||||
}
|
||||
|
||||
const themes = getState().themes
|
||||
|
||||
if (name in themes) {
|
||||
const { theme } = themes[name];
|
||||
|
||||
return {
|
||||
...PRESETS[theme.light ? 'light' : 'dark'],
|
||||
...theme
|
||||
}
|
||||
}
|
||||
|
||||
// how did we get here
|
||||
return PRESETS['dark']
|
||||
}
|
||||
|
||||
const keys = Object.keys(PRESETS.dark);
|
||||
const GlobalTheme = createGlobalStyle<{ theme: Theme }>`
|
||||
:root {
|
||||
|
@ -283,10 +306,9 @@ const GlobalTheme = createGlobalStyle<{ theme: Theme }>`
|
|||
`;
|
||||
|
||||
export const generateVariables = (theme: Theme) => {
|
||||
const mergedTheme = { ...PRESETS[theme.light ? 'light' : 'dark'], ...theme }
|
||||
return (Object.keys(mergedTheme) as Variables[]).map((key) => {
|
||||
return (Object.keys(theme) as Variables[]).map((key) => {
|
||||
if (!keys.includes(key)) return;
|
||||
return `--${key}: ${mergedTheme[key]};`;
|
||||
return `--${key}: ${theme[key]};`;
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -300,8 +322,7 @@ interface Props {
|
|||
|
||||
function Theme({ children, options }: Props) {
|
||||
const theme: Theme = {
|
||||
...PRESETS["dark"],
|
||||
...PRESETS[options?.preset ?? ""],
|
||||
...getBaseTheme(options?.base ?? 'dark'),
|
||||
...options?.custom,
|
||||
};
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ export function Component(props: Props) {
|
|||
|
||||
useEffect(() => setOverride({ css }), [setOverride, css]);
|
||||
|
||||
const selected = props.settings.theme?.preset ?? "dark";
|
||||
const selected = props.settings.theme?.base ?? "dark";
|
||||
return (
|
||||
<div className={styles.appearance}>
|
||||
<h3>
|
||||
|
@ -113,7 +113,7 @@ export function Component(props: Props) {
|
|||
data-active={selected === "light"}
|
||||
onClick={() =>
|
||||
selected !== "light" &&
|
||||
setTheme({ preset: "light" })
|
||||
setTheme({ base: "light" })
|
||||
}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
|
@ -128,7 +128,7 @@ export function Component(props: Props) {
|
|||
draggable={false}
|
||||
data-active={selected === "dark"}
|
||||
onClick={() =>
|
||||
selected !== "dark" && setTheme({ preset: "dark" })
|
||||
selected !== "dark" && setTheme({ base: "dark" })
|
||||
}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useEffect, useState } from "preact/hooks";
|
|||
|
||||
import { dispatch } from "../../../redux";
|
||||
|
||||
import { Theme, generateVariables } from "../../../context/Theme";
|
||||
import { Theme, generateVariables, ThemeOptions } from "../../../context/Theme";
|
||||
|
||||
import Tip from "../../../components/ui/Tip";
|
||||
import previewPath from "../assets/preview.svg";
|
||||
|
@ -21,14 +21,14 @@ export const fetchTheme = (slug: string): Promise<Theme> =>
|
|||
res.json(),
|
||||
);
|
||||
|
||||
interface ThemeMetadata {
|
||||
export interface ThemeMetadata {
|
||||
name: string;
|
||||
creator: string;
|
||||
commit?: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
type Manifest = {
|
||||
export type Manifest = {
|
||||
generated: string;
|
||||
themes: Record<string, ThemeMetadata>;
|
||||
};
|
||||
|
@ -189,14 +189,21 @@ export function ThemeShop() {
|
|||
<div class="description">{theme.description}</div>
|
||||
<button
|
||||
class="preview"
|
||||
onClick={() =>
|
||||
onClick={() => {
|
||||
dispatch({
|
||||
type: "THEMES_SET_THEME",
|
||||
theme: {
|
||||
slug,
|
||||
meta: theme,
|
||||
theme: themeData[slug]
|
||||
}
|
||||
})
|
||||
|
||||
dispatch({
|
||||
type: "SETTINGS_SET_THEME",
|
||||
theme: {
|
||||
custom: themeData[slug],
|
||||
},
|
||||
})
|
||||
}>
|
||||
theme: { base: slug },
|
||||
});
|
||||
}}>
|
||||
<ThemePreview slug={slug} theme={themeData[slug]} />
|
||||
</button>
|
||||
</ThemeInfo>
|
||||
|
|
|
@ -14,6 +14,7 @@ import { QueuedMessage } from "./reducers/queue";
|
|||
import { SectionToggle } from "./reducers/section_toggle";
|
||||
import { Settings } from "./reducers/settings";
|
||||
import { SyncOptions } from "./reducers/sync";
|
||||
import { Themes } from "./reducers/themes";
|
||||
import { TrustedLinks } from "./reducers/trusted_links";
|
||||
import { Unreads } from "./reducers/unreads";
|
||||
|
||||
|
@ -31,6 +32,7 @@ export type State = {
|
|||
notifications: Notifications;
|
||||
sectionToggle: SectionToggle;
|
||||
trustedLinks: TrustedLinks;
|
||||
themes: Themes;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
@ -62,6 +64,7 @@ store.subscribe(() => {
|
|||
notifications,
|
||||
sectionToggle,
|
||||
trustedLinks,
|
||||
themes,
|
||||
} = store.getState() as State;
|
||||
|
||||
localForage.setItem("state", {
|
||||
|
@ -78,6 +81,7 @@ store.subscribe(() => {
|
|||
notifications,
|
||||
sectionToggle,
|
||||
trustedLinks,
|
||||
themes,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import { sectionToggle, SectionToggleAction } from "./section_toggle";
|
|||
import { config, ConfigAction } from "./server_config";
|
||||
import { settings, SettingsAction } from "./settings";
|
||||
import { sync, SyncAction } from "./sync";
|
||||
import { themes, ThemesAction } from "./themes";
|
||||
import { trustedLinks, TrustedLinksAction } from "./trusted_links";
|
||||
import { unreads, UnreadsAction } from "./unreads";
|
||||
|
||||
|
@ -29,6 +30,7 @@ export default combineReducers({
|
|||
notifications,
|
||||
sectionToggle,
|
||||
trustedLinks,
|
||||
themes,
|
||||
});
|
||||
|
||||
export type Action =
|
||||
|
@ -45,4 +47,5 @@ export type Action =
|
|||
| NotificationsAction
|
||||
| SectionToggleAction
|
||||
| TrustedLinksAction
|
||||
| ThemesAction
|
||||
| { type: "__INIT"; state: State };
|
||||
|
|
33
src/redux/reducers/themes.ts
Normal file
33
src/redux/reducers/themes.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { Theme } from "../../context/Theme";
|
||||
|
||||
import { ThemeMetadata } from "../../pages/settings/panes/ThemeShop";
|
||||
|
||||
export interface StoredTheme {
|
||||
slug: string;
|
||||
meta: ThemeMetadata;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
export type Themes = Record<string, StoredTheme>;
|
||||
|
||||
export type ThemesAction =
|
||||
| { type: undefined }
|
||||
| { type: "THEMES_SET_THEME"; theme: StoredTheme }
|
||||
| { type: "THEMES_REMOVE_THEME"; slug: string }
|
||||
| { type: "RESET" };
|
||||
|
||||
export function themes(state: Themes = {}, action: ThemesAction) {
|
||||
switch (action.type) {
|
||||
case "THEMES_SET_THEME":
|
||||
return {
|
||||
...state,
|
||||
[action.theme.slug]: action.theme,
|
||||
};
|
||||
case "THEMES_REMOVE_THEME":
|
||||
return { ...state, [action.slug]: null };
|
||||
case "RESET":
|
||||
return {};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue