Commit Graph
17 Commits
Author SHA1 Message Date
nvrl 9363a0024d navigation: the list by name outside the diary, Ctrl-P goes to anything by its name, new things land beside what they belong to
The list is folders first and then by name in every space but the diary,
which stays a journal by day; a document's row elsewhere shows when it
was last edited. Ctrl-P is a jump by name across every space, served by
GET /api/jump: the last word is looked for in the name, the ones before
along the path. / is the one full-text search, and Tab on its line takes
it to every space and back. A card's notes are made in the folder being
browsed when that is in the card's space, and a missing [[link]]'s
document beside the one linking to it. o in a space with templates opens
the line as :new with them listed.
2026-10-22 17:39:24 +02:00
nvrl b1107013ee store: one workspace, made of parts
The Workspace class held every piece of client state in one 2500-line
file. It is now a root that composes nine parts, each in web/src/lib/state/:

- tree: spaces, folders, the list, search, marks, and what is done to nodes
- tiles: the tiles on screen, the focus trail, and the views among them
- drafts: document drafts and autosave, and text written in place
- cards: the board, the agenda, the card back, and the card verbs
- diary: today's entry, the calendar, stepping between days
- scratch: the scratchpad drawer and its ways out
- sheets: what floats over the tiles, and what each sheet lists
- vault: the vault status and unlocking
- prompts: the [y/N] question, the password box, Proton's check

The root keeps what belongs to no one part: the session, the status
line, guard, what has the focus, and the focused tile's open/draft/
editing. The keyboard layer still sees one `workspace`; call sites read
`workspace.cards.card`, `workspace.tree.nodes` and so on. Behaviour is
unchanged.
2026-10-22 16:14:38 +02:00
nvrl 7f8d625a8d commands: one grammar for !, merged commands, a settings sheet, two-level help
A `!` now means force or everything and nothing else (`:w!`, `:search!`,
`:export!`, `:logout!`). A command that did a second thing behind its bang
takes a word for it instead: `:space new|name|rm`, `:list name|rm`,
`:task [add]|edit`, `:upload seal`, `:import zip [/]`. `:card` while reading
a document makes a card about it, so `:card!` is gone.

Merged: `:export` downloads what has focus, a file as it is or a document as
markdown (`:download` folded in); `:share [off|new]` replaces `:unshare` and
`:link`, and the list's `s` and `y` give way to it and the info sheet;
`:noh` replaces `:clear`; `:vault [unlock|lock|passwd]` replaces `:unlock`,
`:lock` and `:passwd`; Esc in the list puts down what `m` picked up before it
closes the document, replacing `:unmark`.

The old spellings run as their new lines for one release through a table in
commands.ts; help and Tab leave them out, and the wiki lists them.

A settings sheet (`,` or `:settings`) holds the options, the vault, the
backup, the signed-in browsers, ssh keys and capture tokens. Each row runs
the command a line would. Bare `:set`, `:vault`, `:backup`, `:sessions`,
`:sshkey` and `:token` open it at their part.

`?` shows the keys and commands to start with, flagged in the keymap and the
command table; a second `?` (or `:help all`) shows all of them, and a filter
always searches all of them. Help rows are keyed by key and description, as
two contexts can share a label.
2026-10-22 15:35:36 +02:00
nvrl 5684614d0a tiles: the board, the agenda, the calendar and a card's back are tiles
The special workspace was a second layout beside the tiles, with its own
focus, its own Tab, Esc and q, and a returnTo flag to find the way back.
The views are now tile kinds instead: opened beside what is on screen,
walked with Alt-h/j/k/l and gt/gT, closed with q.

- Tile gets a kind: node, board, agenda, calendar or card. view,
  specialFocus, returnTo and the special context are gone.
- A trail of focused tiles: closing one goes back to the one before, so
  q on a card's notes or a calendar day returns to the view.
- A view is never replaced by what is opened from it; that opens beside.
- S tiles the board, agenda and calendar ahead of the documents, or puts
  every view away. :plan, with :special kept as an alias.
- The card sheet is a card tile beside the board, following its cursor;
  leaving it while writing the description saves what is written.
- Spaces remember their views; with a view focused, a space switch takes
  the views along instead of leaving copies behind.
- Card commands check what has the focus rather than the special view.
2026-10-22 10:18:50 +02:00
nvrl 0eabcb2333 keys: one table drives dispatch, help, footers, the rail and the wiki
keymap.ts lists every key with its context, action and help line.
actions.ts holds what each one does, typed against the table so a key
without an action, or an action without a key, does not compile.
modes.ts stacks the contexts (always > sheet > drawer > workspace >
writing > focused tile > special > global) and writes the two-key
pending logic once. App.svelte's 480-line onkeydown is now one call.

