Commit graph

20 commits

Author SHA1 Message Date
Chmouel Boudjnah
0a00ccb27b feat: Group multi-volume series into collapsible library stacks
Some checks are pending
CI / check (push) Waiting to run
CI / Lockfile change (push) Waiting to run
CI / Homebrew cask (push) Waiting to run
Extracted series metadata from EPUB files and remote sync providers to
fold multi-volume series into interactive stacks on the main shelf.
Added a dedicated series view so readers could browse ordered volumes
without cluttering the main library screen.

Signed-off-by: Chmouel Boudjnah <chmouel@chmouel.com>
2026-09-01 08:36:54 +02:00
Chmouel Boudjnah
060466cce9 feat: Add catalog browsing support for liseur-sync servers
Added catalog support for liseur-sync servers so readers can browse
remote folders, view book listings, and download files directly.
Adjusted the link storage to let multiple catalog editions resolve to
the same work without database conflicts.

Signed-off-by: Chmouel Boudjnah <chmouel@chmouel.com>
2026-09-01 07:47:37 +02:00
Chmouel Boudjnah
f5b1c7291e feat: bundle and apply Literata font for reader typography
* Bundled the Literata variable font files and exposed them through a new custom
Electron protocol to ensure consistent offline long-form reading typography.
* Configured the reader engine and CSS theme to default to the new font family
with proper ligatures and an increased default font size.
* Centered the library wordmark and book-count pill together beside the artwork
in the top bar.

Signed-off-by: Chmouel Boudjnah <chmouel@chmouel.com>
2026-08-13 05:42:00 +02:00
Chmouel Boudjnah
24bed63f8e fix: refine continue reading banner 2026-08-13 05:03:38 +02:00
Chmouel Boudjnah
353267401e
fix: reach the settings while a book is open
The panel was part of the library screen, and the library screen is
unmounted while you are reading. Ctrl+, went nowhere, and the only way
to change a setting was to leave the book first.

It belongs to the application shell, which is always there, so it now
opens over whichever screen is showing and closes back onto it. The
screens underneath stop reading the keyboard while it is up: an arrow
key meant for the panel was turning the page behind it.

Ctrl+F is now claimed by whichever screen is on, so it searches the
book while you are reading one instead of doing nothing; the menu item
says "Search" rather than "Search Library". The reader also stops
listening for it when it closes — the shelf's own listener was being
added again on every return from a book and never removed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-12 20:35:07 +02:00
Chmouel Boudjnah
09f57aa46e
chore: check more than formatting before code leaves the machine
The hooks ran `pnpm format:check` on push and nothing else, which let a
change that does not compile, does not lint or does not pass its tests
get all the way to CI before anyone heard about it.

Now there are two passes. Committing runs the checks that answer in a
couple of seconds — formatting, lint, and a guard against a test left
focused with `.only`, which is how a whole test file quietly stops
being a test file. Pushing runs those again, so a commit made with
--no-verify still has to face them, and adds the types and the unit
tests. That is the half of CI that needs neither the network nor a
build; what is left to fail on GitHub is `pnpm build` and the
end-to-end suite.

The configuration moves to the name pre-commit looks for by itself, so
installing it no longer needs flags, and it names both hook types it
wants. Run `pre-commit install` once more after pulling this.

While writing the lint hook: the renderer's ban on Node builtins was
documented but never enforced — only `electron` was. The restriction
now says so, and applies to the renderer and to shared code rather
than to everything with an exception list, which is what it always
meant.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-12 20:35:07 +02:00
Chmouel Boudjnah
29bfc84d24
feat: add an optional vim mode for the shelf and the reader
For people who already navigate everything else with hjkl. Off by
default, and switched on from Settings.

