Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
27b10e3
polish visual system and interaction surfaces
M3RCU3Y Aug 16, 2026
a00e250
add depth to landing backdrop
M3RCU3Y Aug 16, 2026
b5497d5
refine flow reader brand mark
M3RCU3Y Aug 16, 2026
2f6d8b5
improve reader mode switcher accessibility
M3RCU3Y Aug 16, 2026
f98d2db
make library cards clearer and keyboard friendly
M3RCU3Y Aug 16, 2026
15415aa
polish app metadata and typography loading
M3RCU3Y Aug 16, 2026
7e2843d
clean stale build config and align pwa shell
M3RCU3Y Aug 16, 2026
36361d6
add non-deploying branch ci
M3RCU3Y Aug 16, 2026
31a908e
document product polish audit and follow-up work
M3RCU3Y Aug 16, 2026
a67527f
replace idle backdrop with reading weather
M3RCU3Y Aug 16, 2026
ab5eb7d
add performant reading weather atmosphere
M3RCU3Y Aug 16, 2026
8517b6d
load reading weather visual layer
M3RCU3Y Aug 16, 2026
6c45e20
guard reading weather animation performance
M3RCU3Y Aug 16, 2026
394a3c4
simplify landing atmosphere to quiet current
M3RCU3Y Aug 17, 2026
887ca22
add quiet current visual system
M3RCU3Y Aug 17, 2026
732ff4f
switch landing visuals to quiet current
M3RCU3Y Aug 17, 2026
0001567
guard quiet current performance contract
M3RCU3Y Aug 17, 2026
87f5d85
remove superseded reading weather styles
M3RCU3Y Aug 17, 2026
3ca857d
Add temporary lockfile refresh workflow
M3RCU3Y Aug 17, 2026
e6e68cc
Modernize Flow Reader toolchain
M3RCU3Y Aug 17, 2026
9cd1a9c
Run Flow Reader CI on Node 24
M3RCU3Y Aug 17, 2026
66ae5e9
Add MIT license
M3RCU3Y Aug 17, 2026
87b868d
Document Node 24 and MIT license
M3RCU3Y Aug 17, 2026
4c30bbf
Regenerate Flow Reader lockfile from scratch
M3RCU3Y Aug 17, 2026
fc6b705
Commit regenerated Flow Reader lockfile
M3RCU3Y Aug 17, 2026
f35f701
Refresh Flow Reader dependency lockfile
github-actions[bot] Aug 17, 2026
7b1d531
Remove temporary lockfile refresh workflow
M3RCU3Y Aug 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: CI

on:
pull_request:
push:
branches-ignore: [main]

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm

- run: npm ci
- run: npm run check
- run: npm run build
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Brandon Deonarine

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ https://m3rcu3y.github.io/Flow-Reader/

## Run Locally

Prerequisites: Node.js
Prerequisite: Node.js 24 or newer.

```bash
npm install
Expand All @@ -44,10 +44,15 @@ Open the local URL printed by Vite (usually `http://localhost:3000`).

```bash
npm run check
npm run build
```

`npm run check` runs TypeScript (`tsc --noEmit`) and the Vitest suite. Production builds are handled by the GitHub Pages workflow on `main`.

## License

Flow Reader is licensed under the [MIT License](LICENSE).

## Notes
- The library, preferences, and themes use local browser storage.
- “Clear Data” removes Flow Reader data from this device.
Expand Down
113 changes: 113 additions & 0 deletions docs/UX_AUDIT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Flow Reader UX and Product Audit

This audit accompanies the `agent/flow-reader-product-polish` branch. It separates changes that are safe to land as product polish from larger architectural work that should be handled deliberately.

## What felt unreliable

Flow Reader already has a surprisingly broad feature set, but several details made the product feel less trustworthy than the underlying functionality deserved:

- The landing screen had weak visual hierarchy, so the primary action competed with demo, help, URL import, and file import controls.
- The library looked like a utility drawer rather than a durable reading workspace.
- Some interaction affordances were hover-first. Selecting a library entry relied on a clickable list item and the delete control was mostly hidden until hover.
- The reader mode switch looked polished but only partially implemented the expected keyboard tab pattern.
- Product styling used many local utility-class combinations without a compact surface vocabulary, which made related controls feel slightly inconsistent.
- The repository had deployment checks on `main`, but no equivalent non-deploying CI gate for feature branches.
- Build configuration still contained unused Gemini environment-variable plumbing even though the app does not use Gemini.

## Changes in this branch

### Product presentation

- Deepened the dark visual system with more deliberate surfaces, borders, elevation, and focus states.
- Reworked the idle backdrop into a subtle reading-space atmosphere using a grid, orbit, grain, and restrained warm light.
- Gave the landing experience stronger editorial hierarchy and a dedicated glass reading dock.
- Refined the Flow Reader mark while keeping the existing identity and warm accent.
- Improved mobile spacing and reduced-motion behavior.

### Library

- Converted reading selection into a real keyboard-focusable button instead of a clickable list item.
- Kept delete as an independent control with an explicit accessible label.
- Made deletion discoverable on touch devices instead of depending on hover.
- Clarified word counts, progress, source metadata, and previous-session information.

