diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index bfde2bc..90ae400 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -1,12 +1,44 @@ -import { NavLink, useNavigate } from 'react-router-dom' -import { LayoutGrid, Users, Activity, LogOut } from 'lucide-react' +import { useState } from 'react' +import { NavLink, useNavigate, useLocation } from 'react-router-dom' +import { LayoutGrid, Users, Activity, LogOut, ChevronDown } from 'lucide-react' import { AppIcon } from './AppIcon' -import type { User } from '../types' +import type { User, App } from '../types' interface Props { user: User; activeSlug?: string } export function Sidebar({ user, activeSlug }: Props) { const navigate = useNavigate() + const location = useLocation() + + // Determine active app's category so its group auto-stays open + const routeSlug = location.pathname.startsWith('/app/') + ? location.pathname.split('/')[2] + : null + const activeApp = user.apps.find(a => a.slug === routeSlug) + const activeCat = activeApp?.category ?? null + + // Separate uncategorised from categorised + const uncategorised = user.apps.filter(a => !a.category) + const grouped = user.apps.reduce>((acc, app) => { + if (!app.category) return acc + if (!acc[app.category]) acc[app.category] = [] + acc[app.category].push(app) + return acc + }, {}) + const categoryNames = Object.keys(grouped).sort() + + // All categories open by default; track collapsed ones + const [collapsed, setCollapsed] = useState>(new Set()) + + function toggleCat(cat: string) { + // Never collapse the active category + if (cat === activeCat) return + setCollapsed(prev => { + const next = new Set(prev) + next.has(cat) ? next.delete(cat) : next.add(cat) + return next + }) + } async function logout() { await fetch('/api/auth/logout', { method: 'POST', credentials: 'include' }) @@ -30,39 +62,69 @@ export function Sidebar({ user, activeSlug }: Props) {