tokenize-it / src /components /InputPanel.tsx
Orion-zhen's picture
:boom: use web stack
21ab33c unverified
Raw History Blame Contribute Delete
3.63 kB
import { Eraser, LoaderCircle, Sparkles, WandSparkles } from "lucide-react";
const EXAMPLE = "Tokenization turns language into structure. 理解分词,就是理解模型如何阅读世界。";
interface InputPanelProps {
text: string;
ready: boolean;
loading: boolean;
tokenizing: boolean;
dirtyModel: boolean;
onTextChange: (value: string) => void;
onTokenize: () => void;
}
export function InputPanel({
text,
ready,
loading,
tokenizing,
dirtyModel,
onTextChange,
onTokenize,
}: InputPanelProps) {
const words = text.trim() ? text.trim().split(/\s+/u).length : 0;
const lines = text ? text.split(/\r?\n/u).length : 0;
const disabled = !ready || loading || tokenizing || !text || dirtyModel;
return (
<section className="surface p-3" aria-labelledby="input-heading">
<div className="flex items-center justify-between px-2 pb-2">
<h1 id="input-heading" className="text-sm font-semibold text-[var(--ink)]">
输入
</h1>
<span className="eyebrow">Local only</span>
</div>
<div className="editor-shell">
<textarea
className="min-h-48 w-full resize-y bg-transparent px-4 pb-3 pt-4 text-[16px] leading-7 text-[var(--ink)] outline-none placeholder:text-[var(--muted)] sm:min-h-52"
value={text}
maxLength={200000}
onChange={(event) => onTextChange(event.target.value)}
onKeyDown={(event) => {
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
event.preventDefault();
onTokenize();
}
}}
placeholder="写下或粘贴一段文本……"
aria-label="需要 Tokenize 的文本"
/>
<div className="flex flex-col gap-2 border-t border-[var(--line)] px-3 py-2.5 sm:flex-row sm:items-center sm:justify-between">
<span className="font-mono text-[10px] text-[var(--muted)]">
{text.length.toLocaleString()} characters&nbsp; · &nbsp;{words.toLocaleString()} words&nbsp; · &nbsp;{lines} lines
</span>
<div className="flex items-center justify-end gap-1.5">
<span className="mr-1 hidden text-[9px] text-[var(--muted)] md:inline">
⌘ / Ctrl + Enter
</span>
<button
className="mini-icon-button"
type="button"
onClick={() => onTextChange(EXAMPLE)}
aria-label="填入示例文本"
title="示例文本"
>
<WandSparkles size={14} />
</button>
<button
className="mini-icon-button"
type="button"
onClick={() => onTextChange("")}
aria-label="清空文本"
title="清空"
>
<Eraser size={14} />
</button>
<button
className="tokenize-button ml-1 min-w-32 justify-center"
type="button"
onClick={onTokenize}
disabled={disabled}
>
{tokenizing ? (
<LoaderCircle className="animate-spin" size={16} />
) : (
<Sparkles size={16} />
)}
{dirtyModel
? "重新加载模型"
: loading
? "加载中"
: tokenizing
? "解析中"
: ready
? "Tokenize"
: "先加载模型"}
</button>
</div>
</div>
</div>
</section>
);
}