Skip to content

CON-11: archive a page, and find it again in the archive - #94

Merged
molgerz merged 2 commits into
mainfrom
feat/con-11-archive-page
Sep 16, 2026
Merged

molgerz merged 2 commits into
mainfrom
feat/con-11-archive-page

Conversation

@molgerz

@molgerz molgerz commented Sep 16, 2026

Copy link
Copy Markdown
Owner

Archiving takes a page out of the tree, the search and the space overview
without deleting anything, and the archive is a place you can walk into to
bring one back.

How it works

Nostr events are immutable, so archiving is not a state change but another
revision: a 1818 on top of the current head carrying an archived tag,
with the content and the placement travelling along unchanged. Restoring is
the same publish without the tag. Page.archived is read off the head, so
the tree, the search and the overview all get it for free, and the history
stays complete on both sides of the move.

The placement (31818) is deliberately left alone. It has no effect while a
page is out of the tree, and deleting it would make a restore land the page
wherever its title sorts to instead of where it was.

Subpages do not go with the parent — they move up to the top level. The
confirmation says so, counted, because it is the one thing people assume the
other way round.

What you can see

  • History — Archive this page, and on an archived page a callout with
    Bring the page back.
  • Sidebar — an Archive row under the page tree, with a count when
    there is something in it.
  • /s/:group/archive — what was archived, newest first, with author and
    date, and one button per row to bring it back.
  • Page and breadcrumbs — an archived page still answers on its link and
    says that it is archived; a trail stops at an archived parent.

Confirming

window.confirm is gone. ConfirmDialog wraps a native <dialog>, so the
top layer, the backdrop, the focus trap and Escape come from the platform.
The confirming button says the act rather than OK, and Cancel holds the
focus. jsdom ships HTMLDialogElement without implementing any of its
behaviour, hence the shim in src/test.

Notes

Gates

typecheck, lint, test (48 files / 468 tests) and build all pass.

Archiving a page is not a state you set on it — Nostr events are immutable,
so there is nothing to set. It is another revision on top of the current
head, carrying an `archived` tag, with the content and the placement
travelling along unchanged. Restoring publishes the same revision without
the tag. `Page.archived` is read off the head, so the tree, the search and
the breadcrumbs all honour it without being told, and the history stays
complete on both sides of the move: an archived page can be read, compared
and blamed exactly as before.

The placement (`31818`) is deliberately left alone. It has no effect while
a page is out of the tree, and deleting it would make a restore land the
page wherever its title sorts to rather than where it was.

Subpages do not go with the parent; they move up to the top level. That is
the one thing people assume the other way round, so the confirmation says
it, counted.

Confirming happens in the app, not in the browser. `ConfirmDialog` wraps a
native `<dialog>` — the top layer, the backdrop, the focus trap and Escape
come from the platform — and the confirming button says the act rather than
`OK`, with Cancel holding the focus. jsdom ships `HTMLDialogElement`
without implementing any of its behaviour, hence the shim in `src/test`.
Archiving without somewhere to look is a one-way door: the only route back
to a page was a link somebody still happened to have.

So the archive gets an address. A row under the page tree leads to
`/s/:group/archive`, with a count beside it when there is something in it,
and the view lists what was archived — newest first, ties broken by slug so
the order does not shuffle between renders — with the author, the date and
one button per row to bring a page back. The space overview links there
too, under its page list.

The route sits above `:slug` in the table, so `archive` is a route and not
a page that happens to be called that. A page whose slug normalises to one
of the app's own words is shadowed by it — `new` and `search` have had that
since they were added — and that is CON-50, not this branch.
@molgerz
molgerz force-pushed the feat/con-11-archive-page branch from c1125e2 to c76b660 Compare September 16, 2026 23:35
@molgerz
molgerz merged commit eb8f715 into main Sep 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants