files: a node kind of their own, in the tree beside the notes

A file node points at one media row and owns it the way a document owns
what it embeds, so folder deletes, the media browser and exports keep
working. POST /api/nodes/{id}/files streams uploads into a folder;
imports turn non-markdown files into file nodes; exports put them at
their tree path. The browser previews images, video, audio and text,
offers the rest as a download, and takes files dropped on the list.

Migration 0010 widens the kind CHECK by editing the stored schema, as
SQLite documents for loosening a constraint: sqlx runs migrations in a
transaction, where foreign keys cannot be switched off for a rebuild.
This commit is contained in:
nvrl committed 2026-10-19 15:44:30 +02:00
1 parent 3d6944c860
commit 2103edc299
15 files changed
+808 -94

No files matched your search

+6 -4
View File
@@ -98,7 +98,8 @@ a:focus-visible { background: var(--light); color: var(--ink); text-decoration:
* A button rests as a hairline and a label. Hover lifts it a step and lights
* the label; only focus inverts — the NieR cursor, light fill and ink text.
*/
button {
/* `a.button` is a link that has to look like one: open, download. */
button, a.button {
font: inherit;
font-size: 11px;
letter-spacing: 0.12em;
@@ -114,9 +115,10 @@ button {
color var(--t-base) var(--ease-glide),
border-color var(--t-base) var(--ease-glide);
}
button:hover { background: var(--surface-alt); color: var(--light); border-color: var(--outline); }
button:active { transform: translateY(1px); }
button:focus-visible { background: var(--light); color: var(--ink); border-color: var(--light); outline: none; }
a.button { display: inline-flex; align-items: center; justify-content: center; text-decoration: none; }
:is(button, a.button):hover { background: var(--surface-alt); color: var(--light); border-color: var(--outline); }
:is(button, a.button):active { transform: translateY(1px); }
:is(button, a.button):focus-visible { background: var(--light); color: var(--ink); border-color: var(--light); outline: none; }
button:disabled { color: var(--muted); cursor: default; }
input, textarea {