From 3ae6185f31e1e58311e0948e536e579a7c9f6834 Mon Sep 17 00:00:00 2001 From: ShadowDara <128976697+ShadowDara@users.noreply.github.com> Date: Mon, 8 Jun 2026 21:24:45 +0200 Subject: [PATCH] Reapply "added storage api" This reverts commit 27062aa8ec43d2cd5cb7dacf34950fd0017e34e6. --- CHANGELOG.md | 1 + docs/Storage.md | 81 +++++++++++++++++++++++++ packages/samengine/package.json | 3 +- packages/samengine/src/save.ts | 18 ++++++ packages/samengine/src/storage/index.ts | 79 ++++++++++++++++++++++++ 5 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 docs/Storage.md create mode 100644 packages/samengine/src/storage/index.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b939a9..603b557 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ - fixed a Bug where the wrong config was used - fixed a Bug when no Markdown Notes where added - Markdown notes are now removed correctly on Game Start +- added better Storage API ## Future samengine () (Probaly 1.9.1) diff --git a/docs/Storage.md b/docs/Storage.md new file mode 100644 index 0000000..744fa67 --- /dev/null +++ b/docs/Storage.md @@ -0,0 +1,81 @@ +# Storage + +Save String + +```ts +import { StorageLib } from "./storage"; + +StorageLib.set("name", "Max"); + +const name = StorageLib.get("name"); + +console.log(name); +// Max +``` + +Save Object + +```ts +StorageLib.set("user", { + id: 1, + name: "Max", + age: 25 +}); + +const user = StorageLib.get<{ + id: number; + name: string; + age: number; +}>("user"); + +console.log(user?.name); +// Max +``` + +Export + +```ts +const json = StorageLib.exportToJson(); + +const blob = new Blob([json], { + type: "application/json" +}); + +const url = URL.createObjectURL(blob); + +const a = document.createElement("a"); +a.href = url; +a.download = "storage-backup.json"; +a.click(); + +URL.revokeObjectURL(url); +``` + +Import + +```ts +const json = ` +{ + "name": "Lisa", + "age": 30 +} +`; + +StorageLib.importFromJson(json); +``` + +import from file + +```js +const input = document.querySelector("#file"); + +input?.addEventListener("change", async (e) => { + const file = (e.target as HTMLInputElement).files?.[0]; + + if (!file) return; + + const text = await file.text(); + + StorageLib.importFromJson(text); +}); +``` diff --git a/packages/samengine/package.json b/packages/samengine/package.json index ab1f019..069bacd 100644 --- a/packages/samengine/package.json +++ b/packages/samengine/package.json @@ -20,7 +20,8 @@ "./utils/csv": "./dist/utils/csv/index.js", "./build": "./dist/build/index.js", "./physics": "./dist/physics/index.js", - "./samegui": "./dist/samegui/index.js" + "./samegui": "./dist/samegui/index.js", + "./storage": "./dist/storage/index.js" }, "keywords": [ "game", diff --git a/packages/samengine/src/save.ts b/packages/samengine/src/save.ts index c116917..333d8eb 100644 --- a/packages/samengine/src/save.ts +++ b/packages/samengine/src/save.ts @@ -1,9 +1,18 @@ // Key Value Save +/** + * @deprecated Use samengine/storage instead + */ export type SaveData = Record; // Please rename the SaveKey +/** + * @deprecated Use samengine/storage instead + */ export let SAVE_KEY = "my_game_save"; +/** + * @deprecated Use samengine/storage instead + */ export function saveGame(data: SaveData): void { try { const json = JSON.stringify(data); @@ -14,6 +23,9 @@ export function saveGame(data: SaveData): void { } } +/** + * @deprecated Use samengine/storage instead + */ export function loadGame(): SaveData | null { try { const json = localStorage.getItem(SAVE_KEY); @@ -25,11 +37,17 @@ export function loadGame(): SaveData | null { } } +/** + * @deprecated Use samengine/storage instead + */ export function clearSave(): void { localStorage.removeItem(SAVE_KEY); console.log("Save cleared!"); } +/** + * @deprecated Use samengine/storage instead + */ export function exportSave(): void { try { const json = localStorage.getItem(SAVE_KEY); diff --git a/packages/samengine/src/storage/index.ts b/packages/samengine/src/storage/index.ts new file mode 100644 index 0000000..1c5005a --- /dev/null +++ b/packages/samengine/src/storage/index.ts @@ -0,0 +1,79 @@ +// Store Data in the Browser + +export type StoredValue = { + value: T; + expiresAt?: number; +}; + +export class StorageLib { + static set(key: string, value: T): void { + localStorage.setItem(key, JSON.stringify(value)); + } + + static get(key: string): T | null { + const item = localStorage.getItem(key); + + if (!item) { + return null; + } + + try { + return JSON.parse(item) as T; + } catch { + return null; + } + } + + static remove(key: string): void { + localStorage.removeItem(key); + } + + static clear(): void { + localStorage.clear(); + } + + static has(key: string): boolean { + return localStorage.getItem(key) !== null; + } + + /** + * Gesamten Storage als JSON exportieren + */ + static exportToJson(pretty = true): string { + const data: Record = {}; + + for (let i = 0; i < localStorage.length; i++) { + const key = localStorage.key(i); + + if (!key) continue; + + const value = localStorage.getItem(key); + + try { + data[key] = value ? JSON.parse(value) : null; + } catch { + data[key] = value; + } + } + + return JSON.stringify(data, null, pretty ? 2 : 0); + } + + /** + * JSON in den Storage importieren + */ + static importFromJson( + json: string, + overwrite = true + ): void { + const data = JSON.parse(json) as Record; + + for (const [key, value] of Object.entries(data)) { + if (!overwrite && localStorage.getItem(key) !== null) { + continue; + } + + localStorage.setItem(key, JSON.stringify(value)); + } + } +}