Loading a folder now imports a COPY into a browser-local IndexedDB project with
its own /p/:slug URL (original disk files untouched): edits persist to IDB across
visits, and the project exports via Download .zip or per-file. Gated by
VITE_LOCAL_PROJECTS=idb (on for the demo; off keeps the File System Access
write-back flow), so it's configurable per deployment.
Modular, swappable project sources behind the shared ProjectSource interface,
each self-describing via a SourceDescriptor whose kind is shown verbatim in the
UI — "Local (this browser)", "Remote · read-only", "Remote · editable" — on the
home page, the project view, and inside the editor, so the user always knows
whether/how Save persists:
- remote → REST backend (remote-rw)
- static → CDN gallery (remote-ro), saves download
- local (new) → idbProjectStore, writable IDB store
A composite layers the local store over the configured remote/gallery source,
routing per slug so imported/saved projects and the gallery share one namespace.
New, dependency-free (matching sync-client's raw-IDB ethos):
- lib/idb-project-store.ts raw IndexedDB store + create/delete/rename/export
- lib/zip.ts store-only ZIP writer (verified via system unzip)
- lib/import-folder.ts FSA/webkitdirectory folder → in-memory bytes
- lib/project-source-shared.ts source descriptors + deterministic uuid
- components/SourceChip, components/LocalProjectsSection
Home lists local projects (open/export/rename/delete). Verified: typecheck,
project-source tests, prod build, and IDB key-range project isolation in-browser
(prefix-colliding slugs don't leak).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>