feat(app): store settings in the local storage
This commit is contained in:
@@ -1,20 +1,57 @@
|
|||||||
|
import { z } from "zod/mini";
|
||||||
|
|
||||||
|
const STORAGE_ID = "app_settings";
|
||||||
|
|
||||||
|
const settingsSchema = z.object({
|
||||||
|
color: z.object({
|
||||||
|
col: z.number(),
|
||||||
|
row: z.number(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
type Settings = z.infer<typeof settingsSchema>;
|
||||||
|
|
||||||
|
const defaultSettings = (): Settings => ({
|
||||||
|
color: { col: 0, row: 0 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const loadSettings = (): Settings => {
|
||||||
|
const stored = localStorage.getItem(STORAGE_ID);
|
||||||
|
try {
|
||||||
|
const result = settingsSchema.safeParse(JSON.parse(stored ?? ""));
|
||||||
|
if (result.success) {
|
||||||
|
return result.data;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// JSON.parse failed
|
||||||
|
}
|
||||||
|
|
||||||
|
const settings = defaultSettings();
|
||||||
|
saveSettings(settings);
|
||||||
|
return settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveSettings = (settings: Settings) => {
|
||||||
|
localStorage.setItem(STORAGE_ID, JSON.stringify(settings));
|
||||||
|
};
|
||||||
|
|
||||||
export const useAppStore = defineStore("app", {
|
export const useAppStore = defineStore("app", {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
booted: false,
|
booted: false,
|
||||||
_color: { col: 0, row: 0 },
|
settings: loadSettings(),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
setColor(col: number, row: number) {
|
setColor(col: number, row: number) {
|
||||||
this._color = { col, row };
|
this.settings.color = { col, row };
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
color: (state) => ({
|
color: (state) => ({
|
||||||
col: state._color.col,
|
col: state.settings.color.col,
|
||||||
row: state._color.row,
|
row: state.settings.color.row,
|
||||||
hex: APP_COLORS[state._color.row]![state._color.col]!,
|
hex: APP_COLORS[state.settings.color.row]![state.settings.color.col]!,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,7 +19,8 @@
|
|||||||
"pinia": "3.0.4",
|
"pinia": "3.0.4",
|
||||||
"three": "^0.182.0",
|
"three": "^0.182.0",
|
||||||
"vue": "3.5.25",
|
"vue": "3.5.25",
|
||||||
"vue-router": "4.6.3"
|
"vue-router": "4.6.3",
|
||||||
|
"zod": "^4.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt/content": "3.8.2",
|
"@nuxt/content": "3.8.2",
|
||||||
@@ -34,7 +35,6 @@
|
|||||||
"eslint": "9.39.1",
|
"eslint": "9.39.1",
|
||||||
"nuxt": "4.2.1",
|
"nuxt": "4.2.1",
|
||||||
"prettier": "3.6.2",
|
"prettier": "3.6.2",
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.3"
|
||||||
"zod": "4.1.12"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
pnpm-lock.yaml
generated
22
pnpm-lock.yaml
generated
@@ -15,7 +15,7 @@ importers:
|
|||||||
version: 5.2.0(three@0.182.0)(vue@3.5.25(typescript@5.9.3))
|
version: 5.2.0(three@0.182.0)(vue@3.5.25(typescript@5.9.3))
|
||||||
"@tresjs/nuxt":
|
"@tresjs/nuxt":
|
||||||
specifier: ^5.1.2
|
specifier: ^5.1.2
|
||||||
version: 5.1.2(@babel/parser@7.28.5)(@nuxt/content@3.8.2(better-sqlite3@12.4.1)(magicast@0.5.1))(@rollup/pluginutils@5.3.0(rollup@4.53.3))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.4.1))(embla-carousel@8.6.0)(esbuild@0.27.1)(ioredis@5.8.2)(magicast@0.5.1)(three@0.182.0)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))(zod@4.1.12)
|
version: 5.1.2(@babel/parser@7.28.5)(@nuxt/content@3.8.2(better-sqlite3@12.4.1)(magicast@0.5.1))(@rollup/pluginutils@5.3.0(rollup@4.53.3))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.4.1))(embla-carousel@8.6.0)(esbuild@0.27.1)(ioredis@5.8.2)(magicast@0.5.1)(three@0.182.0)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))(zod@4.2.1)
|
||||||
gsap:
|
gsap:
|
||||||
specifier: 3.13.0
|
specifier: 3.13.0
|
||||||
version: 3.13.0
|
version: 3.13.0
|
||||||
@@ -31,6 +31,9 @@ importers:
|
|||||||
vue-router:
|
vue-router:
|
||||||
specifier: 4.6.3
|
specifier: 4.6.3
|
||||||
version: 4.6.3(vue@3.5.25(typescript@5.9.3))
|
version: 4.6.3(vue@3.5.25(typescript@5.9.3))
|
||||||
|
zod:
|
||||||
|
specifier: ^4.2.1
|
||||||
|
version: 4.2.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
"@nuxt/content":
|
"@nuxt/content":
|
||||||
specifier: 3.8.2
|
specifier: 3.8.2
|
||||||
@@ -71,9 +74,6 @@ importers:
|
|||||||
typescript:
|
typescript:
|
||||||
specifier: 5.9.3
|
specifier: 5.9.3
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
zod:
|
|
||||||
specifier: 4.1.12
|
|
||||||
version: 4.1.12
|
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
"@alloc/quick-lru@5.2.0":
|
"@alloc/quick-lru@5.2.0":
|
||||||
@@ -9623,10 +9623,10 @@ packages:
|
|||||||
integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==,
|
integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==,
|
||||||
}
|
}
|
||||||
|
|
||||||
zod@4.1.12:
|
zod@4.2.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==,
|
integrity: sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==,
|
||||||
}
|
}
|
||||||
|
|
||||||
zwitch@2.0.4:
|
zwitch@2.0.4:
|
||||||
@@ -10815,7 +10815,7 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- magicast
|
- magicast
|
||||||
|
|
||||||
"@nuxt/ui@4.2.1(@babel/parser@7.28.5)(@nuxt/content@3.8.2(better-sqlite3@12.4.1)(magicast@0.5.1))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.4.1))(embla-carousel@8.6.0)(ioredis@5.8.2)(magicast@0.5.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))(zod@4.1.12)":
|
"@nuxt/ui@4.2.1(@babel/parser@7.28.5)(@nuxt/content@3.8.2(better-sqlite3@12.4.1)(magicast@0.5.1))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.4.1))(embla-carousel@8.6.0)(ioredis@5.8.2)(magicast@0.5.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))(zod@4.2.1)":
|
||||||
dependencies:
|
dependencies:
|
||||||
"@iconify/vue": 5.0.0(vue@3.5.25(typescript@5.9.3))
|
"@iconify/vue": 5.0.0(vue@3.5.25(typescript@5.9.3))
|
||||||
"@internationalized/date": 3.10.0
|
"@internationalized/date": 3.10.0
|
||||||
@@ -10866,7 +10866,7 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
"@nuxt/content": 3.8.2(better-sqlite3@12.4.1)(magicast@0.5.1)
|
"@nuxt/content": 3.8.2(better-sqlite3@12.4.1)(magicast@0.5.1)
|
||||||
vue-router: 4.6.3(vue@3.5.25(typescript@5.9.3))
|
vue-router: 4.6.3(vue@3.5.25(typescript@5.9.3))
|
||||||
zod: 4.1.12
|
zod: 4.2.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- "@azure/app-configuration"
|
- "@azure/app-configuration"
|
||||||
- "@azure/cosmos"
|
- "@azure/cosmos"
|
||||||
@@ -11737,10 +11737,10 @@ snapshots:
|
|||||||
three: 0.182.0
|
three: 0.182.0
|
||||||
vue: 3.5.25(typescript@5.9.3)
|
vue: 3.5.25(typescript@5.9.3)
|
||||||
|
|
||||||
"@tresjs/nuxt@5.1.2(@babel/parser@7.28.5)(@nuxt/content@3.8.2(better-sqlite3@12.4.1)(magicast@0.5.1))(@rollup/pluginutils@5.3.0(rollup@4.53.3))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.4.1))(embla-carousel@8.6.0)(esbuild@0.27.1)(ioredis@5.8.2)(magicast@0.5.1)(three@0.182.0)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))(zod@4.1.12)":
|
"@tresjs/nuxt@5.1.2(@babel/parser@7.28.5)(@nuxt/content@3.8.2(better-sqlite3@12.4.1)(magicast@0.5.1))(@rollup/pluginutils@5.3.0(rollup@4.53.3))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.4.1))(embla-carousel@8.6.0)(esbuild@0.27.1)(ioredis@5.8.2)(magicast@0.5.1)(three@0.182.0)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))(zod@4.2.1)":
|
||||||
dependencies:
|
dependencies:
|
||||||
"@nuxt/kit": 4.1.2(magicast@0.5.1)
|
"@nuxt/kit": 4.1.2(magicast@0.5.1)
|
||||||
"@nuxt/ui": 4.2.1(@babel/parser@7.28.5)(@nuxt/content@3.8.2(better-sqlite3@12.4.1)(magicast@0.5.1))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.4.1))(embla-carousel@8.6.0)(ioredis@5.8.2)(magicast@0.5.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))(zod@4.1.12)
|
"@nuxt/ui": 4.2.1(@babel/parser@7.28.5)(@nuxt/content@3.8.2(better-sqlite3@12.4.1)(magicast@0.5.1))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.4.1))(embla-carousel@8.6.0)(ioredis@5.8.2)(magicast@0.5.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))(zod@4.2.1)
|
||||||
"@tresjs/core": 5.2.0(three@0.182.0)(vue@3.5.25(typescript@5.9.3))
|
"@tresjs/core": 5.2.0(three@0.182.0)(vue@3.5.25(typescript@5.9.3))
|
||||||
defu: 6.1.4
|
defu: 6.1.4
|
||||||
mlly: 1.8.0
|
mlly: 1.8.0
|
||||||
@@ -16378,6 +16378,6 @@ snapshots:
|
|||||||
|
|
||||||
zod@3.25.76: {}
|
zod@3.25.76: {}
|
||||||
|
|
||||||
zod@4.1.12: {}
|
zod@4.2.1: {}
|
||||||
|
|
||||||
zwitch@2.0.4: {}
|
zwitch@2.0.4: {}
|
||||||
|
|||||||
Reference in New Issue
Block a user