Phase 9: homebrew content + packs

- Homebrew entity (monster/spell/item/feat/condition) — Dexie v6, repo, hook,
  cascade-deleted with campaign
- Homebrew editor page: per-kind fields + description, create/edit/delete
- Compendium merges campaign homebrew of the matching kind (HB badge, generic
  HomebrewDetail) with the same cross-links (add monster->combat, spell/item->character)
- Content packs: export/import homebrew as JSON (validated, ids reassigned)
- System extensibility documented via the existing RulesSystem registry seam
- Fix: card editors (homebrew/npc/quest/note) debounce-save the FULL snapshot, not
  partial patches — editing two fields fast no longer drops an edit

New homebrew e2e + cascade test coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-08 07:54:53 +02:00
parent 744e91f703
commit 7100ea8dd4
16 changed files with 383 additions and 28 deletions
+4 -2
View File
@@ -44,8 +44,10 @@ function Quests({ campaign }: { campaign: Campaign }) {
function QuestCard({ quest }: { quest: Quest }) {
const [q, setQ] = useState(quest);
const [newObj, setNewObj] = useState('');
const save = useDebouncedCallback((patch: Partial<Quest>) => void questsRepo.update(quest.id, patch), 350);
const update = (patch: Partial<Quest>) => { setQ((p) => ({ ...p, ...patch })); save(patch); };
const save = useDebouncedCallback((next: Quest) => void questsRepo.update(next.id, {
title: next.title, status: next.status, description: next.description, reward: next.reward, objectives: next.objectives,
}), 350);
const update = (patch: Partial<Quest>) => setQ((p) => { const next = { ...p, ...patch }; save(next); return next; });
const setObjective = (id: string, patch: Partial<Objective>) =>
update({ objectives: q.objectives.map((o) => (o.id === id ? { ...o, ...patch } : o)) });