Skip to content

Editor: show which file the deck is open as, and open one by dropping it - #162

Merged
nyblnet merged 1 commit into
mainfrom
file-identity-ux
Jul 31, 2026
Merged

Editor: show which file the deck is open as, and open one by dropping it#162
nyblnet merged 1 commit into
mainfrom
file-identity-ux

Conversation

@nyblnet

@nyblnet nyblnet commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Two changes to the same problem: a deck on screen never said which file ⌘S would write, and a deck that arrived from disk could not be written at all without re-picking it in a save dialog.

Name the file

The tab said <deck title> — Bento Slides. It now says <deck title> — <file name> once a file name is knowable, and a quiet chip sits beside the title input.

The two names drift apart constantly — rename a deck and the file on disk keeps its old name — and only one of them answers what does ⌘S overwrite? So the chip appears only when they differ. openedFileName() and fileBase() already existed for exactly this and were used by nothing in the UI.

The tooltip has three states, because two would lie:

situation ⌘S
handle held rewrites this file in place
API, no handle yet asks where to save, then rewrites that file
no API (Safari/Firefox/iOS) saves a copy

Open by drop

Dropping a .bento.html onto the editor loads it and — via DataTransferItem.getAsFileSystemHandle() — adopts a writable handle where the browser offers one.

This is the only route to in-place saving for a deck that arrived from disk. A file double-clicked in Finder opens on file:// with no handle, so every ⌘S re-runs the picker and asks the user to navigate to the file already in front of them. Elsewhere the deck still opens, read-only, and the toast says so.

The kernel gains adoptFileHandle(), deliberately not exposed on window.bento: silently redirecting where ⌘S writes is a user gesture, never a script's.

Guards, verified by dropping real files into a built shell

dropped result
valid deck opens; tab + chip name it
notes.txt ignored — existing paste/drop behaviour
fake.bento.html, no doc block "isn't a Bento document."
freshly built shell (empty block) "has no saved document yet"
encrypted (bento/enc) refused — the password gate lives in boot
any, with unsaved work confirms first

The empty-block case matters: a freshly built shell ships an empty #bento-doc because the starter deck is generated at runtime. Calling that "not a Bento document" would be false, so it gets its own message.

Two bugs found by testing, not by reading

The chip rendered …tml. I truncated from the right, reasoning that the end of a filename identifies it — but every Bento file ends in .bento.html, so that is precisely the part carrying no information. It shows the base name now. It also no longer shrinks: it had squeezed the deck title input to Bento S.

After a handle-less drop the chip showed the URL's filename — labelling the deck with a file it no longer came from. Name resolution is now handle → dropped name → URL.

Checks

tsc clean · shell-gate passes · 8 catalogs updated, packed.ts regenerated (715 strings), build-i18n --check passes · shell 662,149 B (+3,192, ~0.5%).

Not addressed here: Safari/Firefox/iOS still cannot write in place at all — that is structural, and noticeIfCannotWriteInPlace() already says so up front.

Two changes to the same problem — a deck on screen never said which file
⌘S would write, and a deck that arrived from disk could not be written at
all without re-picking it in a save dialog.

**Name the file.** The tab said '<deck title> — Bento Slides'; it now says
'<deck title> — <file name>' once a file name is knowable, and a quiet chip
sits beside the title input in the topbar. The two names drift apart
constantly — rename a deck and the file on disk keeps its old name — and
only one of them answers what ⌘S overwrites, so the chip appears only when
they differ. openedFileName()/fileBase() already existed for this and were
used by nothing in the UI.

The chip's tooltip has THREE states, because two would lie: with a handle
⌘S rewrites this file; with the API but no handle it asks first and then
rewrites that one; without the API it hands back a copy.

**Open by drop.** Dropping a .bento.html onto the editor loads it and, via
getAsFileSystemHandle(), adopts a WRITABLE handle where the browser offers
one (Chromium). This is the only route to in-place saving for a deck that
arrived from disk: a file double-clicked in Finder opens on file:// with no
handle, so every ⌘S re-runs the picker and asks the user to navigate to the
file already in front of them. Elsewhere it still opens, read-only, and says
so. kernel gains adoptFileHandle(), deliberately NOT exposed on window.bento
— silently redirecting where ⌘S writes is a user gesture, never a script's.

Guards, all verified by dropping real files into a built shell: a non-Bento
file keeps its existing paste/drop behaviour; a .bento.html with no document
block is refused with its own message, because a freshly built shell ships an
EMPTY block (the starter deck is generated at runtime) and calling that 'not
a Bento document' would be false; an encrypted deck is refused rather than
half-opened, since the password gate lives in boot; and unsaved work is
confirmed before being replaced.

Two bugs found and fixed by testing rather than reading. The chip first
truncated from the right and rendered '…tml' — every Bento file ends in
.bento.html, so the extension is the one part identifying nothing; it shows
the base name now, and no longer shrinks (it had squeezed the title input to
'Bento S'). And after a drop with no handle the chip kept showing the URL's
file name, labelling the deck with a file it no longer came from.

8 catalogs updated, packed.ts regenerated (715 strings). tsc, shell-gate and
the i18n check pass.
@nyblnet
nyblnet merged commit 939381b into main Jul 31, 2026
1 check passed
@nyblnet
nyblnet deleted the file-identity-ux branch July 31, 2026 21:28
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.

1 participant