* feat(ui): add floating glowing dictation overlay Show a bottom-center non-focus overlay while recognition is LISTENING or PROCESSING so users get a clear visual cue beyond the tray icon. Optional GtkLayerShell on Wayland; plain always-on-top GTK fallback elsewhere. Configurable via ui.show_overlay (default on) and Settings. * fix(test): isolate dictation overlay tests from GTK pollution Overlay unit tests no longer construct real GTK windows or import tray_indicator, which was loading gi.repository early and breaking later tests that mock GI (single-instance and suspend GLib checks). * docs: add dictation overlay screenshots Capture the floating glowing orb in listening (green) and processing (amber) states for the PR and README screenshots section. * test(ui): raise dictation overlay coverage for Codecov patch gate Exercise GTK init, draw/animation, positioning, layer-shell fallbacks, tray overlay wiring, settings toggle, and config edge cases so patch coverage on the floating overlay clears the 80% Codecov target. * test(tray): call overlay helpers via unbound methods Avoid instance-level MagicMock shadowing of set_overlay_enabled under some import/mock orderings (seen on CI Python 3.10). * test(tray): inject explicit config mock for overlay helpers Assign a MagicMock config_manager on the instance so assertions do not depend on the constructor patch (which can leave a real ConfigManager under some Python versions / import orders). * refactor(ui): ponytail pass on dictation overlay Drop the hand-drawn mic glyph, simplify the Cairo clear/pulse path, reuse ConfigManager get_bool/set, tighten tray overlay helpers, and delete string-grep structural tests that proved nothing. * fix(ui): pin overlay to bottom strip and stop stealing focus Use a full-width bottom strip (layer-shell left/right/bottom anchors, or resize+move fallback) so the orb is bottom-center on Wayland. Map the window once and toggle opacity instead of hide/show so compositors do not re-activate it and yank focus out of the editor (which broke IBus inject). * fix(appimage): seed GtkLayerShell typelib for dictation overlay * fix(ui): address greptile findings on dictation overlay * fix(appimage): keep layer-shell typelib optional for direct builds
Vocalinux website
Marketing site for vocalinux.com, built with Next.js and deployed as a static export (GitHub Pages).
Product claims and design constraints: PRODUCT.md, DESIGN.md. Agent notes: AGENTS.md.
Development
npm install
npm run dev
Production build
npm install
npm run build
Static output is written to out/.
Local preview of the build
cd out
python3 -m http.server 3000
Open http://localhost:3000.
Scripts
| Script | Purpose |
|---|---|
npm run dev |
Dev server |
npm run build |
Production static export |
npm run deploy |
Build and prepare GitHub Pages (.nojekyll, CNAME) |
npm run lint |
ESLint |
npm run typecheck |
TypeScript |
Deployment
Push to main triggers the site workflow. Production host: vocalinux.com.
Manual path:
cd web
npm install
npm run deploy
That produces out/ with .nojekyll and a CNAME for vocalinux.com.
Layout
web/
├── src/
│ ├── app/ # Next.js app routes
│ ├── components/
│ │ ├── site-chrome.tsx
│ │ └── ui/ # Reusable UI components
│ ├── hooks/
│ └── lib/
├── public/ # Static assets and screenshots
├── out/ # Build output (generated)
└── package.json
Configuration notes
- Custom domain:
deployscript writesout/CNAME - Subdirectory deploy: set
basePathinnext.config.jsif needed - Family workbench UI: warm paper, system type, same language as VocaHQ (DESIGN.md)
Troubleshooting
| Symptom | Check |
|---|---|
| Module not found | npm install |
| Type errors | npm run typecheck |
| Lint errors | npm run lint |
| 404 on GitHub Pages | Ensure out/.nojekyll exists |
| Assets 404 | Confirm basePath matches deploy path |
License
Same as the main Vocalinux project (AGPL-3.0).