From 95db6fdfdc6aad269e1e067ee8a4c5aeec2faca5 Mon Sep 17 00:00:00 2001 From: david raistrick <1108844+keen99@users.noreply.github.com> Date: Tue, 7 Jul 2026 14:31:04 -0400 Subject: [PATCH] Character section rollup: clickable title, count, persisted collapse Match campaigns rollup pattern. Title button toggles collapse (chevron left, like campaigns). Character count in header. Collapse state persisted to localStorage key ttrpg.charactersCollapsed. --- TODO.md | 13 ------------- src/App.js | 22 ++++++++++++++-------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/TODO.md b/TODO.md index 529c687..68d6594 100644 --- a/TODO.md +++ b/TODO.md @@ -50,19 +50,6 @@ lots of updates - `isActive = id => updatedParticipants.find(p => p.id === id && p.isActive)` - Returns participant obj (truthy) not boolean. Works by accident, fragile. -### BUG: select campaign during active combat = screen flicker, no action -- In active encounter, click different campaign → flicker, no nav, no end. -- Either block (toast: end encounter first) or auto-end current + switch. -- Decide UX before fix. - - -### FEAT: generic/non-5e rules mode -- Campaign/encounter ruleset toggle: `5e` vs `generic`. -- Generic mode turns off death saves/state machine. -- Generic mode allows negative HP. -- 5e mode rejects negative damage/heal and clamps HP at 0. - - ### FEAT: clarify "Is NPC" in add-participant - Ambiguous label. May expand work based on what NPC means here (ally? monster? diff --git a/src/App.js b/src/App.js index 63fbbf4..84ff2aa 100644 --- a/src/App.js +++ b/src/App.js @@ -5,7 +5,7 @@ import { PlusCircle, Users, Swords, Trash2, Eye, Edit3, Save, XCircle, ChevronsUpDown, UserCheck, UserX, HeartCrack, HeartPulse, Zap, EyeOff, ExternalLink, AlertTriangle, Play as PlayIcon, Pause as PauseIcon, SkipForward as SkipForwardIcon, - StopCircle as StopCircleIcon, Users2, Dices, ChevronUp, ChevronDown, ScrollText, + StopCircle as StopCircleIcon, Users2, Dices, ChevronDown, ScrollText, Maximize2, Minimize2, Moon, Coffee, Clock, ChevronRight, X, Undo2, Redo2, Crosshair } from 'lucide-react'; @@ -682,7 +682,14 @@ function CharacterManager({ campaignId, campaignCharacters }) { const [editingCharacter, setEditingCharacter] = useState(null); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [itemToDelete, setItemToDelete] = useState(null); - const [isOpen, setIsOpen] = useState(true); + const [isOpen, setIsOpen] = useState(() => { + try { return localStorage.getItem('ttrpg.charactersCollapsed') !== 'true'; } + catch { return true; } + }); + useEffect(() => { + try { localStorage.setItem('ttrpg.charactersCollapsed', String(!isOpen)); } + catch {} + }, [isOpen]); const handleAddCharacter = async () => { if (!db || !characterName.trim() || !campaignId) return; @@ -769,15 +776,14 @@ function CharacterManager({ campaignId, campaignCharacters }) { <>