Help, the panel footers (a shared Keys component), the rail's keycaps
and Commands.md all read the table; the wiki gains the card and
scratchpad key tables.

One fix on the way: Ctrl-S in the editor no longer saves twice, which
could make the second save fail as "changed somewhere else".
2026-10-22 03:42:19 +02:00
nvrl 7f8a3816d3 fixes: what the audit turned up
- POST /api/diary/day finds a day's entry, or starts it at the root of the
  diary, by the server's clock. T, the calendar and a capture all use it, so
  they can no longer write two entries for one day: before, T counted days by
  the browser's midnight and wrote into whichever diary folder was last open.
- A Ctrl-P result opens beside the results, as a / result does, so n and N
  go on from it rather than finding no search.
- A card's description resolves its [[links]] the way a document does, and
  following one leaves the card for what it leads to.
- gf on the board opens a card's notes. Enter was documented for that, but
  Enter turns the card over.
- The pane header and the status line show where the open node is, rather
  than where the list is, so a node from another space shows its own path.
2026-10-22 03:10:49 +02:00
nvrl 176aad8c6f special: keys go to a tile, and Esc only ever leaves
Inside the special workspace the agenda and the calendar could only be
reached with Alt-h/j/k/l, which a desktop that binds Alt to its own windows
never lets through, and the same keys meant two things: t on the agenda put
the whole workspace away, t elsewhere went to it. Three esc buttons, one per
tile, all closed everything.

Now b, t and C only ever go to their tile, from anywhere. Tab and Shift-Tab
walk the tiles, as they walk the spaces elsewhere; l past the board's last
list goes on into the agenda, h in the agenda back to the board, j past its
end into the calendar. S toggles the workspace, and q and Esc leave it from
whichever tile — after leaving fullscreen first. The tile buttons are gone;
each tile's head shows its key instead, lit on the one with focus, and the
bar has a special pill beside the spaces.

A document opened from the workspace — a day of the calendar, an entry of
the agenda, today's entry, a card's notes — comes back to the tile it was
opened from on q.

The board tile shows the board of the space being browsed, or else the last
one shown, so coming from the diary, which has none, no longer leaves it
empty. Card and list actions follow the board on screen, not the browsed
space.
2026-10-21 15:53:24 +02:00
nvrl 73ac961751 special: the board, the agenda and the calendar in a workspace of their own
The board swapped out the tree, and the agenda and the calendar were
overlays over it, each with a key to open and a key to close. They are now
three tiles of one special workspace, as the desktop keeps its scratchpad:
the board on the left, the agenda over the calendar on the right.

S puts it up and away from anywhere. b, t and C go straight to their tile,
and put the workspace away when that tile already has focus. Alt-h/j/k/l
move the focus between the tiles, f gives the focused one the porthole,
and the tiles without focus keep their cursors, dimmed. A digit switches
space as everywhere, and the board follows; the board's head names every
space that has one. Enter on an agenda card goes to it on the board beside.
A space without a board says so in the board's tile instead of refusing.

The rail offers the three tiles as doors, so a phone, which shows one at a
time, can walk between them. The help, the README, the wiki and the
screenshots say how it works now.
2026-10-21 15:04:58 +02:00
nvrl 6673298cb2 boards: a card can come back once it is done
`:repeat weekly` gives a card a rule: daily, weekly, monthly, yearly, or
every +Nd, +Nw, +Nm, +Ny. Finishing it, by a move into the last list or by
the API's done, leaves a copy at the bottom of the inbox with the same
title, notes, document and rule, due on the next date. The finished card
gives its rule up in the same transaction, so reopening it and finishing it
again makes no second copy.

The next date is counted on the calendar in WORKSPACE_TIMEZONE, so noon
stays noon across a change of the clocks, and months are counted from the
old due date rather than step by step, so a card due on the 31st comes back
on the 31st wherever a month has one. A card finished late skips the dates
already past; one without a date counts from the moment it was finished.

A move and an edit answer with `again`, the copy, so the status line can
say when the card comes back. The board and the agenda show the rule as
`↻ weekly`, the rail has a button for it, and `:` in the agenda now opens
the line with the agenda kept up, so `:repeat` knows which card.

