Introduce a settings modal (opened from the kebab menu) with a rules edition selector for condition tooltip descriptions and a theme picker replacing the inline cycle button. About half the conditions have meaningful mechanical differences between editions. - Add description5e field to ConditionDefinition with 5e (2014) text - Add RulesEditionProvider context with localStorage persistence - Create SettingsModal with Conditions and Theme sections - Wire condition tooltips to edition-aware descriptions - Fix 6 inaccurate 5.5e condition descriptions - Update spec 003 with stories CC-3, CC-8 and FR-095–FR-102 Closes #12 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
53 lines
1.1 KiB
TypeScript
53 lines
1.1 KiB
TypeScript
import type { RulesEdition } from "@initiative/domain";
|
|
import { useCallback, useSyncExternalStore } from "react";
|
|
|
|
const STORAGE_KEY = "initiative:rules-edition";
|
|
|
|
const listeners = new Set<() => void>();
|
|
let currentEdition: RulesEdition = loadEdition();
|
|
|
|
function loadEdition(): RulesEdition {
|
|
try {
|
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
if (raw === "5e" || raw === "5.5e") return raw;
|
|
} catch {
|
|
// storage unavailable
|
|
}
|
|
return "5.5e";
|
|
}
|
|
|
|
function saveEdition(edition: RulesEdition): void {
|
|
try {
|
|
localStorage.setItem(STORAGE_KEY, edition);
|
|
} catch {
|
|
// quota exceeded or storage unavailable
|
|
}
|
|
}
|
|
|
|
function notifyAll(): void {
|
|
for (const listener of listeners) {
|
|
listener();
|
|
}
|
|
}
|
|
|
|
function subscribe(callback: () => void): () => void {
|
|
listeners.add(callback);
|
|
return () => listeners.delete(callback);
|
|
}
|
|
|
|
function getSnapshot(): RulesEdition {
|
|
return currentEdition;
|
|
}
|
|
|
|
export function useRulesEdition() {
|
|
const edition = useSyncExternalStore(subscribe, getSnapshot);
|
|
|
|
const setEdition = useCallback((next: RulesEdition) => {
|
|
currentEdition = next;
|
|
saveEdition(next);
|
|
notifyAll();
|
|
}, []);
|
|
|
|
return { edition, setEdition } as const;
|
|
}
|