'use client'; import { useState } from 'react'; import { useFileTree, FileTree } from '@pierre/trees/react'; import { themeToTreeStyles } from '@pierre/trees'; import { SquareRegular } from '@fluentui/react-icons'; import { useCanvas } from '@/store/canvas'; import { useArtboards } from '@/hooks/useArtboards'; const T = { bg: '#111115', border: 'rgba(255,255,255,0.055)', item: 'rgba(255,255,255,0.42)', itemHov: 'rgba(255,255,255,0.72)', selBg: 'rgba(51,133,255,0.12)', selFg: 'rgba(255,255,255,0.88)', accent: '#3385FF', dim: 'rgba(255,255,255,0.22)', sep: 'rgba(255,255,255,0.04)', }; // Map the panel's dark theme into Trees' CSS custom properties const treeThemeStyles = themeToTreeStyles({ type: 'dark', bg: '#111115', fg: 'rgba(255,255,255,0.42)', colors: { 'editor.selectionBackground': 'rgba(51,133,255,0.14)', 'list.activeSelectionBackground': 'rgba(51,133,255,0.14)', 'list.inactiveSelectionBackground': 'rgba(51,133,255,0.08)', 'list.hoverBackground': 'rgba(255,255,255,0.04)', 'list.activeSelectionForeground': 'rgba(255,255,255,0.88)', 'editorIndentGuide.background': 'rgba(255,255,255,0.04)', }, }); export function ArtboardNavigator() { const { selectedArtboardId, selectArtboard, workspaceId, projectId } = useCanvas(); const { artboards, rawArtboards } = useArtboards(workspaceId ?? undefined, projectId ?? undefined); // Build file tree paths from artboard names (strip .tsx suffix if present, else use name as path) const filePaths = rawArtboards.length > 0 ? rawArtboards.map((ab) => `artboards/${ab.name}`) : ['artboards/(no artboards yet)']; const { model } = useFileTree({ paths: filePaths, initialExpansion: 2, density: 'compact', icons: 'minimal', }); return (
{/* ── Artboards ── */} Artboards
{artboards.map((ab) => { const sel = selectedArtboardId === ab.id; return ( selectArtboard(ab.id)} icon={ } label={ab.label} after={sel && } /> ); })}
{/* ── Files — @pierre/trees ── */} Files
{/* ── Graph stats ── */} Graph
); } /* ── Artboard row ─────────────────────────────────────────── */ function NavRow({ selected = false, onClick, icon, label, after, }: { selected?: boolean; onClick?: () => void; icon: React.ReactNode; label: string; after?: React.ReactNode; }) { const [hov, setHov] = useState(false); return (
setHov(true)} onMouseLeave={() => setHov(false)} style={{ display: 'flex', alignItems: 'center', gap: 7, padding: '6px 10px', borderRadius: 5, cursor: 'pointer', background: selected ? T.selBg : hov ? 'rgba(255,255,255,0.04)' : 'transparent', color: selected ? T.selFg : hov ? T.itemHov : T.item, fontSize: '0.75rem', letterSpacing: '-0.01em', fontWeight: selected ? 500 : 400, userSelect: 'none', marginBottom: 1, transition: 'background 0.1s, color 0.1s', }} > {icon} {label} {after}
); } /* ── Helpers ──────────────────────────────────────────────── */ function SectionLabel({ children }: { children: string }) { return (
{children}
); } function HSep() { return
; } function ActiveDot() { return ( ); } function GraphStat({ label, value, color }: { label: string; value: string; color: string }) { return (
{label} {value}
); }