From 65be047dc62e8567272e581caf4d210020f5826a Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Mon, 13 Dec 2021 17:27:30 +0000 Subject: [PATCH] feat(mobx): continue implementing themes; performance work on settings --- src/components/settings/AppearanceShims.tsx | 258 ++++++++++++++++ .../settings/appearance/ThemeBaseSelector.tsx | 84 ++++++ .../settings/appearance}/dark.svg | 0 .../settings/appearance}/light.svg | 0 .../settings}/mutant_emoji.svg | 0 .../settings}/noto_emoji.svg | 0 .../settings}/openmoji_emoji.svg | 0 .../settings}/twemoji_emoji.svg | 0 src/components/ui/Radio.tsx | 9 +- src/context/Theme.tsx | 6 +- src/mobx/stores/Cache.ts | 76 +++++ src/mobx/stores/Settings.ts | 4 + src/mobx/stores/helpers/STheme.ts | 36 ++- src/pages/settings/panes/Appearance.tsx | 279 ++---------------- src/pages/settings/panes/Panes.module.scss | 32 -- 15 files changed, 497 insertions(+), 287 deletions(-) create mode 100644 src/components/settings/AppearanceShims.tsx create mode 100644 src/components/settings/appearance/ThemeBaseSelector.tsx rename src/{pages/settings/assets => components/settings/appearance}/dark.svg (100%) rename src/{pages/settings/assets => components/settings/appearance}/light.svg (100%) rename src/{pages/settings/assets => components/settings}/mutant_emoji.svg (100%) rename src/{pages/settings/assets => components/settings}/noto_emoji.svg (100%) rename src/{pages/settings/assets => components/settings}/openmoji_emoji.svg (100%) rename src/{pages/settings/assets => components/settings}/twemoji_emoji.svg (100%) create mode 100644 src/mobx/stores/Cache.ts diff --git a/src/components/settings/AppearanceShims.tsx b/src/components/settings/AppearanceShims.tsx new file mode 100644 index 00000000..a4bcae0b --- /dev/null +++ b/src/components/settings/AppearanceShims.tsx @@ -0,0 +1,258 @@ +import { Store } from "@styled-icons/boxicons-regular"; +import { observer } from "mobx-react-lite"; +import { Link } from "react-router-dom"; + +import { Text } from "preact-i18n"; + +import TextAreaAutoSize from "../../lib/TextAreaAutoSize"; + +import { useApplicationState } from "../../mobx/State"; +import { EmojiPack } from "../../mobx/stores/Settings"; + +import { + Fonts, + FONTS, + FONT_KEYS, + MonospaceFonts, + MONOSPACE_FONTS, + MONOSPACE_FONT_KEYS, +} from "../../context/Theme"; + +import Checkbox from "../ui/Checkbox"; +import ColourSwatches from "../ui/ColourSwatches"; +import ComboBox from "../ui/ComboBox"; +import Radio from "../ui/Radio"; +import CategoryButton from "../ui/fluent/CategoryButton"; +import mutantSVG from "./mutant_emoji.svg"; +import notoSVG from "./noto_emoji.svg"; +import openmojiSVG from "./openmoji_emoji.svg"; +import twemojiSVG from "./twemoji_emoji.svg"; + +import { ThemeBaseSelector } from "./appearance/ThemeBaseSelector"; + +export const ThemeBaseSelectorShim = observer(() => { + const theme = useApplicationState().settings.theme; + return ( + + ); +}); + +export const ThemeShopShim = () => { + if (!useApplicationState().experiments.isEnabled("theme_shop")) return null; + + return ( + + } action="chevron" hover> + + + + ); +}; + +export const ThemeAccentShim = observer(() => { + const theme = useApplicationState().settings.theme; + return ( + <> +

+ +

+ theme.setVariable("accent", colour)} + /> + + ); +}); + +export const ThemeCustomCSSShim = observer(() => { + const theme = useApplicationState().settings.theme; + return ( + <> +

+ +

+ theme.setCSS(ev.currentTarget.value)} + /> + + ); +}); + +export const DisplayCompactShim = () => { + return ( + <> +

+ +

+
+ + } + checked> + + + + } + disabled> + + +
+ + ); +}; + +export const DisplayFontShim = observer(() => { + const theme = useApplicationState().settings.theme; + return ( + <> +

+ +

+ theme.setFont(e.currentTarget.value as Fonts)}> + {FONT_KEYS.map((key) => ( + + ))} + + + ); +}); + +export const DisplayMonospaceFontShim = observer(() => { + const theme = useApplicationState().settings.theme; + return ( + <> +

+ +

+ + theme.setMonospaceFont( + e.currentTarget.value as MonospaceFonts, + ) + }> + {MONOSPACE_FONT_KEYS.map((key) => ( + + ))} + + + ); +}); + +export const DisplayLigaturesShim = observer(() => { + const settings = useApplicationState().settings; + if (settings.theme.getFont() !== "Inter") return null; + + return ( +

+ settings.set("appearance:ligatures", v)} + description={ + + }> + + +

+ ); +}); + +export const DisplayEmojiShim = observer(() => { + const settings = useApplicationState().settings; + const emojiPack = settings.get("appearance:emoji"); + const setPack = (v: EmojiPack) => () => settings.set("appearance:emoji", v); + + return ( + <> +

+ +

+
+
+
+
+ e.preventDefault()} + /> +
+

+ Mutant Remix{" "} + + (by Revolt) + +

+
+
+
+ e.preventDefault()} + /> +
+

Twemoji

+
+
+
+
+
+ e.preventDefault()} + /> +
+

Openmoji

+
+
+
+ e.preventDefault()} + /> +
+

Noto Emoji

+
+
+
+ + ); +}); diff --git a/src/components/settings/appearance/ThemeBaseSelector.tsx b/src/components/settings/appearance/ThemeBaseSelector.tsx new file mode 100644 index 00000000..54f1b72e --- /dev/null +++ b/src/components/settings/appearance/ThemeBaseSelector.tsx @@ -0,0 +1,84 @@ +import { observer } from "mobx-react-lite"; +import styled from "styled-components"; + +import { Text } from "preact-i18n"; + +import { useApplicationState } from "../../../mobx/State"; + +import darkSVG from "./dark.svg"; +import lightSVG from "./light.svg"; + +const List = styled.div` + gap: 8px; + display: flex; + width: 100%; + + > div { + min-width: 0; + display: flex; + flex-direction: column; + } + + img { + cursor: pointer; + border-radius: var(--border-radius); + transition: border 0.3s; + border: 3px solid transparent; + width: 100%; + + &[data-active="true"] { + cursor: default; + border: 3px solid var(--accent); + &:hover { + border: 3px solid var(--accent); + } + } + + &:hover { + border: 3px solid var(--tertiary-background); + } + } +`; + +interface Props { + value?: "light" | "dark"; + setValue: (base: "light" | "dark") => void; +} + +export function ThemeBaseSelector({ value, setValue }: Props) { + return ( + <> +

+ +

+ +
+ value !== "light" && setValue("light")} + onContextMenu={(e) => e.preventDefault()} + /> +

+ +

+
+
+ value !== "dark" && setValue("dark")} + onContextMenu={(e) => e.preventDefault()} + /> +

+ +

+
+
+ + ); +} diff --git a/src/pages/settings/assets/dark.svg b/src/components/settings/appearance/dark.svg similarity index 100% rename from src/pages/settings/assets/dark.svg rename to src/components/settings/appearance/dark.svg diff --git a/src/pages/settings/assets/light.svg b/src/components/settings/appearance/light.svg similarity index 100% rename from src/pages/settings/assets/light.svg rename to src/components/settings/appearance/light.svg diff --git a/src/pages/settings/assets/mutant_emoji.svg b/src/components/settings/mutant_emoji.svg similarity index 100% rename from src/pages/settings/assets/mutant_emoji.svg rename to src/components/settings/mutant_emoji.svg diff --git a/src/pages/settings/assets/noto_emoji.svg b/src/components/settings/noto_emoji.svg similarity index 100% rename from src/pages/settings/assets/noto_emoji.svg rename to src/components/settings/noto_emoji.svg diff --git a/src/pages/settings/assets/openmoji_emoji.svg b/src/components/settings/openmoji_emoji.svg similarity index 100% rename from src/pages/settings/assets/openmoji_emoji.svg rename to src/components/settings/openmoji_emoji.svg diff --git a/src/pages/settings/assets/twemoji_emoji.svg b/src/components/settings/twemoji_emoji.svg similarity index 100% rename from src/pages/settings/assets/twemoji_emoji.svg rename to src/components/settings/twemoji_emoji.svg diff --git a/src/components/ui/Radio.tsx b/src/components/ui/Radio.tsx index a9418d88..8f4dbb6c 100644 --- a/src/components/ui/Radio.tsx +++ b/src/components/ui/Radio.tsx @@ -7,9 +7,9 @@ interface Props { children: Children; description?: Children; - checked: boolean; + checked?: boolean; disabled?: boolean; - onSelect: () => void; + onSelect?: () => void; } interface BaseProps { @@ -87,9 +87,10 @@ const RadioDescription = styled.span` `; export default function Radio(props: Props) { + const selected = props.checked ?? false; return ( !props.disabled && props.onSelect && props.onSelect() @@ -101,7 +102,7 @@ export default function Radio(props: Props) { {props.children} {props.description && ( - + {props.description} )} diff --git a/src/context/Theme.tsx b/src/context/Theme.tsx index cd6edfb7..55370c44 100644 --- a/src/context/Theme.tsx +++ b/src/context/Theme.tsx @@ -1,7 +1,7 @@ +import { observer } from "mobx-react-lite"; import { Helmet } from "react-helmet"; import { createGlobalStyle } from "styled-components"; -import { createContext } from "preact"; import { useEffect } from "preact/hooks"; import { useApplicationState } from "../mobx/State"; @@ -316,7 +316,7 @@ export const generateVariables = (theme: Theme) => { }); }; -export default function Theme() { +export default observer(() => { const settings = useApplicationState().settings; const theme = settings.theme; @@ -359,4 +359,4 @@ export default function Theme() {