import { createEffect, createSignal, For, onCleanup, onMount, Show, untrack, type Accessor, } from "solid-js"; import { createStore } from "solid-js/store"; import texts, { APP_LOCALE_OPTIONS, type AppLocale, } from "../i18n"; import { UI_SCALE_NAMES, type UiScale, uiScaleLevel, } from "../ui"; import { InteractionHelp } from "./InteractionHelp"; import { Dialog } from "./Widgets/Dialog"; import { Icon, type IconName } from "./Widgets/Icon"; type SettingsMenuState = { locale: AppLocale; openGalleryInNewTab: boolean; readerEnabled: boolean; exitReaderOnFullscreenExit: boolean; readerFullscreenEnabled: boolean; replacePreviewWithScroll: boolean; enhanceThumbsGridsEnabled: boolean; enhanceSearchGridsEnabled: boolean; myTagsEnabled: boolean; readHistoryEnabled: boolean; includeUnreadHistoryEnabled: boolean; searchHistoryEnabled: boolean; touchUiEnabled: boolean; fitToViewport: boolean; portraitUiScale: UiScale; landscapeUiScale: UiScale; }; type SettingsTab = "general" | "enhance" | "options" | "about"; const SETTINGS_SECTIONS: ReadonlyArray = [ ["general", texts.settings.general, "book-open"], ["enhance", texts.settings.enhance, "sparkles"], ["options", texts.settings.options, "settings"], ["about", texts.settings.about, "info"], ]; const SETTINGS_ACTION_BUTTON_CLASS = "block w-full min-h-[var(--ui-control-size-md)] ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center [font-size:var(--ui-font-size-md)] font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98"; const SETTINGS_APPLY_BUTTON_COLOR = "border-[var(--color-site-accent)] bg-[var(--color-site-accent)] text-[var(--color-site-surface)] shadow-[0_2px_8px_var(--color-shadow-panel)] hover:brightness-108"; const SETTINGS_CLOSE_BUTTON_COLOR = "border-[var(--color-site-border-subtle)] bg-[var(--color-site-surface)] text-[var(--color-site-text)] hover:bg-[var(--color-site-item-hover)]"; const SETTINGS_DOT_CLASS = "block flex-none ui-w-md ui-h-md rounded-full"; const UI_SCALE_OPTIONS = UI_SCALE_NAMES.map((value) => ({ label: String(uiScaleLevel(value)), value, })); const LICENSES = [ { href: "https://github.com/yamipot/ehpeek/blob/master/LICENSE", license: "MIT", name: "EhPeek", }, { href: "https://github.com/solidjs/solid/blob/main/LICENSE", license: "MIT", name: "SolidJS", }, { href: "https://github.com/lucide-icons/lucide/blob/main/LICENSE", license: "ISC", name: "Lucide Icons", }, { href: "https://github.com/adobe/spectrum-design-data/blob/main/LICENSE", license: "Apache-2.0", name: "Adobe Spectrum Tokens", }, ] as const; function SwitchButton(props: { checked: boolean; description: string; label: string; onChange: (value: boolean) => void; }) { const [helpOpen, setHelpOpen] = createSignal(false); return (

{props.description}

); } function SelectSetting(props: { label: string; noTranslate?: boolean; onChange: (value: T) => void; options: ReadonlyArray<{ label: string; value: T }>; value: T; }) { return ( ); } export function SettingsMenu(props: { historyHref: string; leftHandedControls: Accessor; open: boolean; defaultState: SettingsMenuState; initState: SettingsMenuState; onApply: (state: SettingsMenuState) => void; onOpenChange: (open: boolean) => void; }) { const [draft, setDraft] = createStore( untrack(() => ({ ...props.initState })), ); const [activeTab, setActiveTab] = createSignal("general"); const [helpOpen, setHelpOpen] = createSignal(false); const [licensesOpen, setLicensesOpen] = createSignal(false); const [changed, setChanged] = createSignal(false); let menu!: HTMLDivElement; const close = () => { if (changed() && !window.confirm(texts.settings.discardChanges)) { return false; } props.onOpenChange(false); return true; }; const updateDraft = (key: keyof SettingsMenuState, value: boolean) => { setChanged(true); setDraft(key, value); }; createEffect(() => { if (props.open) { setDraft(untrack(() => ({ ...props.initState }))); setActiveTab("general"); setHelpOpen(false); setLicensesOpen(false); setChanged(false); } }); onMount(() => { const onPointerDown = (event: PointerEvent) => { if (!props.open) { return; } if (event.target instanceof Element && menu.contains(event.target)) { return; } if (!close()) { event.preventDefault(); event.stopImmediatePropagation(); } }; const onKeyDown = (event: KeyboardEvent) => { if (!props.open) { return; } if (event.key === "Escape") { if (!close()) { event.preventDefault(); event.stopImmediatePropagation(); } } }; document.addEventListener("pointerdown", onPointerDown); document.addEventListener("keydown", onKeyDown); onCleanup(() => { document.removeEventListener("pointerdown", onPointerDown); document.removeEventListener("keydown", onKeyDown); }); }); return (
{([tab, label, icon]) => ( )}

{SETTINGS_SECTIONS.find(([tab]) => tab === activeTab())?.[1]}

setHelpOpen(false)} />
setLicensesOpen(false)} title={texts.settings.licenses} variant="site" width="lg" > {(license) => ( {license.name} {license.license} )}
); }