Schnellzugriff: Reihenfolge per Drag & Drop änderbar
This commit is contained in:
@@ -1408,6 +1408,8 @@ function QuickLinksSettings({ toast }) {
|
||||
const [showForm, setForm] = useState(false);
|
||||
const [form, setF] = useState({ title:'', url:'', icon:'🔗' });
|
||||
const [editId, setEditId] = useState(null);
|
||||
const dragRef = useRef(null);
|
||||
const touchRef = useRef({});
|
||||
const { confirm, ConfirmDialog } = useConfirm();
|
||||
|
||||
useEffect(() => { api('/dashboard/links').then(setLinks).catch(() => {}); }, []);
|
||||
@@ -1441,6 +1443,52 @@ function QuickLinksSettings({ toast }) {
|
||||
catch(e) { toast(e.message, 'error'); }
|
||||
};
|
||||
|
||||
const reorder = async (newLinks) => {
|
||||
setLinks(newLinks);
|
||||
try { await api('/dashboard/links-order', { method:'PUT', body:{ ids: newLinks.map(l=>l.id) } }); }
|
||||
catch(e) { toast(e.message,'error'); }
|
||||
};
|
||||
|
||||
// Desktop drag handlers
|
||||
const onDragStart = (e, id) => { dragRef.current = id; e.dataTransfer.effectAllowed = 'move'; };
|
||||
const onDragOver = (e, id) => {
|
||||
e.preventDefault();
|
||||
if (dragRef.current === id) return;
|
||||
const from = links.findIndex(l => l.id === dragRef.current);
|
||||
const to = links.findIndex(l => l.id === id);
|
||||
if (from < 0 || to < 0) return;
|
||||
const next = [...links]; next.splice(to, 0, next.splice(from, 1)[0]);
|
||||
setLinks(next);
|
||||
};
|
||||
const onDrop = () => reorder(links);
|
||||
|
||||
// Touch handlers (long press + drag)
|
||||
const onTouchStart = (e, id) => {
|
||||
touchRef.current = { id, startY: e.touches[0].clientY, timer: setTimeout(() => {
|
||||
touchRef.current.active = true;
|
||||
}, 300) };
|
||||
};
|
||||
const onTouchMove = (e) => {
|
||||
if (!touchRef.current.active) return;
|
||||
e.preventDefault();
|
||||
const y = e.touches[0].clientY;
|
||||
const els = document.elementsFromPoint(e.touches[0].clientX, y);
|
||||
const target = els.find(el => el.dataset?.linkId);
|
||||
if (!target) return;
|
||||
const targetId = parseInt(target.dataset.linkId);
|
||||
if (targetId === touchRef.current.id) return;
|
||||
const from = links.findIndex(l => l.id === touchRef.current.id);
|
||||
const to = links.findIndex(l => l.id === targetId);
|
||||
if (from < 0 || to < 0) return;
|
||||
const next = [...links]; next.splice(to, 0, next.splice(from, 1)[0]);
|
||||
setLinks(next);
|
||||
};
|
||||
const onTouchEnd = () => {
|
||||
clearTimeout(touchRef.current.timer);
|
||||
if (touchRef.current.active) reorder(links);
|
||||
touchRef.current = {};
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ConfirmDialog/>
|
||||
@@ -1448,8 +1496,19 @@ function QuickLinksSettings({ toast }) {
|
||||
{links.length > 0 && (
|
||||
<div style={{ marginBottom:12 }}>
|
||||
{links.map(l => (
|
||||
<div key={l.id} style={{ display:'flex', alignItems:'center', gap:10, padding:'8px 0',
|
||||
borderBottom:'1px solid rgba(255,255,255,0.05)' }}>
|
||||
<div key={l.id}
|
||||
data-link-id={l.id}
|
||||
draggable
|
||||
onDragStart={e => onDragStart(e, l.id)}
|
||||
onDragOver={e => onDragOver(e, l.id)}
|
||||
onDrop={onDrop}
|
||||
onTouchStart={e => onTouchStart(e, l.id)}
|
||||
onTouchMove={onTouchMove}
|
||||
onTouchEnd={onTouchEnd}
|
||||
style={{ display:'flex', alignItems:'center', gap:10, padding:'8px 0',
|
||||
borderBottom:'1px solid rgba(255,255,255,0.05)',
|
||||
cursor:'grab', userSelect:'none' }}>
|
||||
<span style={{ color:'rgba(255,255,255,0.2)', fontSize:14, flexShrink:0, cursor:'grab' }}>⠿</span>
|
||||
<span style={{ fontSize:18, width:24, textAlign:'center', flexShrink:0 }}>
|
||||
{l.icon && l.icon.startsWith('http')
|
||||
? <img src={l.icon} alt="" style={{width:18,height:18,objectFit:'contain'}} onError={e=>e.target.style.display='none'}/>
|
||||
|
||||
Reference in New Issue
Block a user