### Reader controls

- Added roving tab focus to the reader mode switch.
- Added Arrow Left, Arrow Right, Home, and End keyboard behavior.
- Unified the switch with the updated surface language.

### Reliability and build hygiene

- Added CI for pull requests and non-main branches. It runs `npm ci`, `npm run check`, and `npm run build` without deploying.
- Removed stale Gemini build-time definitions.
- Enabled PWA cleanup of outdated caches and immediate client claim behavior.
- Improved metadata and mobile app-shell hints in `index.html`.

## Recommended follow-up work

### Priority 0: Make first-load/offline behavior more self-contained

The app currently loads Tailwind's browser runtime, Google Fonts, and PDF.js from external CDNs. The PWA can cache those resources after they have loaded, but a fresh installation still depends on those networks.

Move Tailwind to the normal Vite/PostCSS build pipeline, bundle PDF.js through npm, and consider either self-hosting fonts or using a robust local fallback stack. This reduces first-load failure modes, makes the PWA claim more trustworthy, and removes runtime styling compilation.

### Priority 1: Split the two oversized orchestration components

`src/App.tsx` currently owns reader state, session state, mobile chrome visibility, global listeners, persistence coordination, sprint behavior, overlays, and layout. `src/components/TextInput.tsx` owns multiple import engines plus several UI flows.

Good extraction targets:

- `useReadingSession`
- `useReaderChrome`
- `useActiveBook`
- `useBionicHotspots`
- `useFileImport`
- `useUrlImport`
- `PdfPasswordDialog`
- `ImportProgress`
- `FullscreenEditor`

The goal is not abstraction for its own sake. The goal is to make individual user flows testable without loading the entire application shell.

### Priority 1: Clarify URL-import privacy

The local library is private to the device, but URL import intentionally sends the entered URL to a public text extractor. The existing disclosure is good, but the distinction should be even clearer because “local-first” can otherwise be interpreted as “nothing ever leaves this device.”

Recommended product wording should distinguish:

- pasted/file content: processed locally, except OCR dependencies already loaded by the app;
- URL import: the URL is sent to the extractor, then the resulting text is stored locally.

A “Paste locally instead” route should remain prominent whenever URL extraction fails.

### Priority 1: Add browser-level regression tests

The existing service tests are useful, but the riskiest behavior now lives in browser interactions: mode switching, resume prompts, Bionic scroll persistence, mobile drawers, import status, localStorage restoration, and keyboard shortcuts.

Add a small Playwright suite covering:

1. Paste text → start → play/pause → seek → exit → resume.
2. Switch RSVP / RSVP+ / Bionic and persist the mode.
3. Add/delete a library item with keyboard navigation.
4. Mobile drawer and landing layout at a narrow viewport.
5. URL-import blocked/fallback state using a mocked response.
6. PWA production build smoke test.

### Priority 2: Replace browser-native confirmation dialogs

`confirm()` is currently used for destructive data clearing and large-PDF continuation. App-native dialogs would feel more coherent, provide better explanation, and give more control over focus management.

### Priority 2: Improve long-library scalability

The localStorage model is reasonable for a personal reader, but importing many large documents will eventually make synchronous serialization and full-list rendering noticeable. A future storage migration to IndexedDB should be considered before adding cloud sync or very large libraries.

## Suggested sequence

1. Land this visual/accessibility/CI pass after branch checks are green.
2. Bundle runtime CDN dependencies.
3. Split `App.tsx` and `TextInput.tsx` along the flow boundaries above.
4. Add Playwright coverage while those boundaries are fresh.
5. Revisit storage only if the product is going to support genuinely large libraries or sync.

The reader engine itself does not need to be rewritten as part of this cleanup. The RSVP timing hook and service boundaries are already better isolated than the app shell, so the highest-return work is around orchestration, first-load reliability, accessibility, and product trust.
20 changes: 13 additions & 7 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<meta name="description" content="A local-first RSVP and Bionic Flow reader for articles, PDFs, documents, and notes." />
<meta name="theme-color" content="#0b0b0d" />
<meta name="color-scheme" content="dark" />
<meta name="application-name" content="Flow Reader" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<title>Flow Reader</title>
<!-- No leading slash so icons resolve correctly under a GitHub Pages base path -->
<link rel="icon" href="pwa-icon.svg" />
<link rel="apple-touch-icon" href="pwa-icon.svg" />
<!-- Google Fonts: Merriweather (Serif) and Inter (Sans-Serif) -->

<!-- Editorial heading + neutral UI typography. -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Merriweather:wght@300;400;700;900&family=Playfair+Display:wght@400;600;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Merriweather:wght@300;400;700;900&family=Playfair+Display:wght@400;600;700&display=swap" rel="stylesheet">

<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
Expand Down Expand Up @@ -45,9 +51,9 @@
window.pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
}
</script>
</head>
</head>
<body class="bg-app-bg text-text-primary font-sans antialiased overflow-x-hidden selection:bg-accent-red selection:text-text-primary">
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
Loading
Loading