import React, { useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { GripVertical } from 'lucide-react'; import { useDragDrop, useDragSource } from '../../contexts/DragDropContext'; import { useAuthStore } from '../../store/authStore'; import { useSidebarStore, SidebarItemConfig } from '../../store/sidebarStore'; import { useLuckyMixAvailable } from '../../hooks/useLuckyMixAvailable'; import { ALL_NAV_ITEMS } from '../../config/navItems'; import { applySidebarDropReorder } from '../../utils/sidebarNavReorder'; type DropTarget = { idx: number; before: boolean; section: 'library' | 'system' } | null; function SidebarGripHandle({ idx, section, label }: { idx: number; section: 'library' | 'system'; label: string }) { const { t } = useTranslation(); const { onMouseDown } = useDragSource(() => ({ data: JSON.stringify({ type: 'sidebar_reorder', index: idx, section }), label, })); return ( ); } export function SidebarCustomizer() { const { t } = useTranslation(); const { items, setItems, toggleItem } = useSidebarStore(); const { isDragging: isPsyDragging } = useDragDrop(); const containerRef = useRef(null); const [dropTarget, setDropTarget] = useState(null); const dropTargetRef = useRef(null); const itemsRef = useRef(items); itemsRef.current = items; const randomNavMode = useAuthStore(s => s.randomNavMode); const setRandomNavMode = useAuthStore(s => s.setRandomNavMode); const luckyMixBase = useLuckyMixAvailable(); const luckyMixAvailable = luckyMixBase && randomNavMode === 'separate'; const libraryItems = items.filter(cfg => { if (!ALL_NAV_ITEMS[cfg.id] || ALL_NAV_ITEMS[cfg.id].section !== 'library') return false; if (randomNavMode === 'hub' && (cfg.id === 'randomMix' || cfg.id === 'randomAlbums' || cfg.id === 'luckyMix')) return false; if (randomNavMode === 'separate' && cfg.id === 'randomPicker') return false; if (cfg.id === 'luckyMix' && !luckyMixAvailable) return false; return true; }); const systemItems = items.filter(cfg => ALL_NAV_ITEMS[cfg.id]?.section === 'system'); useEffect(() => { if (!isPsyDragging) { dropTargetRef.current = null; setDropTarget(null); } }, [isPsyDragging]); useEffect(() => { const el = containerRef.current; if (!el) return; const onPsyDrop = (e: Event) => { const detail = (e as CustomEvent).detail; if (!detail?.data) return; let parsed: { type?: string; index?: number; section?: string }; try { parsed = JSON.parse(detail.data); } catch { return; } if (parsed.type !== 'sidebar_reorder' || parsed.index == null || !parsed.section) return; const fromIdx = parsed.index; const fromSection = parsed.section as 'library' | 'system'; const target = dropTargetRef.current; dropTargetRef.current = null; setDropTarget(null); const next = applySidebarDropReorder(itemsRef.current, fromSection, fromIdx, target, randomNavMode); if (next) setItems(next); }; el.addEventListener('psy-drop', onPsyDrop); return () => el.removeEventListener('psy-drop', onPsyDrop); }, [libraryItems, systemItems, setItems, randomNavMode]); const handleMouseMove = (e: React.MouseEvent) => { if (!isPsyDragging || !containerRef.current) return; const rows = containerRef.current.querySelectorAll('[data-sidebar-idx]'); let target: DropTarget = null; for (const row of rows) { const rect = row.getBoundingClientRect(); const idx = Number(row.dataset.sidebarIdx); const section = row.dataset.sidebarSection as 'library' | 'system'; if (e.clientY < rect.top + rect.height / 2) { target = { idx, before: true, section }; break; } target = { idx, before: false, section }; } dropTargetRef.current = target; setDropTarget(target); }; const renderRow = (cfg: SidebarItemConfig, localIdx: number, section: 'library' | 'system') => { const meta = ALL_NAV_ITEMS[cfg.id]; if (!meta) return null; const Icon = meta.icon; const isBefore = isPsyDragging && dropTarget?.section === section && dropTarget.idx === localIdx && dropTarget.before; const isAfter = isPsyDragging && dropTarget?.section === section && dropTarget.idx === localIdx && !dropTarget.before; return (
{t(meta.labelKey)}
); }; return ( <>
{t('settings.randomNavSplitTitle')}
{t('settings.randomNavSplitDesc')}
{/* Library block */}
{t('sidebar.library')}
{libraryItems.map((cfg, i) => renderRow(cfg, i, 'library'))}
{/* System block */}
{t('sidebar.system')}
{systemItems.map((cfg, i) => renderRow(cfg, i, 'system'))}
{t('settings.sidebarFixed')}: {t('sidebar.nowPlaying')}, {t('sidebar.settings')}
); }