import { Reset, Import } from "@styled-icons/boxicons-regular"; import { Pencil } from "@styled-icons/boxicons-solid"; // @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 TextAreaAutoSize from "../../../lib/TextAreaAutoSize"; import { debounce } from "../../../lib/debounce"; import { dispatch } from "../../../redux"; import { connectState } from "../../../redux/connector"; import { EmojiPacks, Settings } from "../../../redux/reducers/settings"; import { DEFAULT_FONT, DEFAULT_MONO_FONT, Fonts, FONTS, FONT_KEYS, MonospaceFonts, MONOSPACE_FONTS, MONOSPACE_FONT_KEYS, Theme, ThemeContext, 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 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"; interface Props { settings: Settings; } // ! FIXME: code needs to be rewritten to fix jittering export function Component(props: Props) { const theme = useContext(ThemeContext); const { writeClipboard, openScreen } = useIntermediate(); function setTheme(theme: ThemeOptions) { dispatch({ type: "SETTINGS_SET_THEME", theme, }); } const pushOverride = useCallback((custom: Partial) => { dispatch({ type: "SETTINGS_SET_THEME_OVERRIDE", custom, }); }, []); function setAccent(accent: string) { setOverride({ accent, "scrollbar-thumb": pSBC(-0.2, accent), }); } const emojiPack = props.settings.appearance?.emojiPack ?? "mutant"; function setEmojiPack(emojiPack: EmojiPacks) { dispatch({ type: "SETTINGS_SET_APPEARANCE", options: { emojiPack, }, }); } // eslint-disable-next-line react-hooks/exhaustive-deps const setOverride = useCallback( debounce(pushOverride as (...args: unknown[]) => void, 200), [pushOverride], ) as (custom: Partial) => void; const [css, setCSS] = useState(props.settings.theme?.custom?.css ?? ""); useEffect(() => setOverride({ css }), [setOverride, css]); const selected = props.settings.theme?.preset ?? "dark"; return (

selected !== "light" && setTheme({ preset: "light" }) } onContextMenu={(e) => e.preventDefault()} />

selected !== "dark" && setTheme({ preset: "dark" }) } onContextMenu={(e) => e.preventDefault()} />

{/* setTheme({ ligatures: !props.settings.theme?.ligatures, }) }> Use the system theme */}

{/*

} checked > } disabled >
*/}

pushOverride({ font: e.currentTarget.value as Fonts }) }> {FONT_KEYS.map((key) => ( ))} {/* TOFIX: Only show when a font with ligature support is selected, i.e.: Inter.*/}

setTheme({ ligatures: !props.settings.theme?.ligatures, }) } description={ }>

setEmojiPack("mutant")} data-active={emojiPack === "mutant"}> e.preventDefault()} />

Mutant Remix{" "} (by Revolt)

setEmojiPack("twemoji")} data-active={emojiPack === "twemoji"}> e.preventDefault()} />

Twemoji

setEmojiPack("openmoji")} data-active={emojiPack === "openmoji"}> e.preventDefault()} />

Openmoji

setEmojiPack("noto")} data-active={emojiPack === "noto"}> e.preventDefault()} />

Noto Emoji

}>
}>
writeClipboard(JSON.stringify(theme))}> }> {" "} {/*TOFIX: Try to put the tooltip above the .code div without messing up the css challenge */} {JSON.stringify(theme)}
}>

App

{( [ "accent", "background", "foreground", "primary-background", "primary-header", "secondary-background", "secondary-foreground", "secondary-header", "tertiary-background", "tertiary-foreground", "block", "message-box", "mention", "scrollbar-thumb", "scrollbar-track", "status-online", "status-away", "status-busy", "status-streaming", "status-invisible", "success", "warning", "error", "hover", ] as const ).map((x) => (
setOverride({ [x]: v.currentTarget.value, }) } />
{x}
e.currentTarget.parentElement?.parentElement ?.querySelector("input") ?.click() }>
setOverride({ [x]: y.currentTarget.value, }) } />
))}
}>

pushOverride({ monospaceFont: e.currentTarget .value as MonospaceFonts, }) }> {MONOSPACE_FONT_KEYS.map((key) => ( ))}

setCSS(ev.currentTarget.value)} />
); } export const Appearance = connectState(Component, (state) => { return { settings: state.settings, }; }); function getContrastingColour(hex: string, fallback: string): string { hex = hex.replace("#", ""); const r = parseInt(hex.substr(0, 2), 16); const g = parseInt(hex.substr(2, 2), 16); const b = parseInt(hex.substr(4, 2), 16); const cc = (r * 299 + g * 587 + b * 114) / 1000; if (isNaN(r) || isNaN(g) || isNaN(b) || isNaN(cc)) return getContrastingColour(fallback, "#fffff"); return cc >= 175 ? "black" : "white"; }