The rule travels in `.workspace.json` without a format bump: an older build
ignores the field and imports the card as one that does not repeat. An
import drops a rule it cannot read.
2026-10-21 00:02:42 +02:00
nvrl 8ffad6350f trash: a delete can be undone
`x`, `dd`, `:delete` and `:rmspace` no longer end anything. What they
delete is moved, whole, under one hidden root, and `u` puts the last of it
back where it was. `:trash` lists everything deleted, the last first:
Enter or `r` restores, `x` deletes one for good and `:trash purge` empties
it, each asking first. Something whose folder has gone since comes back to
the root of its space; something whose space is in the trash too waits for
the space. The daily sweep purges what has waited WORKSPACE_TRASH_DAYS (30),
and only then are its files deleted.

While it waits, a trashed node is out of the tree, the search, the agenda,
the mails, the SFTP mount, the export and the readable files/ view, and a
shared document answers 404 until it comes back with the same link. `rm`
over the mount trashes too; a rename onto a taken name still replaces what
was there, so editor saves do not fill the trash.
2026-10-20 18:15:22 +02:00
nvrl 6bf88e7ffd tree: several nodes picked up and moved at once
m now adds the row under the cursor to a set of marks and steps on, so
mmm picks up three; M takes the whole folder, Esc or :unmark puts it all
back. Marks stay while the list walks, so they can be gathered from
several folders. p, :mv and Shift+digit move the whole set.

With a pointer, Ctrl- or Cmd-click marks a row and Shift-click every row
from the cursor to it. Rows drag onto a folder row, a crumb or a space
pill; a marked row carries every marked node with it.

POST /api/nodes/move takes { ids, parent_id } and moves them all or
none: every node is checked before any moves, sealing into a sealed
folder happens before the one transaction that moves them, and two of a
name get slugs of their own. The single move goes the same way.
2026-10-20 11:13:52 +02:00
nvrl 2733ac1a3a ui: touch parity, saves that survive outages, edits that do not collide
PUT /api/nodes/{id} takes base_updated_at and answers 409 when the node
was saved since; the editor sends it, so a save from another tab, the
phone or the SFTP mount is no longer overwritten in silence. :w! and
:wq! now force the write.

An autosave the server could not take is kept and retried with backoff,
and at once on the online event; network failures say "the server
cannot be reached" rather than "Failed to fetch". At boot that is no
longer shown as a login screen. A session that expires mid-edit shows
the login with a note, and logging back in resumes the open draft.

Folder listings and the media list are read page by page, so more than
500 children are no longer cut off. Search results carry the space and
folder they sit in, and the overview's recent list includes files.
Embedding uploads report progress, like uploads into a folder.

On touch devices vim is off by default. Each row has an actions sheet
(rename, move, share, seal, delete), folders start with a .. row, and
the dock gains today's entry, upload, search all spaces, drop for a
marked node, help, and the board's list, reorder, rename and delete.
The agenda gets a done button per card and a button for today's entry.

Sharing a folder or a file is refused in the client. :mv .. in a search
moves up from the match's own folder. Files dropped outside the list or
editor no longer navigate the tab away. The public share view renders
/n/ links as plain text, and tells a network error from a dead link.
2026-10-20 05:53:34 +02:00
nvrl 9255d36b61 agenda, capture and finder: what needs doing comes to you
GET /api/agenda gathers unfinished cards from every board that are late,
due within a week, or in hand, plus whether the diary has today; the
reminder mail and the agenda share one diary check. t opens it (and it
opens itself once a day when something is late or due), T writes today's
entry, the bar counts late and due cards, Ctrl-P searches every space,
and a document o made that is left empty is removed on the way out.
2026-10-19 14:51:52 +02:00
nvrl e1c8e22ea5 board: one model — first list inbox, last list done
Space sends a card to the done list or back to the inbox instead of
ticking it in place. Enter on a card with no document starts one named
after it, and q comes back to the board on the same card. :card captures
into the inbox without leaving the current view (c anywhere), :due takes
fri, tm, +3d and the like, :name! renames a list, done cards older than a
week fold away behind z, and the board spells out its keys. The phone dock
gains send, done, due and notes doors.
2026-10-19 14:45:35 +02:00
nvrl ecfbab0eaa ui: share view in the shell, icon rail, phone polish
- shared view uses the bar, porthole and status band; outline gets its own
  window on wide screens; j/k, gg/G, Ctrl-d/u scroll with a vim-style ruler
- rail doors are line icons in groups with hover tooltips and keycaps
- phone: number-only space pills, no nested rims, icon dock, toast messages,
  back button and one-line meta in the document header
- keycaps (.kbd) wherever keys are shown, styled scrollbars in Chrome,
  outline tracks position on jumps, breakpoints unified at 767px
2026-10-17 17:27:59 +02:00
nvrl 9391b10af1 hyprland 2026-10-17 14:25:32 +02:00
nvrl 8a37ca5dfe redesign 2026-10-17 13:44:05 +02:00