87 lines
3.4 KiB
TypeScript
87 lines
3.4 KiB
TypeScript
"use client"
|
|
|
|
import { cn } from "@/lib/utils"
|
|
import { Search, Heart, Clock, Star } from "lucide-react"
|
|
|
|
export type GameCategory = string
|
|
|
|
interface GamingSidebarProps {
|
|
title: string
|
|
subtitle?: string
|
|
activeCategory: GameCategory
|
|
onCategoryChange: (category: GameCategory) => void
|
|
categories: {
|
|
id: string
|
|
name: string
|
|
icon: any
|
|
subtitle?: string
|
|
hasChevron?: boolean
|
|
}[]
|
|
}
|
|
|
|
export function GamingSidebar({ title, subtitle, activeCategory, onCategoryChange, categories }: GamingSidebarProps) {
|
|
return (
|
|
<aside className="hidden h-full w-[280px] shrink-0 bg-brand-surface-light lg:block overflow-y-auto border-r border-border/40 scrollbar-hide">
|
|
{/* Sidebar Header */}
|
|
<div className="bg-brand-surface px-3 py-2 text-[12px] font-bold text-white uppercase flex items-center justify-between border-b border-white/10 h-12">
|
|
<div className="flex items-center gap-2">
|
|
<Star className="size-4 text-brand-primary" />
|
|
<div className="flex flex-col">
|
|
<span className="leading-tight">{title}</span>
|
|
{subtitle && <span className="text-[10px] text-white/40 font-normal lowercase">{subtitle}</span>}
|
|
</div>
|
|
</div>
|
|
<svg viewBox="0 0 24 24" className="size-3.5 fill-white/40"><path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/></svg>
|
|
</div>
|
|
|
|
<div className="flex flex-col gap-[1px]">
|
|
{categories.map((cat) => {
|
|
const Icon = cat.icon
|
|
const isActive = activeCategory === cat.id
|
|
|
|
return (
|
|
<button
|
|
key={cat.id}
|
|
onClick={() => onCategoryChange(cat.id)}
|
|
className={cn(
|
|
"w-full flex flex-col px-3 py-2 text-left transition-colors border-b border-border/5",
|
|
isActive
|
|
? "bg-brand-surface border-l-4 border-l-brand-primary"
|
|
: "bg-brand-surface-light hover:bg-brand-surface"
|
|
)}
|
|
>
|
|
<div className="flex items-center justify-between w-full">
|
|
<div className="flex items-center gap-3">
|
|
{typeof Icon === 'string' ? (
|
|
(Icon.startsWith('http') || Icon.startsWith('/')) ? (
|
|
<img src={Icon} alt={cat.name} className="w-5 h-5 object-contain opacity-80" />
|
|
) : (
|
|
<span className="size-4 flex items-center justify-center text-[14px]">{Icon}</span>
|
|
)
|
|
) : (
|
|
<Icon className={cn("size-4", isActive ? "text-brand-primary" : "text-white/60")} />
|
|
)}
|
|
<div className="flex flex-col">
|
|
<span className={cn(
|
|
"text-[12px] font-bold tracking-tight",
|
|
isActive ? "text-white" : "text-white/80"
|
|
)}>
|
|
{cat.name}
|
|
</span>
|
|
{cat.subtitle && (
|
|
<span className="text-[9px] text-white/40 font-medium">{cat.subtitle}</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
{cat.hasChevron && (
|
|
<svg viewBox="0 0 24 24" className="size-3.5 fill-white/40"><path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/></svg>
|
|
)}
|
|
</div>
|
|
</button>
|
|
)
|
|
})}
|
|
</div>
|
|
</aside>
|
|
)
|
|
}
|