Writer power-ups (Phase 11), plus the selection-bubble vs copy/paste fix.
- Find & Replace (Ctrl/Cmd+F): SearchHighlight decoration extension +
FindReplace bar (match-case, replace-all back-to-front, scroll without
popping the selection bubble).
- Read-aloud (Web Speech, offline) on the word card and selection bubble.
- Keyboard/touch access to the ESL helpers: Ctrl/Cmd+D look up word at caret,
Ctrl/Cmd+J rewrite selection, touch long-press lookup. Refactored the
right-click handler into a shared openWordLookup(pos).
- Whole-corpus backup: GET /api/docs/export-all zips every doc (md/docx),
de-dupes filenames, dated name; sidebar download links. TestExportAll.
- Smart typography input rules (curly quotes/em-dash/ellipsis), ASCII-only so
CJK is untouched.
- Duplicate doc, sidebar sort (Recent/Title/Longest), toolbar outline popover.
- English phonetic (chosen over pinyin for an English learner): ECDICT-built
phonetic.json.gz (46,579 words) + Result.Phonetic + WordCard IPA line;
scripts/build_phonetic.py (full build + --seed fallback).
- Selection bubble no longer blocks copy/paste: deferred to pointer-up and made
click-through except on its buttons.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
Two editor features that were in flight alongside the sound work:
- FontSize TipTap extension (rides on textStyle) with Small/Normal/Large/
Title presets in the toolbar; StatusBar + CSS support
- Image handling: internal/images handler, upload route + config, client
API, EditorCore wiring, and md/html/docx export support for images
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
Tier-1 voice-consistency pass: whole-document LLM review surfacing passages
that read tonally out of place (formal/over-polished/paraphrased-too-closely),
as honey-decorated `voice` flags with no correction (awareness-only).
- internal/llm/voice.go: RunVoice sends the whole document (no TruncateDoc),
MaxTokens 2048, 20s per-doc floor (VoiceInterval). Standalone voice prompt
in prompts.go (not bundled with the grammar checkpoint, per spec).
- internal/suggestions: POST /api/docs/:id/voice. replacePending is now
family-scoped (pendingScope) so grammar and voice never clobber each other's
pending flags; both passes return the unified pending set. check/voice share
one runPass helper. TestVoicePassCoexists covers both directions.
- Frontend: api.voiceDoc, useCheckpoint voicing/runVoice, honey "Check my
voice" toolbar pill, breathing honey dot in StatusBar.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
Backend internal/docs: chi sub-router (list/create/get/update/delete)
mounted at /api/docs, scoped to the local user. Create uses RETURNING;
update is a COALESCE partial-update so rename and full editor save share
one PUT. JSON 404/400 errors; handlers_test.go walks the lifecycle.
Frontend: api/client.ts, useAutoSave (1.5s debounce + saveNow flush
before doc switch), EditorCore (Tiptap StarterKit/Underline/TextAlign/
Placeholder/CharacterCount) + Toolbar, DocList/DocListItem, StatusBar,
and an App.tsx that orchestrates load/select/create/delete with
optimistic sidebar patching. content + content_text + word_count are
emitted together on every edit. .petal-prose styling (Lora body, Nunito
headings).
Verified: tsc clean, vite build, go build, full CRUD smoke test incl.
CJK title round-trip and SPA serve.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd