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:
@@ -81,11 +81,11 @@ func (h *Handler) create(w http.ResponseWriter, r *http.Request) {
|
||||
var doc db.Document
|
||||
err := h.DB.QueryRow(
|
||||
`INSERT INTO documents (user_id) VALUES (?)
|
||||
RETURNING id, user_id, title, content, content_text, word_count, created_at, updated_at`,
|
||||
RETURNING id, user_id, title, content, content_text, tone, word_count, created_at, updated_at`,
|
||||
db.LocalUserID,
|
||||
).Scan(
|
||||
&doc.ID, &doc.UserID, &doc.Title, &doc.Content, &doc.ContentText,
|
||||
&doc.WordCount, &doc.CreatedAt, &doc.UpdatedAt,
|
||||
&doc.Tone, &doc.WordCount, &doc.CreatedAt, &doc.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
serverError(w, err)
|
||||
@@ -115,6 +115,7 @@ type updateRequest struct {
|
||||
Title *string `json:"title"`
|
||||
Content *string `json:"content"`
|
||||
ContentText *string `json:"content_text"`
|
||||
Tone *string `json:"tone"`
|
||||
WordCount *int `json:"word_count"`
|
||||
}
|
||||
|
||||
@@ -134,10 +135,11 @@ func (h *Handler) update(w http.ResponseWriter, r *http.Request) {
|
||||
SET title = COALESCE(?, title),
|
||||
content = COALESCE(?, content),
|
||||
content_text = COALESCE(?, content_text),
|
||||
tone = COALESCE(?, tone),
|
||||
word_count = COALESCE(?, word_count),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ? AND user_id = ?`,
|
||||
req.Title, req.Content, req.ContentText, req.WordCount, id, db.LocalUserID,
|
||||
req.Title, req.Content, req.ContentText, req.Tone, req.WordCount, id, db.LocalUserID,
|
||||
)
|
||||
if err != nil {
|
||||
serverError(w, err)
|
||||
@@ -177,13 +179,13 @@ func (h *Handler) delete(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *Handler) fetch(id string) (db.Document, error) {
|
||||
var doc db.Document
|
||||
err := h.DB.QueryRow(
|
||||
`SELECT id, user_id, title, content, content_text, word_count, created_at, updated_at
|
||||
`SELECT id, user_id, title, content, content_text, tone, word_count, created_at, updated_at
|
||||
FROM documents
|
||||
WHERE id = ? AND user_id = ?`,
|
||||
id, db.LocalUserID,
|
||||
).Scan(
|
||||
&doc.ID, &doc.UserID, &doc.Title, &doc.Content, &doc.ContentText,
|
||||
&doc.WordCount, &doc.CreatedAt, &doc.UpdatedAt,
|
||||
&doc.Tone, &doc.WordCount, &doc.CreatedAt, &doc.UpdatedAt,
|
||||
)
|
||||
return doc, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user