11 Commits

Author SHA1 Message Date
a8f93582bf Read-aloud: voice picker + speed control, auto-avoids eSpeak
- ⚙ button opens a settings popover above the toolbar with:
  - Voice dropdown: lists all voices the browser exposes, with ☁
    suffix for remote/cloud voices vs local ones
  - Speed slider: 0.5x–2.0x in 0.1 steps, labelled live
- On first load, auto-selects the first English non-eSpeak voice
  (helps Linux/Firefox users who only have eSpeak installed by default
  and haven't yet set a preference)
- Voice URI and rate persist in localStorage (sw-tts-voice, sw-tts-rate)
- Voice and rate applied per-utterance via voiceURIRef / ttsRateRef
  so changes take effect on the next sentence without restarting

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 21:21:15 -04:00
c6d1554215 Typewriter mode, SVG alignment icons, highlight readability fix
Typewriter mode (⌨ toolbar button):
- Registers TipTap update/selectionUpdate listeners via editor.on()
- On each change, uses coordsAtPos + window.scrollBy to keep cursor
  at 50% of viewport height — instant, no scroll-lag
- Adds 50vh padding-bottom so the last line can reach screen centre
- Toggles .typewriter class on <html>; cleans up on unmount

Alignment buttons:
- Replaced L/C/R text labels with inline SVG stacked-line icons
  (left, centre, right, justify) — standard text-editor appearance
- Added Justify as a fourth option

Highlight readability:
- Added color: #111 !important to .editor-body .ProseMirror mark
  so highlighted text is always dark-on-light regardless of theme

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 21:00:14 -04:00
1d00d86709 Add read-aloud: reads story from cursor to end using Web Speech API
- 🔊 button at far-right of toolbar; toggles to ⏹ while reading
- Extracts plain text from cursor position to end of document via
  editor.state.doc.textBetween — works with cursor or selection
- Splits into sentence chunks to work around Chrome's ~15s utterance
  cutoff bug; each chunk's onend fires the next
- isReadingRef guards the closure so Stop cancels mid-sentence cleanly
- Gentle pulse animation on the active button (reading-pulse keyframe)
- No server required — uses built-in browser speechSynthesis

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 20:55:50 -04:00
48d3533bfc Prompt queue: pre-fetch 5, instant local fallback, emoji source icon
- Refill a queue of 5 AI prompts in the background on page load
- Track in-flight fetches with pendingFetches ref so we never over-request
- fetchPrompt() is now synchronous: pops from queue or instantly returns a
  shuffled built-in (LOCAL_PROMPTS, 12 entries, no-repeat cycling)
- Source badge replaced with a small emoji in the top-right corner of the
  popover: 🤖 for AI prompts, 📚 for built-ins
- Removed promptLoading state and spinner entirely

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 20:48:31 -04:00
37448be5a8 Add notes panel, font picker, sticky toolbar, and prompt improvements
- Notes: per-story rich-text notes panel (right drawer) with TipTap
  editor, image support, autosave, and full CRUD API
- Font picker: 15 Google Fonts selectable from a floating Aa button,
  persisted to localStorage via --font-body CSS variable
- Sticky toolbar: pulled formatting bar out of overflow:hidden wrapper
  so it sticks below the topbar while scrolling
- Prompts: 100 additional built-in prompts (120 total) in a shuffled
  no-repeat queue; pre-fetch on page load so the AI has time to respond;
  timeout raised to 45s; error logging + /api/prompts/test debug endpoint;
  source badge shows whether prompt came from AI or built-in list

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 20:21:26 -04:00
b7baf4fa15 Rename app to Grimoire, add book+crescent moon SVG icon
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 15:56:46 -04:00
88e4441222 Fix mobile topbar horizontal overflow
Wrap button labels in spans so the existing hide-on-mobile rule fires.
Hide all topbar text labels and save status on small screens, leaving
only icons. Add overflow-x: hidden to html as a safety net.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 15:48:41 -04:00
219fd87e5e Remove leftover pocketbase lib
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 12:11:41 -04:00
9afb1dd4c5 Switch from email to username, add password change and admin reset
- Login now uses username instead of email
- DB migration renames email -> username on existing databases
- Users can change their own password from the Stories page
- Admin can reset any user's password from the admin panel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 12:11:27 -04:00
18d238a602 Fix nginx upstream resolution by removing broken Docker DNS resolver
The resolver 127.0.0.11 directive caused ECONNREFUSED errors in this
network setup. Direct proxy_pass resolves server at startup which is
sufficient since depends_on ensures server is running first.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 11:57:02 -04:00
1f51504de9 Add story writer app with editor, auth, export, and polish features
- React + TipTap editor with formatting toolbar (bold, italic, underline,
  strikethrough, alignment, highlight, scene breaks)
- Custom image node view with resize and alignment controls; server-side
  WebP conversion via sharp
- Express + SQLite backend with JWT auth and admin user management
- Export to PDF, EPUB, and ODT
- Five themes (Midnight, Gothic Night, Enchanted Forest, Aged Manuscript,
  Neon Noir); Lora body font for readability
- Writing streak, daily word goal, milestones, and Ollama writing prompts
- Docker Compose setup for self-hosted deployment behind NPMplus

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 11:47:55 -04:00