feat(state): localStorage player prefs for story and action display

This commit is contained in:
ginnoir
2026-06-11 18:52:39 -05:00
parent 9196c77e25
commit b88399ac14
2 changed files with 58 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { getPrefs, setPrefs } from '../prefs';
describe('prefs', () => {
beforeEach(() => {
vi.stubGlobal('localStorage', {
store: {} as Record<string, string>,
getItem(key: string) {
return this.store[key] ?? null;
},
setItem(key: string, value: string) {
this.store[key] = value;
},
});
});
it('returns defaults when localStorage empty', () => {
expect(getPrefs()).toEqual({ storyOpenMode: 'auto', actionDetailMode: 'inline' });
});
it('round-trips updated prefs', () => {
setPrefs({ storyOpenMode: 'manual', actionDetailMode: 'hover' });
expect(getPrefs().storyOpenMode).toBe('manual');
});
});
+33
View File
@@ -0,0 +1,33 @@
const PREFS_KEY = 'idlegame:prefs:v1';
export type StoryOpenMode = 'auto' | 'choices-only' | 'manual';
export type ActionDetailMode = 'inline' | 'hover' | 'info-button';
export interface GamePrefs {
storyOpenMode: StoryOpenMode;
actionDetailMode: ActionDetailMode;
}
const DEFAULTS: GamePrefs = {
storyOpenMode: 'auto',
actionDetailMode: 'inline',
};
export function getPrefs(): GamePrefs {
if (typeof localStorage === 'undefined') return { ...DEFAULTS };
try {
const raw = localStorage.getItem(PREFS_KEY);
if (!raw) return { ...DEFAULTS };
return { ...DEFAULTS, ...JSON.parse(raw) };
} catch {
return { ...DEFAULTS };
}
}
export function setPrefs(partial: Partial<GamePrefs>): GamePrefs {
const next = { ...getPrefs(), ...partial };
if (typeof localStorage !== 'undefined') {
localStorage.setItem(PREFS_KEY, JSON.stringify(next));
}
return next;
}