111 lines
3.7 KiB
TypeScript

'use client'
import { useState } from 'react'
import Link from 'next/link'
import { usePathname, useSearchParams } from 'next/navigation'
import { cn } from '@/lib/utils'
import { StickyNote, Bell, Archive, Trash2, Tag, ChevronDown, ChevronUp } from 'lucide-react'
import { useLabels } from '@/context/LabelContext'
import { LabelManagementDialog } from './label-management-dialog'
import { LABEL_COLORS } from '@/lib/types'
export function Sidebar({ className }: { className?: string }) {
const pathname = usePathname()
const searchParams = useSearchParams()
const { labels, getLabelColor } = useLabels()
const [isLabelsExpanded, setIsLabelsExpanded] = useState(false)
const currentLabels = searchParams.get('labels')?.split(',').filter(Boolean) || []
const currentSearch = searchParams.get('search')
// Show first 5 labels by default, or all if expanded
const displayedLabels = isLabelsExpanded ? labels : labels.slice(0, 5)
const hasMoreLabels = labels.length > 5
const NavItem = ({ href, icon: Icon, label, active, onClick, iconColorClass }: any) => (
<Link
href={href}
onClick={onClick}
className={cn(
"flex items-center gap-3 px-4 py-3 rounded-r-full text-sm font-medium transition-colors mr-2",
active
? "bg-amber-100 text-amber-900 dark:bg-amber-900/30 dark:text-amber-100"
: "hover:bg-gray-100 dark:hover:bg-zinc-800 text-gray-700 dark:text-gray-300"
)}
>
<Icon className={cn("h-5 w-5", active && "fill-current", !active && iconColorClass)} />
<span className="truncate">{label}</span>
</Link>
)
return (
<aside className={cn("w-[280px] flex-col gap-1 py-2 overflow-y-auto hidden md:flex", className)}>
<NavItem
href="/"
icon={StickyNote}
label="Notes"
active={pathname === '/' && currentLabels.length === 0 && !currentSearch}
/>
<NavItem
href="/reminders"
icon={Bell}
label="Reminders"
active={pathname === '/reminders'}
/>
<div className="my-2 px-4 flex items-center justify-between group">
<span className="text-xs font-medium text-gray-500 uppercase tracking-wider">Labels</span>
<div className="opacity-0 group-hover:opacity-100 transition-opacity">
<LabelManagementDialog />
</div>
</div>
{displayedLabels.map(label => {
const colorName = getLabelColor(label.name)
const colorClass = LABEL_COLORS[colorName]?.icon
return (
<NavItem
key={label.id}
href={`/?labels=${encodeURIComponent(label.name)}`}
icon={Tag}
label={label.name}
active={currentLabels.includes(label.name)}
iconColorClass={colorClass}
/>
)
})}
{hasMoreLabels && (
<button
onClick={() => setIsLabelsExpanded(!isLabelsExpanded)}
className="flex items-center gap-3 px-4 py-3 rounded-r-full text-sm font-medium transition-colors mr-2 w-full hover:bg-gray-100 dark:hover:bg-zinc-800 text-gray-700 dark:text-gray-300"
>
{isLabelsExpanded ? (
<ChevronUp className="h-5 w-5" />
) : (
<ChevronDown className="h-5 w-5" />
)}
<span>{isLabelsExpanded ? 'Show less' : 'Show more'}</span>
</button>
)}
<div className="my-2 border-t border-gray-200 dark:border-zinc-800" />
<NavItem
href="/archive"
icon={Archive}
label="Archive"
active={pathname === '/archive'}
/>
<NavItem
href="/trash"
icon={Trash2}
label="Trash"
active={pathname === '/trash'}
/>
</aside>
)
}