mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-06 23:45:52 -05:00
feat(mobx): start implementing theme store
This commit is contained in:
parent
26a34032f9
commit
bd4369cf29
9 changed files with 207 additions and 112 deletions
|
@ -1,11 +1,11 @@
|
|||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import { Download, CloudDownload } from "@styled-icons/boxicons-regular";
|
||||
|
||||
import { useContext, useEffect, useState } from "preact/hooks";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
|
||||
import { internalSubscribe } from "../../lib/eventEmitter";
|
||||
|
||||
import { ThemeContext } from "../../context/Theme";
|
||||
import { useApplicationState } from "../../mobx/State";
|
||||
|
||||
import IconButton from "../ui/IconButton";
|
||||
|
||||
|
@ -27,7 +27,7 @@ export default function UpdateIndicator({ style }: Props) {
|
|||
});
|
||||
|
||||
if (!pending) return null;
|
||||
const theme = useContext(ThemeContext);
|
||||
const theme = useApplicationState().settings.theme;
|
||||
|
||||
if (style === "titlebar") {
|
||||
return (
|
||||
|
@ -36,7 +36,10 @@ export default function UpdateIndicator({ style }: Props) {
|
|||
content="A new update is available!"
|
||||
placement="bottom">
|
||||
<div onClick={() => updateSW(true)}>
|
||||
<CloudDownload size={22} color={theme.success} />
|
||||
<CloudDownload
|
||||
size={22}
|
||||
color={theme.getVariable("success")}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
@ -47,7 +50,7 @@ export default function UpdateIndicator({ style }: Props) {
|
|||
|
||||
return (
|
||||
<IconButton onClick={() => updateSW(true)}>
|
||||
<Download size={22} color={theme.success} />
|
||||
<Download size={22} color={theme.getVariable("success")} />
|
||||
</IconButton>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,12 +5,10 @@ import { useParams } from "react-router-dom";
|
|||
import { Masquerade } from "revolt-api/types/Channels";
|
||||
import { Presence } from "revolt-api/types/Users";
|
||||
import { User } from "revolt.js/dist/maps/Users";
|
||||
import { Nullable } from "revolt.js/dist/util/null";
|
||||
import styled, { css } from "styled-components";
|
||||
|
||||
import { useContext } from "preact/hooks";
|
||||
import { useApplicationState } from "../../../mobx/State";
|
||||
|
||||
import { ThemeContext } from "../../../context/Theme";
|
||||
import { useClient } from "../../../context/revoltjs/RevoltClient";
|
||||
|
||||
import fallback from "../assets/user.png";
|
||||
|
@ -26,15 +24,15 @@ interface Props extends IconBaseProps<User> {
|
|||
}
|
||||
|
||||
export function useStatusColour(user?: User) {
|
||||
const theme = useContext(ThemeContext);
|
||||
const theme = useApplicationState().settings.theme;
|
||||
|
||||
return user?.online && user?.status?.presence !== Presence.Invisible
|
||||
? user?.status?.presence === Presence.Idle
|
||||
? theme["status-away"]
|
||||
? theme.getVariable("status-away")
|
||||
: user?.status?.presence === Presence.Busy
|
||||
? theme["status-busy"]
|
||||
: theme["status-online"]
|
||||
: theme["status-invisible"];
|
||||
? theme.getVariable("status-busy")
|
||||
: theme.getVariable("status-online")
|
||||
: theme.getVariable("status-invisible");
|
||||
}
|
||||
|
||||
const VoiceIndicator = styled.div<{ status: VoiceStatus }>`
|
||||
|
|
|
@ -6,9 +6,6 @@ import { useEffect } from "preact/hooks";
|
|||
|
||||
import { useApplicationState } from "../mobx/State";
|
||||
import { getState } from "../redux";
|
||||
import { connectState } from "../redux/connector";
|
||||
|
||||
import { Children } from "../types/Preact";
|
||||
|
||||
export type Variables =
|
||||
| "accent"
|
||||
|
@ -66,9 +63,11 @@ export type MonospaceFonts =
|
|||
| "Ubuntu Mono"
|
||||
| "JetBrains Mono";
|
||||
|
||||
export type Theme = {
|
||||
export type Overrides = {
|
||||
[variable in Variables]: string;
|
||||
} & {
|
||||
};
|
||||
|
||||
export type Theme = Overrides & {
|
||||
light?: boolean;
|
||||
font?: Fonts;
|
||||
css?: string;
|
||||
|
@ -228,7 +227,6 @@ export const DEFAULT_MONO_FONT = "Fira Code";
|
|||
// Generated from https://gitlab.insrt.uk/revolt/community/themes
|
||||
export const PRESETS: Record<string, Theme> = {
|
||||
light: {
|
||||
light: true,
|
||||
accent: "#FD6671",
|
||||
background: "#F6F6F6",
|
||||
foreground: "#000000",
|
||||
|
@ -255,7 +253,6 @@ export const PRESETS: Record<string, Theme> = {
|
|||
"status-invisible": "#A5A5A5",
|
||||
},
|
||||
dark: {
|
||||
light: false,
|
||||
accent: "#FD6671",
|
||||
background: "#191919",
|
||||
foreground: "#F6F6F6",
|
||||
|
@ -319,33 +316,22 @@ export const generateVariables = (theme: Theme) => {
|
|||
});
|
||||
};
|
||||
|
||||
// Load the default default them and apply extras later
|
||||
export const ThemeContext = createContext<Theme>(PRESETS["dark"]);
|
||||
|
||||
interface Props {
|
||||
children: Children;
|
||||
}
|
||||
|
||||
export default function Theme({ children }: Props) {
|
||||
export default function Theme() {
|
||||
const settings = useApplicationState().settings;
|
||||
|
||||
const theme: Theme = {
|
||||
...getBaseTheme(settings.get("appearance:theme:base") ?? "dark"),
|
||||
...settings.get("appearance:theme:custom"),
|
||||
};
|
||||
const theme = settings.theme;
|
||||
|
||||
const root = document.documentElement.style;
|
||||
useEffect(() => {
|
||||
const font = theme.font ?? DEFAULT_FONT;
|
||||
const font = theme.getFont() ?? DEFAULT_FONT;
|
||||
root.setProperty("--font", `"${font}"`);
|
||||
FONTS[font].load();
|
||||
}, [root, theme.font]);
|
||||
}, [root, theme.getFont()]);
|
||||
|
||||
useEffect(() => {
|
||||
const font = theme.monospaceFont ?? DEFAULT_MONO_FONT;
|
||||
const font = theme.getMonospaceFont() ?? DEFAULT_MONO_FONT;
|
||||
root.setProperty("--monospace-font", `"${font}"`);
|
||||
MONOSPACE_FONTS[font].load();
|
||||
}, [root, theme.monospaceFont]);
|
||||
}, [root, theme.getMonospaceFont()]);
|
||||
|
||||
useEffect(() => {
|
||||
root.setProperty(
|
||||
|
@ -363,16 +349,14 @@ export default function Theme({ children }: Props) {
|
|||
return () => window.removeEventListener("resize", resize);
|
||||
}, [root]);
|
||||
|
||||
const variables = theme.getVariables();
|
||||
return (
|
||||
<ThemeContext.Provider value={theme}>
|
||||
<>
|
||||
<Helmet>
|
||||
<meta name="theme-color" content={theme["background"]} />
|
||||
<meta name="theme-color" content={variables["background"]} />
|
||||
</Helmet>
|
||||
<GlobalTheme theme={theme} />
|
||||
{theme.css && (
|
||||
<style dangerouslySetInnerHTML={{ __html: theme.css }} />
|
||||
)}
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
<GlobalTheme theme={variables} />
|
||||
<style dangerouslySetInnerHTML={{ __html: theme.getCSS() ?? "" }} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,15 +17,14 @@ export default function Context({ children }: { children: Children }) {
|
|||
return (
|
||||
<Router basename={import.meta.env.BASE_URL}>
|
||||
<State>
|
||||
<Theme>
|
||||
<Settings>
|
||||
<Locale>
|
||||
<Intermediate>
|
||||
<Client>{children}</Client>
|
||||
</Intermediate>
|
||||
</Locale>
|
||||
</Settings>
|
||||
</Theme>
|
||||
<Settings>
|
||||
<Locale>
|
||||
<Intermediate>
|
||||
<Client>{children}</Client>
|
||||
</Intermediate>
|
||||
</Locale>
|
||||
</Settings>
|
||||
<Theme />
|
||||
</State>
|
||||
</Router>
|
||||
);
|
||||
|
|
|
@ -2,11 +2,12 @@ import { action, computed, makeAutoObservable, ObservableMap } from "mobx";
|
|||
|
||||
import { mapToRecord } from "../../lib/conversion";
|
||||
|
||||
import { Theme } from "../../context/Theme";
|
||||
import { Fonts, MonospaceFonts, Overrides, Theme } from "../../context/Theme";
|
||||
|
||||
import { Sounds } from "../../assets/sounds/Audio";
|
||||
import Persistent from "../interfaces/Persistent";
|
||||
import Store from "../interfaces/Store";
|
||||
import STheme from "./helpers/STheme";
|
||||
|
||||
export type SoundOptions = {
|
||||
[key in Sounds]?: boolean;
|
||||
|
@ -20,43 +21,35 @@ interface ISettings {
|
|||
|
||||
"appearance:emoji": EmojiPack;
|
||||
"appearance:ligatures": boolean;
|
||||
"appearance:theme:base": string;
|
||||
"appearance:theme:custom": Partial<Theme>;
|
||||
|
||||
"appearance:theme:base": "dark" | "light";
|
||||
"appearance:theme:overrides": Partial<Overrides>;
|
||||
"appearance:theme:light": boolean;
|
||||
"appearance:theme:font": Fonts;
|
||||
"appearance:theme:monoFont": MonospaceFonts;
|
||||
"appearance:theme:css": string;
|
||||
}
|
||||
|
||||
/*const Schema: {
|
||||
[key in keyof ISettings]:
|
||||
| "string"
|
||||
| "number"
|
||||
| "boolean"
|
||||
| "object"
|
||||
| "function";
|
||||
} = {
|
||||
"notifications:desktop": "boolean",
|
||||
"notifications:sounds": "object",
|
||||
|
||||
"appearance:emoji": "string",
|
||||
"appearance:ligatures": "boolean",
|
||||
"appearance:theme:base": "string",
|
||||
"appearance:theme:custom": "object",
|
||||
};*/
|
||||
|
||||
/**
|
||||
* Manages user settings.
|
||||
*/
|
||||
export default class Settings implements Store, Persistent<ISettings> {
|
||||
private data: ObservableMap<string, unknown>;
|
||||
|
||||
theme: STheme;
|
||||
|
||||
/**
|
||||
* Construct new Layout store.
|
||||
* Construct new Settings store.
|
||||
*/
|
||||
constructor() {
|
||||
this.data = new ObservableMap();
|
||||
makeAutoObservable(this);
|
||||
|
||||
this.theme = new STheme(this);
|
||||
}
|
||||
|
||||
get id() {
|
||||
return "layout";
|
||||
return "settings";
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
@ -69,18 +62,38 @@ export default class Settings implements Store, Persistent<ISettings> {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a settings key.
|
||||
* @param key Colon-divided key
|
||||
* @param value Value
|
||||
*/
|
||||
@action set<T extends keyof ISettings>(key: T, value: ISettings[T]) {
|
||||
return this.data.set(key, value);
|
||||
this.data.set(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a settings key.
|
||||
* @param key Colon-divided key
|
||||
* @returns Value at key
|
||||
*/
|
||||
@computed get<T extends keyof ISettings>(key: T) {
|
||||
return this.data.get(key) as ISettings[T] | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value in settings without type-checking.
|
||||
* @param key Colon-divided key
|
||||
* @param value Value
|
||||
*/
|
||||
@action setUnchecked(key: string, value: unknown) {
|
||||
return this.data.set(key, value);
|
||||
this.data.set(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a settings key with unknown type.
|
||||
* @param key Colon-divided key
|
||||
* @returns Value at key
|
||||
*/
|
||||
@computed getUnchecked(key: string) {
|
||||
return this.data.get(key);
|
||||
}
|
||||
|
|
94
src/mobx/stores/helpers/STheme.ts
Normal file
94
src/mobx/stores/helpers/STheme.ts
Normal file
|
@ -0,0 +1,94 @@
|
|||
import { makeAutoObservable, computed } from "mobx";
|
||||
|
||||
import {
|
||||
Theme,
|
||||
PRESETS,
|
||||
Variables,
|
||||
DEFAULT_FONT,
|
||||
DEFAULT_MONO_FONT,
|
||||
} from "../../../context/Theme";
|
||||
|
||||
import Settings from "../Settings";
|
||||
|
||||
/**
|
||||
* Helper class for reading and writing themes.
|
||||
*/
|
||||
export default class STheme {
|
||||
private settings: Settings;
|
||||
|
||||
/**
|
||||
* Construct a new theme helper.
|
||||
* @param settings Settings parent class
|
||||
*/
|
||||
constructor(settings: Settings) {
|
||||
this.settings = settings;
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base theme used for this theme.
|
||||
* @returns Id of base theme
|
||||
*/
|
||||
@computed getBase() {
|
||||
return this.settings.get("appearance:theme:base") ?? "dark";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the theme is light.
|
||||
* @returns True if the theme is light
|
||||
*/
|
||||
@computed isLight() {
|
||||
return (
|
||||
this.settings.get("appearance:theme:light") ??
|
||||
this.getBase() === "light"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current theme's CSS variables.
|
||||
* @returns Record of CSS variables
|
||||
*/
|
||||
@computed getVariables(): Theme {
|
||||
return {
|
||||
...PRESETS[this.getBase()],
|
||||
...this.settings.get("appearance:theme:overrides"),
|
||||
light: this.isLight(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific value of a variable by its key.
|
||||
* @param key Variable
|
||||
* @returns Value of variable
|
||||
*/
|
||||
@computed getVariable(key: Variables) {
|
||||
return (this.settings.get("appearance:theme:overrides") ??
|
||||
PRESETS[this.getBase()])[key]!;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current applied font.
|
||||
* @returns Current font
|
||||
*/
|
||||
@computed getFont() {
|
||||
return this.settings.get("appearance:theme:font") ?? DEFAULT_FONT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current applied monospace font.
|
||||
* @returns Current monospace font
|
||||
*/
|
||||
@computed getMonospaceFont() {
|
||||
return (
|
||||
this.settings.get("appearance:theme:monoFont") ?? DEFAULT_MONO_FONT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently applied CSS snippet.
|
||||
* @returns CSS string
|
||||
*/
|
||||
@computed getCSS() {
|
||||
return this.settings.get("appearance:theme:css");
|
||||
}
|
||||
}
|
|
@ -5,13 +5,9 @@ import { LIBRARY_VERSION } from "revolt.js";
|
|||
|
||||
import styles from "./Login.module.scss";
|
||||
import { Text } from "preact-i18n";
|
||||
import { useContext } from "preact/hooks";
|
||||
|
||||
import { useApplicationState } from "../../mobx/State";
|
||||
|
||||
import { ThemeContext } from "../../context/Theme";
|
||||
import { AppContext } from "../../context/revoltjs/RevoltClient";
|
||||
|
||||
import LocaleSelector from "../../components/common/LocaleSelector";
|
||||
import background from "./background.jpg";
|
||||
|
||||
|
@ -23,8 +19,9 @@ import { FormReset, FormSendReset } from "./forms/FormReset";
|
|||
import { FormResend, FormVerify } from "./forms/FormVerify";
|
||||
|
||||
export default observer(() => {
|
||||
const theme = useContext(ThemeContext);
|
||||
const configuration = useApplicationState().config.get();
|
||||
const state = useApplicationState();
|
||||
const theme = state.settings.theme;
|
||||
const configuration = state.config.get();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -33,7 +30,10 @@ export default observer(() => {
|
|||
)}
|
||||
<div className={styles.login}>
|
||||
<Helmet>
|
||||
<meta name="theme-color" content={theme.background} />
|
||||
<meta
|
||||
name="theme-color"
|
||||
content={theme.getVariable("background")}
|
||||
/>
|
||||
</Helmet>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.attribution}>
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
|
||||
import { isTouchscreenDevice } from "../../lib/isTouchscreenDevice";
|
||||
|
||||
import { ThemeContext } from "../../context/Theme";
|
||||
import { useApplicationState } from "../../mobx/State";
|
||||
|
||||
import Category from "../../components/ui/Category";
|
||||
import Header from "../../components/ui/Header";
|
||||
|
@ -53,7 +53,7 @@ export function GenericSettings({
|
|||
showExitButton,
|
||||
}: Props) {
|
||||
const history = useHistory();
|
||||
const theme = useContext(ThemeContext);
|
||||
const theme = useApplicationState().settings.theme;
|
||||
const { page } = useParams<{ page: string }>();
|
||||
|
||||
const [closing, setClosing] = useState(false);
|
||||
|
@ -94,8 +94,8 @@ export function GenericSettings({
|
|||
name="theme-color"
|
||||
content={
|
||||
isTouchscreenDevice
|
||||
? theme["background"]
|
||||
: theme["secondary-background"]
|
||||
? theme.getVariable("background")
|
||||
: theme.getVariable("secondary-background")
|
||||
}
|
||||
/>
|
||||
</Helmet>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Reset, Import } from "@styled-icons/boxicons-regular";
|
||||
import { Pencil, Store } from "@styled-icons/boxicons-solid";
|
||||
import { Link } from "react-router-dom";
|
||||
// @ts-expect-error shade-blend-color does not have typings.
|
||||
import pSBC from "shade-blend-color";
|
||||
|
||||
|
@ -8,16 +9,14 @@ import { Text } from "preact-i18n";
|
|||
import { useCallback, useContext, useEffect, useState } from "preact/hooks";
|
||||
|
||||
import TextAreaAutoSize from "../../../lib/TextAreaAutoSize";
|
||||
import CategoryButton from "../../../components/ui/fluent/CategoryButton";
|
||||
|
||||
|
||||
import { debounce } from "../../../lib/debounce";
|
||||
|
||||
import { useApplicationState } from "../../../mobx/State";
|
||||
import { dispatch } from "../../../redux";
|
||||
import { connectState } from "../../../redux/connector";
|
||||
import { isExperimentEnabled } from "../../../redux/reducers/experiments";
|
||||
import { EmojiPacks, Settings } from "../../../redux/reducers/settings";
|
||||
|
||||
|
||||
import {
|
||||
DEFAULT_FONT,
|
||||
DEFAULT_MONO_FONT,
|
||||
|
@ -28,7 +27,6 @@ import {
|
|||
MONOSPACE_FONTS,
|
||||
MONOSPACE_FONT_KEYS,
|
||||
Theme,
|
||||
ThemeContext,
|
||||
ThemeOptions,
|
||||
} from "../../../context/Theme";
|
||||
import { useIntermediate } from "../../../context/intermediate/Intermediate";
|
||||
|
@ -40,14 +38,13 @@ import Checkbox from "../../../components/ui/Checkbox";
|
|||
import ColourSwatches from "../../../components/ui/ColourSwatches";
|
||||
import ComboBox from "../../../components/ui/ComboBox";
|
||||
import InputBox from "../../../components/ui/InputBox";
|
||||
import CategoryButton from "../../../components/ui/fluent/CategoryButton";
|
||||
import darkSVG from "../assets/dark.svg";
|
||||
import lightSVG from "../assets/light.svg";
|
||||
import mutantSVG from "../assets/mutant_emoji.svg";
|
||||
import notoSVG from "../assets/noto_emoji.svg";
|
||||
import openmojiSVG from "../assets/openmoji_emoji.svg";
|
||||
import twemojiSVG from "../assets/twemoji_emoji.svg";
|
||||
import { Link } from "react-router-dom";
|
||||
import { isExperimentEnabled } from "../../../redux/reducers/experiments";
|
||||
|
||||
interface Props {
|
||||
settings: Settings;
|
||||
|
@ -55,7 +52,7 @@ interface Props {
|
|||
|
||||
// ! FIXME: code needs to be rewritten to fix jittering
|
||||
export function Component(props: Props) {
|
||||
const theme = useContext(ThemeContext);
|
||||
const theme = useApplicationState().settings.theme;
|
||||
const { writeClipboard, openScreen } = useIntermediate();
|
||||
|
||||
function setTheme(theme: ThemeOptions) {
|
||||
|
@ -112,8 +109,7 @@ export function Component(props: Props) {
|
|||
draggable={false}
|
||||
data-active={selected === "light"}
|
||||
onClick={() =>
|
||||
selected !== "light" &&
|
||||
setTheme({ base: "light" })
|
||||
selected !== "light" && setTheme({ base: "light" })
|
||||
}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
|
@ -138,16 +134,24 @@ export function Component(props: Props) {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{isExperimentEnabled('theme_shop') && <Link to="/settings/theme_shop" replace>
|
||||
<CategoryButton icon={<Store size={24} />} action="chevron" hover>
|
||||
<Text id="app.settings.pages.theme_shop.title" />
|
||||
</CategoryButton>
|
||||
</Link>}
|
||||
{isExperimentEnabled("theme_shop") && (
|
||||
<Link to="/settings/theme_shop" replace>
|
||||
<CategoryButton
|
||||
icon={<Store size={24} />}
|
||||
action="chevron"
|
||||
hover>
|
||||
<Text id="app.settings.pages.theme_shop.title" />
|
||||
</CategoryButton>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
<h3>
|
||||
<Text id="app.settings.pages.appearance.accent_selector" />
|
||||
</h3>
|
||||
<ColourSwatches value={theme.accent} onChange={setAccent} />
|
||||
<ColourSwatches
|
||||
value={theme.getVariable("accent")}
|
||||
onChange={setAccent}
|
||||
/>
|
||||
|
||||
{/*<h3>
|
||||
<Text id="app.settings.pages.appearance.message_display" />
|
||||
|
@ -175,7 +179,7 @@ export function Component(props: Props) {
|
|||
<Text id="app.settings.pages.appearance.font" />
|
||||
</h3>
|
||||
<ComboBox
|
||||
value={theme.font ?? DEFAULT_FONT}
|
||||
value={theme.getFont()}
|
||||
onChange={(e) =>
|
||||
pushOverride({ font: e.currentTarget.value as Fonts })
|
||||
}>
|
||||
|
@ -363,11 +367,11 @@ export function Component(props: Props) {
|
|||
<div
|
||||
className={styles.entry}
|
||||
key={x}
|
||||
style={{ backgroundColor: theme[x] }}>
|
||||
style={{ backgroundColor: theme.getVariable(x) }}>
|
||||
<div className={styles.input}>
|
||||
<input
|
||||
type="color"
|
||||
value={theme[x]}
|
||||
value={theme.getVariable(x)}
|
||||
onChange={(v) =>
|
||||
setOverride({
|
||||
[x]: v.currentTarget.value,
|
||||
|
@ -377,8 +381,8 @@ export function Component(props: Props) {
|
|||
</div>
|
||||
<span
|
||||
style={`color: ${getContrastingColour(
|
||||
theme[x],
|
||||
theme["primary-background"],
|
||||
theme.getVariable(x),
|
||||
theme.getVariable("primary-background"),
|
||||
)}`}>
|
||||
{x}
|
||||
</span>
|
||||
|
@ -395,7 +399,7 @@ export function Component(props: Props) {
|
|||
<InputBox
|
||||
type="text"
|
||||
className={styles.text}
|
||||
value={theme[x]}
|
||||
value={theme.getVariable(x)}
|
||||
onChange={(y) =>
|
||||
setOverride({
|
||||
[x]: y.currentTarget.value,
|
||||
|
@ -416,7 +420,7 @@ export function Component(props: Props) {
|
|||
<Text id="app.settings.pages.appearance.mono_font" />
|
||||
</h3>
|
||||
<ComboBox
|
||||
value={theme.monospaceFont ?? DEFAULT_MONO_FONT}
|
||||
value={theme.getMonospaceFont()}
|
||||
onChange={(e) =>
|
||||
pushOverride({
|
||||
monospaceFont: e.currentTarget
|
||||
|
|
Loading…
Reference in a new issue