-
Notifications
You must be signed in to change notification settings - Fork 0
Local Storage and JSON Import Export
The planner is server-less β no account, no cloud, no backend. Every project lives entirely in your browser's IndexedDB database, and you can export it as a portable JSON file at any time.
Feature line from the README: πΎ Local project storage + JSON import/export.
The browser opens a single IndexedDB database (mlp.db) with three
object stores:
| Store | Purpose |
|---|---|
projects |
One record per project (ProjectRecord) keyed by project id. |
thumbnails |
An optional thumbnail blob per project (rendered on the dashboard). |
blobs |
Large binary payloads such as background images, keyed bg:<projectId>:<imageId>. |
The repository wraps the database with a friendly typed API
(ProjectRepository):
-
listProjects()β list ofProjectSummary(id, name, surface count, material count, thumbnail). -
getProject(id)β migratedProjectornull. -
saveProject(project)β validates with the ZodProjectSchemaand persists. -
deleteProject(id)β removes the project, its thumbnail and everybg:<id>:blob in a single transaction. -
duplicateProject(id, newName)β deep clones a project with a fresh id and timestamps. -
putBlob/getBlob/deleteBlob/putThumbnail/getThumbnail.
You don't have to think about saving:
-
Autosave β a debounced subscription on the project store calls
repo.saveProject(...)every ~500 ms after the last edit. A toast is shown on failure; the editor toolbar displaysSaved HH:MM:SSorNot savedplus an unsaved-dot indicator. -
Manual save β
Ctrl+Sor Save now in the File menu triggers an immediate save throughuseSaveProject. The repo writes the sameProjectRecord, so manual and automatic saves are interchangeable. -
Schema validation β every save runs through
ProjectSchema.parse. An invalid project (e.g. produced by a future bug) is rejected before it can corrupt your database.
migrateProject (under src/storage/migrations.ts) brings older project
JSON or older IndexedDB records up to the current schemaVersion. This
runs:
- On
getProject(id)after reading from IndexedDB. - On
parseProjectFromJson(text)when importing.
That means you can open an old export, or move your data to a newer build of the app, and it just works.
From the File menu or Dashboard:
-
downloadProjectJson(project)callsexportProjectToJson(project)which serialises the wholeProjectwithJSON.stringify(project, null, 2). - The download is named
<slugified-name>-<last 6 of id>.mlp.json(for examplekitchen-floor-3f4a91.mlp.json). - A toast confirms the export, or surfaces the error message if the browser blocks the download.
Exports are plain JSON β they can be diffed, committed to git, or embedded in a backup workflow.
Two import surfaces:
- The dashboard top bar keeps the shared theme button behaviour: New project uses the accent hover state, while Import JSON keeps the neutral surface hover treatment.
- Dashboard β Import JSON β pops a file picker, parses, saves into IndexedDB and opens the new project.
- File menu β Import project JSONβ¦ β same workflow, but from inside an open project. The replacement is loaded into the editor and the hash route is updated.
Both routes use parseProjectFromJson:
-
JSON.parse(text)β raisesProjectImportErrorwith a clear message on invalid JSON. -
migrateProject(...)β applies migrations and Zod validation. If the file is malformed or from a future incompatible schema, aProjectImportErrordescribes exactly what went wrong.
Toasts on success / failure mirror the export workflow.
- IndexedDB wrapper β
src/storage/indexedDb.ts - Repository β
src/storage/projectRepository.ts - Autosave β
src/storage/autosave.ts - JSON import / export β
src/storage/jsonImportExport.ts - Migrations β
src/storage/migrations.ts - Manual save hook β
src/features/editor/useSaveProject.ts - Dashboard β
src/features/dashboard/DashboardPage.tsx
Documentation for the material-layout-planner project. Every feature in the application is documented here β see the contribution rules before opening a pull request.