The shelf answers to hjkl with counts, 0/^/$ across a row, gg and G for
the ends, <C-d>/<C-u> by the half screen, / to search, f and s to walk
the filters and sorts, and Enter or o to open what is selected. In a
book: pages with hjkl, chapters with ]] and [[, 50% to jump halfway,
12G for the twelfth chapter, n and N between search matches, m to
bookmark, and q to come back to the shelf. ? shows the whole list
wherever you are.

It is strictly additive. Arrows, space, the page keys, F11, Enter and
the menu shortcuts behave the same whether it is on or off, because a
vim key is only claimed when it is bound and nothing else answers to
it. Escape still belongs to the application: it drops a half-typed
sequence if there is one, then closes what is open, then leaves the
book.

The grammar lives in one pure module that the screens, the key sheet
and the tests all read, so the keys cannot drift from their own
documentation.

Along the way: the Settings panel could not be closed with Escape once
focus had landed on one of its controls.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-12 20:35:07 +02:00
Chmouel Boudjnah
d560cf63ae
chore: Add pre-commit hook for automated code formatting
Added a pre-commit configuration file to run formatting checks before
every push and updated the development documentation with installation
instructions.
2026-08-12 17:54:57 +02:00
Chmouel Boudjnah
e4ceffe22f
style: Format codebase with Prettier
Applied Prettier code style formatting across various source, test, and
documentation files.

Signed-off-by: Chmouel Boudjnah <chmouel@chmouel.com>
2026-08-12 17:52:09 +02:00
Chmouel Boudjnah
f9c9ae70c3
docs: run the test windows on a screen nobody is using
The end-to-end tests open real application windows. On a machine
somebody is working at, they take the focus and the keyboard for the
length of the run, and a stray click lands wherever the mouse happens
to be. The instructions for avoiding that were in the developer notes
only, so agents, which are pointed at AGENTS.md, never saw them and
ran the tests over the top of whatever was on screen.

Add scripts/headless.sh, which starts a hidden desktop of its own,
runs the command inside it and shuts it down afterwards, and say in
AGENTS.md that this is how the tests are to be run.

The old written-out recipe also named a specific screen to use, which
was only ever right on the machine it was written on: the names are
handed out in whatever order, and the name it gave is usually the real
session, so following it did exactly the thing it set out to avoid.
The script asks the hidden desktop its name rather than guessing, and
clears the leftover address that otherwise lets a stray command
rearrange the windows of the person sitting there.
2026-08-12 17:51:53 +02:00
Chmouel Boudjnah
a50b3e2c55
docs: describe explicit navigation origins and immediate sync publishing
Updates ARCHITECTURE.md with the PositionOrigin contract, the
application-scoped worker position publisher, and the sync service's
signal-driven single-flight drain with monotonic queue versions.
Updates PERFORMANCE.md to note that page turns still never await the
position publish or the network, and that progress reaches a
configured server immediately rather than on the old 2s debounce.
2026-08-12 17:43:19 +02:00
Chmouel Boudjnah
5b100fc731
fix: tell the sync server which book is which
Nothing this app sent to a liseur-sync server was ever filed against the
right book, and on a good day nothing was filed at all. The request asking
the server to identify a book was the wrong shape, so the server rejected
every one of them without the app noticing. A book the server cannot name
cannot have its place saved, cannot collect the place left on the phone,
and cannot count towards the reading statistics.

Books are now described the way the phone describes them: the file's
fingerprint, the library server's own reference, the identifier printed in
the book, and the title and author reduced to a plain form the two apps
agree on. That last one has to be spelled identically on both sides or the
same book quietly becomes two, so the checks here are a translation of the
phone's own.

Each sync now also introduces a batch of unnamed books, most recently read
first, and asks each newly named one where it was left off. Without that
step a book only ever became known by being read on this computer, and
anything the phone had already recorded for it was passed over for good.
2026-08-12 16:43:24 +02:00
Chmouel Boudjnah
9708e72610
feat: share statistics with a server you already added
Servers added before the statistics screen existed hold only a
position-sync permission, and the server refuses reading history to it.
The only way to get the second permission was to remove the server and
add it back, which unlinks every book from it.

The settings row now offers to ask for it directly: type your password
once and the server grants the statistics permission on its own, leaving
the sync credential and every book link untouched.
2026-08-12 16:09:20 +02:00
Chmouel Boudjnah
6ce0f2239a
feat: show how much you have read, counting every device
Adds a reading statistics screen: total time read, books read from and
finished, a day streak, a chart of the past week, and a list of books by
time spent. It opens from the button beside the theme switch in the
library header.

The figures start with what this computer recorded, so the screen works
offline and with no server at all. When a liseur-sync server is
configured, the reading done on your phone and any other device is folded
in, exactly as the Android app does it: the server counts the same
sittings this computer already reported, so its figure replaces the local
one instead of being added to it.

Those statistics live behind a separate permission on the server, which a
sync token is refused. Signing in now asks for that second permission as
well. A server that declines still syncs your place in a book, and the
settings screen says the totals will stay on this computer.
2026-08-12 16:06:15 +02:00
Chmouel Boudjnah
f69f934635
docs: add project todo list and update instructions
Created a comprehensive tracking document for planned features and known
missing work by comparing the design specifications against the current
codebase. Updated the agent instructions to require checking this new
document before starting any new features.

Signed-off-by: Chmouel Boudjnah <chmouel@chmouel.com>
2026-08-12 15:46:03 +02:00
Chmouel Boudjnah
1c11f2ad20
docs: move design/architecture/performance docs under docs/
Keep only README.md, AGENTS.md and SECURITY.md at the root, where
tooling and GitHub expect to find them, and relocate the longer
reference docs alongside DEVELOPMENT.md. Updated cross-links accordingly.
2026-08-12 15:37:23 +02:00
Chmouel Boudjnah
780b28bf65
docs: retire the milestone roadmap now that it is finished
Every milestone in DESIGN.md's roadmap was done, so the phased-build
scaffolding (roadmap table, milestone rules, per-milestone labels
scattered across AGENTS.md, PERFORMANCE.md and ARCHITECTURE.md) no
longer describes anything in progress. Removed it and the reader-engine
ADR it referenced, leaving the docs as plain descriptions of what the
app is rather than a project-planning artifact.
2026-08-12 15:35:56 +02:00
Chmouel Boudjnah
07828857b3
docs: write down how the project treats its dependencies
SECURITY.md explains what is actually at risk here, why fourteen days is the
number, what the lockfile check is for, and how to report a vulnerability. It
also lists the measures deliberately not taken and why, so the argument is
not had twice.

Releases now carry build provenance alongside their checksums. The builds are
still unsigned, but anyone can check that the bytes they downloaded came out
of this workflow at this commit, which a checksum on its own cannot say.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-12 15:27:02 +02:00
Chmouel Boudjnah
d1c23fe932
docs: Move development instructions into dedicated guide
Extracted setup, test commands, and environment variable details from
README.md into a new docs/DEVELOPMENT.md file to clean up project
documentation.

Signed-off-by: Chmouel Boudjnah <chmouel@chmouel.com>
2026-08-12 10:55:35 +02:00
Chmouel Boudjnah
1611c660a2
feat: Implement EPUB reader, local SQLite storage, catalog sync
Added full support for importing, storing, reading, and synchronizing
EPUB books. Parsed book files in a background worker and persisted
library metadata in SQLite to handle large libraries without slowing
down the main interface. Created a custom column-based reader with
themes, typography controls, annotations, and text search. Added
background catalog sync and reading progress reconciliation for remote
servers to keep reading state consistent across devices.

Signed-off-by: Chmouel Boudjnah <chmouel@chmouel.com>
2026-08-12 08:29:31 +02:00