Phase 9: ESL superpowers — Chinese gloss + tone-rewrite
Inline Chinese gloss (offline) and a "say it more naturally" / tone-rewrite,
the two ESL features for the Mandarin-speaking writer.
Gloss: embedded English→Chinese dictionary (gloss.json.gz, 57k common words
built from ECDICT via scripts/build_gloss.py). lexicon gains Gloss()/Result.Gloss
and a lightweight GET /api/gloss/{word}; the right-click WordCard leads with the
中文; GlossTip shows it on a 350ms hover (reuses wordAt, so CJK is never glossed).
Offline + instant, works with the LLM down.
Rewrite: selecting text pops a SelectionBubble (✨更自然 + the tone vocabulary);
picking a style calls POST /api/docs/:id/rewrite (llm.RunRewrite, stateless,
owner-scoped) and shows a RewritePreview (original→rewrite, accept/cancel/retry).
Accept applies it in-editor.
Tests added in lexicon and suggestions. go build/vet/test, tsc, vite all clean;
live smoke vs a fake vLLM verified gloss + rewrite + 400/404/502 paths.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
This commit is contained in:
32
web/src/components/Editor/GlossTip.tsx
Normal file
32
web/src/components/Editor/GlossTip.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
// GlossTip is the inline hover gloss: rest the pointer on an English word and a
|
||||
// small bubble shows its Chinese meaning, pulled instantly from the offline
|
||||
// gloss dataset. It's a pure reading aid — pointer-events are off so it never
|
||||
// steals hover or blocks a click, and it sits just under the word. Bilingual
|
||||
// chrome elsewhere puts zh first; here the gloss IS the content (the word is
|
||||
// already on screen), so the bubble shows only the 中文.
|
||||
|
||||
interface Props {
|
||||
gloss: string
|
||||
style: React.CSSProperties
|
||||
}
|
||||
|
||||
export function GlossTip({ gloss, style }: Props) {
|
||||
return (
|
||||
<div
|
||||
className="petal-gloss-tip pointer-events-none absolute z-20 px-2.5 py-1.5 text-sm"
|
||||
role="tooltip"
|
||||
style={{
|
||||
maxWidth: 280,
|
||||
background: 'var(--color-plum)',
|
||||
color: 'var(--color-surface)',
|
||||
borderRadius: 'var(--radius-input)',
|
||||
boxShadow: 'var(--shadow-soft)',
|
||||
lineHeight: 1.35,
|
||||
fontFamily: "'Nunito','PingFang SC','Microsoft YaHei','Noto Sans CJK SC',sans-serif",
|
||||
...style,
|
||||
}}
|
||||
>
|
||||
{gloss}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user