diff --git a/src/App.js b/src/App.js index d1bfff8..debef6e 100644 --- a/src/App.js +++ b/src/App.js @@ -682,6 +682,22 @@ function CharacterManager({ campaignId, campaignCharacters }) { const [editingCharacter, setEditingCharacter] = useState(null); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [itemToDelete, setItemToDelete] = useState(null); + const [draggedCharId, setDraggedCharId] = useState(null); + + const handleCharDragStart = (e, id) => { setDraggedCharId(id); e.dataTransfer.effectAllowed = 'move'; }; + const handleCharDragOver = (e) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; }; + const handleCharDrop = async (e, targetId) => { + e.preventDefault(); + if (!campaignId || !draggedCharId || draggedCharId === targetId) { setDraggedCharId(null); return; } + const reordered = [...campaignCharacters]; + const fromIdx = reordered.findIndex(c => c.id === draggedCharId); + const toIdx = reordered.findIndex(c => c.id === targetId); + if (fromIdx === -1 || toIdx === -1) { setDraggedCharId(null); return; } + const [moved] = reordered.splice(fromIdx, 1); + reordered.splice(toIdx, 0, moved); + try { await storage.updateDoc(getPath.campaign(campaignId), { players: reordered }); } catch (err) {} + setDraggedCharId(null); + }; const [isOpen, setIsOpen] = useState(() => { try { return localStorage.getItem('ttrpg.charactersCollapsed') !== 'true'; } catch { return true; } @@ -841,7 +857,17 @@ function CharacterManager({ campaignId, campaignCharacters }) {