Whiteboard: Titel nachträglich umbenennbar (Doppelklick oder ✎-Button, in Liste und Topbar)

This commit is contained in:
2026-06-25 21:06:53 +02:00
parent c5407afd48
commit 267c149eec

View File

@@ -188,6 +188,8 @@ export default function Whiteboard({ toast, mobile }) {
const [current, setCurrent] = useState(null); // { id, title, role }
const [creating, setCreating] = useState(false);
const [newTitle, setNewTitle] = useState('');
const [editingId, setEditingId] = useState(null); // ID des gerade umbenannten Boards
const [editTitle, setEditTitle] = useState('');
// ── Canvas-State ──────────────────────────────────────────────────────────
const [elements, setElements] = useState([]);
@@ -224,6 +226,16 @@ export default function Whiteboard({ toast, mobile }) {
.finally(() => setLoading(false));
}, []);
const renameBoard = async (id, title) => {
if (!title?.trim()) return;
try {
await api(`/tools/whiteboard/${id}/title`, { method:'PATCH', body:{ title: title.trim() } });
setBoards(prev => prev.map(b => b.id === id ? { ...b, title: title.trim() } : b));
if (current?.id === id) setCurrent(prev => ({ ...prev, title: title.trim() }));
} catch(e) { toast(e.message, 'error'); }
finally { setEditingId(null); }
};
useEffect(() => { loadBoards(); }, [loadBoards]);
// Canvas rendern wenn sich Elemente oder Viewport ändern
@@ -560,16 +572,34 @@ export default function Whiteboard({ toast, mobile }) {
{boards.map(b => (
<div key={b.id} style={{ ...S.card, display:'flex', alignItems:'center', gap:12, marginBottom:8, cursor:'pointer' }}
onClick={() => openBoard(b)}>
onClick={() => { if (editingId !== b.id) openBoard(b); }}>
<div style={{ fontSize:24 }}>🖊</div>
<div style={{ flex:1, minWidth:0 }}>
<div style={{ color:'#fff', fontFamily:'monospace', fontSize:13, fontWeight:700 }}>{b.title}</div>
{editingId === b.id ? (
<input autoFocus value={editTitle}
onChange={e => setEditTitle(e.target.value)}
onKeyDown={e => { if (e.key==='Enter') renameBoard(b.id, editTitle); if (e.key==='Escape') setEditingId(null); }}
onBlur={() => renameBoard(b.id, editTitle)}
onClick={e => e.stopPropagation()}
style={{ ...S.inp, fontSize:12, fontWeight:700, padding:'3px 8px', width:'100%' }}
/>
) : (
<div style={{ color:'#fff', fontFamily:'monospace', fontSize:13, fontWeight:700 }}
onDoubleClick={e => { e.stopPropagation(); if (b.role==='owner'||b.role==='edit'){ setEditingId(b.id); setEditTitle(b.title); } }}>
{b.title}
</div>
)}
<div style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:10, marginTop:2 }}>
{b.role === 'owner' ? '👑 Eigenes' : b.role === 'edit' ? '✏ Bearbeiten' : '👁 Lesen'}
{b.owner_name && b.role !== 'owner' && ` · von ${b.owner_name}`}
{' · ' + new Date(b.updated_at).toLocaleDateString('de-DE', { day:'2-digit', month:'2-digit', year:'numeric' })}
</div>
</div>
{(b.role === 'owner' || b.role === 'edit') && (
<button onClick={e => { e.stopPropagation(); setEditingId(b.id); setEditTitle(b.title); }}
title="Umbenennen"
style={{ background:'transparent', border:'none', color:'rgba(255,255,255,0.2)', cursor:'pointer', fontSize:14, padding:'4px 6px' }}></button>
)}
{b.role === 'owner' && (
<button onClick={e => { e.stopPropagation(); if (confirm(`"${b.title}" löschen?`))
api(`/tools/whiteboard/${b.id}`, { method:'DELETE' }).then(loadBoards).catch(err => toast(err.message, 'error'));
@@ -609,11 +639,24 @@ export default function Whiteboard({ toast, mobile }) {
background:'rgba(0,0,0,0.6)', borderBottom:'1px solid rgba(255,255,255,0.08)', flexShrink:0, flexWrap:'wrap' }}>
<button onClick={closeBoard} style={{ background:'transparent', border:'none', color:'rgba(255,255,255,0.5)',
cursor:'pointer', fontSize:18, padding:'2px 6px', lineHeight:1 }}></button>
<span style={{ color:'#fff', fontFamily:'monospace', fontSize:13, fontWeight:700, flex:1, minWidth:0,
overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>
{editingId === current?.id ? (
<input autoFocus value={editTitle}
onChange={e => setEditTitle(e.target.value)}
onKeyDown={e => { if (e.key==='Enter') renameBoard(current.id, editTitle); if (e.key==='Escape') setEditingId(null); }}
onBlur={() => renameBoard(current.id, editTitle)}
style={{ ...S.inp, fontSize:13, fontWeight:700, flex:1, padding:'3px 8px' }}
/>
) : (
<span
onDoubleClick={() => { if (current?.role !== 'view'){ setEditingId(current.id); setEditTitle(current.title); } }}
title={current?.role !== 'view' ? 'Doppelklick zum Umbenennen' : ''}
style={{ color:'#fff', fontFamily:'monospace', fontSize:13, fontWeight:700, flex:1, minWidth:0,
overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap',
cursor: current?.role !== 'view' ? 'text' : 'default' }}>
{current?.title}
{current?.role === 'view' && <span style={{ color:'rgba(255,255,255,0.3)', fontSize:10, marginLeft:8 }}>👁 nur lesen</span>}
</span>
)}
{/* Aktive User */}
{collab.length > 0 && (