tokenize-it / src /components /SettingsMenu.tsx
Orion-zhen's picture
:boom: use web stack
21ab33c unverified
Raw History Blame Contribute Delete
3.25 kB
import { Check, Moon, Settings, Sun, Trash2 } from "lucide-react";
import { useEffect, useRef } from "react";
import { formatBytes } from "../lib/format";
interface SettingsMenuProps {
open: boolean;
dark: boolean;
addSpecialTokens: boolean;
cacheCleared: boolean;
cacheSizeBytes: number | null;
onOpenChange: (open: boolean) => void;
onDarkChange: (dark: boolean) => void;
onAddSpecialTokensChange: (value: boolean) => void;
onClearCache: () => void;
}
export function SettingsMenu({
open,
dark,
addSpecialTokens,
cacheCleared,
cacheSizeBytes,
onOpenChange,
onDarkChange,
onAddSpecialTokensChange,
onClearCache,
}: SettingsMenuProps) {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!open) return;
const closeOnOutsideClick = (event: PointerEvent) => {
if (!containerRef.current?.contains(event.target as Node)) onOpenChange(false);
};
const closeOnEscape = (event: KeyboardEvent) => {
if (event.key === "Escape") onOpenChange(false);
};
document.addEventListener("pointerdown", closeOnOutsideClick);
document.addEventListener("keydown", closeOnEscape);
return () => {
document.removeEventListener("pointerdown", closeOnOutsideClick);
document.removeEventListener("keydown", closeOnEscape);
};
}, [open, onOpenChange]);
return (
<div className="relative" ref={containerRef}>
<button
className="toolbar-control"
type="button"
aria-expanded={open}
onClick={() => onOpenChange(!open)}
>
<Settings size={16} />
<span className="hidden sm:inline">设置</span>
</button>
{open ? (
<div className="popover-panel absolute right-0 top-[calc(100%+10px)] z-30 w-72 p-4">
<p className="text-xs font-semibold text-[var(--ink)]">显示与编码</p>
<label className="settings-row mt-3">
<span>
<strong>边界 Special Tokens</strong>
<small>按模型配置添加 BOS 和 EOS</small>
</span>
<input
className="peer sr-only"
type="checkbox"
checked={addSpecialTokens}
onChange={(event) => onAddSpecialTokensChange(event.target.checked)}
/>
<span className="toggle" />
</label>
<button className="settings-row mt-1 w-full" type="button" onClick={() => onDarkChange(!dark)}>
<span>
<strong>外观</strong>
<small>{dark ? "当前为深色模式" : "当前为浅色模式"}</small>
</span>
{dark ? <Moon size={17} /> : <Sun size={17} />}
</button>
<button className="settings-row mt-1 w-full" type="button" onClick={onClearCache}>
<span>
<strong>浏览器缓存</strong>
<small>
{cacheSizeBytes === null
? "正在计算…"
: `当前占用 ${formatBytes(cacheSizeBytes)}`}
</small>
</span>
{cacheCleared ? <Check className="text-[var(--success)]" size={17} /> : <Trash2 size={17} />}
</button>
</div>
) : null}
</div>
);
}