Editor: document tone, right-click word lookup, expanded stats
Four enhancements to make the editor fit real school usage:
- Per-document tone (academic/professional/casual/humorous/creative/
persuasive/general): new documents.tone column (migration 0002), threaded
through the docs API, a bilingual ToneSelect dropdown on the title row, and
injected into the grammar-checkpoint LLM prompt so advice fits the register.
The voice pass stays tone-agnostic.
- Right-click word lookup: a new offline `lexicon` package serves definitions
(Wordset, modern ESL-friendly glosses) and synonyms (WordNet synsets first,
then frequency+stopword-ranked Moby for breadth) from gzipped embedded data,
behind /api/word/{word} with light morphology. The WordCard popover shows the
definition and tappable synonym pills that swap the word in place.
- Expanded writing stats: clicking the word count opens a StatsPanel with page
count, sentences, paragraphs, reading time, average word length, word variety,
and Flesch-Kincaid reading level — all computed client-side.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
This commit is contained in:
@@ -14,6 +14,7 @@ export interface Document {
|
||||
title: string
|
||||
content: string // Tiptap JSON (stringified)
|
||||
content_text: string // flattened plain text
|
||||
tone: string // target writing tone; steers LLM advice
|
||||
word_count: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
@@ -25,9 +26,25 @@ export interface DocUpdate {
|
||||
title?: string
|
||||
content?: string
|
||||
content_text?: string
|
||||
tone?: string
|
||||
word_count?: number
|
||||
}
|
||||
|
||||
// One sense of a word from the offline dictionary.
|
||||
export interface WordMeaning {
|
||||
part_of_speech: string
|
||||
definition: string
|
||||
example?: string
|
||||
}
|
||||
|
||||
// The offline lookup for one word: a few definition senses and a list of
|
||||
// synonyms. Either list may be empty when the word isn't a headword.
|
||||
export interface WordInfo {
|
||||
word: string
|
||||
definitions: WordMeaning[]
|
||||
synonyms: string[]
|
||||
}
|
||||
|
||||
export type SuggestionType = 'grammar' | 'phrasing' | 'idiom' | 'clarity' | 'voice'
|
||||
|
||||
// A single LLM-proposed edit. `original` is the source of truth for placement —
|
||||
@@ -83,6 +100,9 @@ export const api = {
|
||||
dismissSuggestion: (id: string) =>
|
||||
req<void>(`/suggestions/${id}/dismiss`, { method: 'POST' }),
|
||||
|
||||
// Offline word lookup (definition + synonyms) for the right-click popover.
|
||||
lookupWord: (word: string) => req<WordInfo>(`/word/${encodeURIComponent(word)}`),
|
||||
|
||||
// Current deployed build id — changes whenever a new frontend ships. The
|
||||
// app polls this to offer a refresh. Bypasses any cache so the answer is live.
|
||||
version: () => req<{ version: string }>('/version', { cache: 'no-store' }),
|
||||
|
||||
Reference in New Issue
Block a user