mirror of
https://github.com/stoatchat/for-legacy-web.git
synced 2026-03-07 01:15:28 +00:00
feat(mobx): continue implementing themes; performance work on settings
This commit is contained in:
@@ -1,61 +1,50 @@
|
||||
import { Reset, Import } from "@styled-icons/boxicons-regular";
|
||||
import { Pencil, Store } from "@styled-icons/boxicons-solid";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Pencil } from "@styled-icons/boxicons-solid";
|
||||
import { observer } from "mobx-react-lite";
|
||||
// @ts-expect-error shade-blend-color does not have typings.
|
||||
import pSBC from "shade-blend-color";
|
||||
|
||||
import styles from "./Panes.module.scss";
|
||||
import { Text } from "preact-i18n";
|
||||
import { useCallback, useContext, useEffect, useState } from "preact/hooks";
|
||||
import { useCallback, useEffect, useState } from "preact/hooks";
|
||||
|
||||
import TextAreaAutoSize from "../../../lib/TextAreaAutoSize";
|
||||
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,
|
||||
Fonts,
|
||||
FONTS,
|
||||
FONT_KEYS,
|
||||
MonospaceFonts,
|
||||
MONOSPACE_FONTS,
|
||||
MONOSPACE_FONT_KEYS,
|
||||
Theme,
|
||||
ThemeOptions,
|
||||
} from "../../../context/Theme";
|
||||
import { Theme, ThemeOptions } from "../../../context/Theme";
|
||||
import { useIntermediate } from "../../../context/intermediate/Intermediate";
|
||||
|
||||
import CollapsibleSection from "../../../components/common/CollapsibleSection";
|
||||
import Tooltip from "../../../components/common/Tooltip";
|
||||
import Button from "../../../components/ui/Button";
|
||||
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 {
|
||||
ThemeBaseSelectorShim,
|
||||
ThemeShopShim,
|
||||
ThemeAccentShim,
|
||||
DisplayCompactShim,
|
||||
DisplayFontShim,
|
||||
DisplayMonospaceFontShim,
|
||||
DisplayLigaturesShim,
|
||||
DisplayEmojiShim,
|
||||
ThemeCustomCSSShim,
|
||||
} from "../../../components/settings/AppearanceShims";
|
||||
|
||||
interface Props {
|
||||
settings: Settings;
|
||||
}
|
||||
|
||||
// ! FIXME: code needs to be rewritten to fix jittering
|
||||
export function Component(props: Props) {
|
||||
const theme = useApplicationState().settings.theme;
|
||||
export const Component = observer((props: Props) => {
|
||||
//const theme = useApplicationState().settings.theme;
|
||||
const { writeClipboard, openScreen } = useIntermediate();
|
||||
|
||||
function setTheme(theme: ThemeOptions) {
|
||||
/*function setTheme(theme: ThemeOptions) {
|
||||
dispatch({
|
||||
type: "SETTINGS_SET_THEME",
|
||||
theme,
|
||||
@@ -95,191 +84,18 @@ export function Component(props: Props) {
|
||||
|
||||
useEffect(() => setOverride({ css }), [setOverride, css]);
|
||||
|
||||
const selected = props.settings.theme?.base ?? "dark";
|
||||
const selected = theme.getBase();*/
|
||||
return (
|
||||
<div className={styles.appearance}>
|
||||
<h3>
|
||||
<Text id="app.settings.pages.appearance.theme" />
|
||||
</h3>
|
||||
<div className={styles.themes}>
|
||||
<div className={styles.theme}>
|
||||
<img
|
||||
loading="eager"
|
||||
src={lightSVG}
|
||||
draggable={false}
|
||||
data-active={selected === "light"}
|
||||
onClick={() =>
|
||||
selected !== "light" && setTheme({ base: "light" })
|
||||
}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
<h4>
|
||||
<Text id="app.settings.pages.appearance.color.light" />
|
||||
</h4>
|
||||
</div>
|
||||
<div className={styles.theme}>
|
||||
<img
|
||||
loading="eager"
|
||||
src={darkSVG}
|
||||
draggable={false}
|
||||
data-active={selected === "dark"}
|
||||
onClick={() =>
|
||||
selected !== "dark" && setTheme({ base: "dark" })
|
||||
}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
<h4>
|
||||
<Text id="app.settings.pages.appearance.color.dark" />
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
<ThemeBaseSelectorShim />
|
||||
<ThemeShopShim />
|
||||
<ThemeAccentShim />
|
||||
{/*<DisplayCompactShim />
|
||||
<DisplayFontShim />
|
||||
<DisplayLigaturesShim />
|
||||
<DisplayEmojiShim />*/}
|
||||
|
||||
{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.getVariable("accent")}
|
||||
onChange={setAccent}
|
||||
/>
|
||||
|
||||
{/*<h3>
|
||||
<Text id="app.settings.pages.appearance.message_display" />
|
||||
</h3>
|
||||
<div className={styles.display}>
|
||||
<Radio
|
||||
description={
|
||||
<Text id="app.settings.pages.appearance.display.default_description" />
|
||||
}
|
||||
checked
|
||||
>
|
||||
<Text id="app.settings.pages.appearance.display.default" />
|
||||
</Radio>
|
||||
<Radio
|
||||
description={
|
||||
<Text id="app.settings.pages.appearance.display.compact_description" />
|
||||
}
|
||||
disabled
|
||||
>
|
||||
<Text id="app.settings.pages.appearance.display.compact" />
|
||||
</Radio>
|
||||
</div>*/}
|
||||
|
||||
<h3>
|
||||
<Text id="app.settings.pages.appearance.font" />
|
||||
</h3>
|
||||
<ComboBox
|
||||
value={theme.getFont()}
|
||||
onChange={(e) =>
|
||||
pushOverride({ font: e.currentTarget.value as Fonts })
|
||||
}>
|
||||
{FONT_KEYS.map((key) => (
|
||||
<option value={key} key={key}>
|
||||
{FONTS[key as keyof typeof FONTS].name}
|
||||
</option>
|
||||
))}
|
||||
</ComboBox>
|
||||
{/* TOFIX: Only show when a font with ligature support is selected, i.e.: Inter.*/}
|
||||
<p>
|
||||
<Checkbox
|
||||
checked={props.settings.theme?.ligatures === true}
|
||||
onChange={() =>
|
||||
setTheme({
|
||||
ligatures: !props.settings.theme?.ligatures,
|
||||
})
|
||||
}
|
||||
description={
|
||||
<Text id="app.settings.pages.appearance.ligatures_desc" />
|
||||
}>
|
||||
<Text id="app.settings.pages.appearance.ligatures" />
|
||||
</Checkbox>
|
||||
</p>
|
||||
|
||||
<h3>
|
||||
<Text id="app.settings.pages.appearance.emoji_pack" />
|
||||
</h3>
|
||||
<div className={styles.emojiPack}>
|
||||
<div className={styles.row}>
|
||||
<div>
|
||||
<div
|
||||
className={styles.button}
|
||||
onClick={() => setEmojiPack("mutant")}
|
||||
data-active={emojiPack === "mutant"}>
|
||||
<img
|
||||
loading="eager"
|
||||
src={mutantSVG}
|
||||
draggable={false}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
</div>
|
||||
<h4>
|
||||
Mutant Remix{" "}
|
||||
<a
|
||||
href="https://mutant.revolt.chat"
|
||||
target="_blank"
|
||||
rel="noreferrer">
|
||||
(by Revolt)
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
className={styles.button}
|
||||
onClick={() => setEmojiPack("twemoji")}
|
||||
data-active={emojiPack === "twemoji"}>
|
||||
<img
|
||||
loading="eager"
|
||||
src={twemojiSVG}
|
||||
draggable={false}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
</div>
|
||||
<h4>Twemoji</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.row}>
|
||||
<div>
|
||||
<div
|
||||
className={styles.button}
|
||||
onClick={() => setEmojiPack("openmoji")}
|
||||
data-active={emojiPack === "openmoji"}>
|
||||
<img
|
||||
loading="eager"
|
||||
src={openmojiSVG}
|
||||
draggable={false}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
</div>
|
||||
<h4>Openmoji</h4>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
className={styles.button}
|
||||
onClick={() => setEmojiPack("noto")}
|
||||
data-active={emojiPack === "noto"}>
|
||||
<img
|
||||
loading="eager"
|
||||
src={notoSVG}
|
||||
draggable={false}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
</div>
|
||||
<h4>Noto Emoji</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CollapsibleSection
|
||||
{/*<CollapsibleSection
|
||||
defaultValue={false}
|
||||
id="settings_overrides"
|
||||
summary={<Text id="app.settings.pages.appearance.overrides" />}>
|
||||
@@ -300,7 +116,6 @@ export function Component(props: Props) {
|
||||
onClick={() => writeClipboard(JSON.stringify(theme))}>
|
||||
<Tooltip content={<Text id="app.special.copy" />}>
|
||||
{" "}
|
||||
{/*TOFIX: Try to put the tooltip above the .code div without messing up the css challenge */}
|
||||
{JSON.stringify(theme)}
|
||||
</Tooltip>
|
||||
</div>
|
||||
@@ -410,48 +225,18 @@ export function Component(props: Props) {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CollapsibleSection>
|
||||
</CollapsibleSection>*/}
|
||||
|
||||
<CollapsibleSection
|
||||
id="settings_advanced_appearance"
|
||||
defaultValue={false}
|
||||
summary={<Text id="app.settings.pages.appearance.advanced" />}>
|
||||
<h3>
|
||||
<Text id="app.settings.pages.appearance.mono_font" />
|
||||
</h3>
|
||||
<ComboBox
|
||||
value={theme.getMonospaceFont()}
|
||||
onChange={(e) =>
|
||||
pushOverride({
|
||||
monospaceFont: e.currentTarget
|
||||
.value as MonospaceFonts,
|
||||
})
|
||||
}>
|
||||
{MONOSPACE_FONT_KEYS.map((key) => (
|
||||
<option value={key} key={key}>
|
||||
{
|
||||
MONOSPACE_FONTS[
|
||||
key as keyof typeof MONOSPACE_FONTS
|
||||
].name
|
||||
}
|
||||
</option>
|
||||
))}
|
||||
</ComboBox>
|
||||
|
||||
<h3>
|
||||
<Text id="app.settings.pages.appearance.custom_css" />
|
||||
</h3>
|
||||
<TextAreaAutoSize
|
||||
maxRows={20}
|
||||
minHeight={480}
|
||||
code
|
||||
value={css}
|
||||
onChange={(ev) => setCSS(ev.currentTarget.value)}
|
||||
/>
|
||||
<DisplayMonospaceFontShim />
|
||||
<ThemeCustomCSSShim />
|
||||
</CollapsibleSection>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export const Appearance = connectState(Component, (state) => {
|
||||
return {
|
||||
|
||||
@@ -150,38 +150,6 @@
|
||||
}
|
||||
|
||||
.appearance {
|
||||
.theme {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.themes {
|
||||
gap: 8px;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
details {
|
||||
summary {
|
||||
font-size: 0.8125rem;
|
||||
|
||||
Reference in New Issue
Block a user