feat: add shadcn sidebar to dashboard with navigation

Integrate shadcn sidebar component into dashboard layout:
- Create new dashboard/layout.tsx with SidebarProvider and responsive design
- Add AppSidebar component with navigation items (Dashboard, Settings, Admin)
- Implement responsive sidebar (permanent on desktop, drawer on mobile)
- Add Settings page with user profile information
- Update dashboard page to remove old header and integrate with new layout
- Configure Tailwind CSS colors for sidebar theming
- Add components.json for shadcn configuration

Features:
- Desktop sidebar is permanent and collapsible
- Mobile sidebar opens as overlay/drawer
- Active route highlighting in navigation
- User profile display with email and role
- Logout button in sidebar footer
- Conditional Admin link (only for admin users)
- Settings page showing account information

Files created:
- src/components/ui/sidebar.tsx (shadcn sidebar primitives)
- src/components/app-sidebar.tsx (main sidebar component)
- src/app/dashboard/layout.tsx (layout wrapper)
- src/app/dashboard/settings/page.tsx (settings page)
- components.json (shadcn configuration)

Files modified:
- tailwind.config.ts (added sidebar color scheme)
- src/app/globals.css (added sidebar CSS variables)
- src/app/dashboard/page.tsx (refactored to work with layout)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
XPS\Micro 2026-02-01 23:13:03 +01:00
parent 92820c251c
commit 234156feed
8 changed files with 838 additions and 131 deletions

11
frontend/components.json Normal file
View File

@ -0,0 +1,11 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": false,
"tsx": true,
"baseColor": "slate",
"aliases": {
"components": "./src/components",
"utils": "./src/lib/utils"
}
}

View File

@ -0,0 +1,27 @@
'use client'
import { SidebarProvider, SidebarInset, SidebarTrigger } from '@/components/ui/sidebar'
import { AppSidebar } from '@/components/app-sidebar'
import { Separator } from '@/components/ui/separator'
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<SidebarProvider>
<AppSidebar />
<SidebarInset>
<header className="flex h-16 shrink-0 items-center gap-2 border-b px-4">
<SidebarTrigger className="-ml-1" />
<Separator orientation="vertical" className="mr-2 h-4" />
<h1 className="text-xl font-semibold">Dashboard</h1>
</header>
<main className="flex flex-1 flex-col gap-4 p-4">
{children}
</main>
</SidebarInset>
</SidebarProvider>
)
}

View File

@ -19,12 +19,8 @@ import {
Play,
CheckCircle,
AlertCircle,
LogOut,
Shield,
Container as ContainerIcon,
} from "lucide-react";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import Link from "next/link";
export default function DashboardPage() {
const router = useRouter();
@ -111,11 +107,6 @@ export default function DashboardPage() {
}
};
const handleLogout = async () => {
await logout();
router.push("/login");
};
if (authLoading || !user) {
return (
<div className="flex min-h-screen items-center justify-center">
@ -125,49 +116,9 @@ export default function DashboardPage() {
}
return (
<div className="min-h-screen bg-muted/50">
{/* Header */}
<header className="border-b bg-background">
<div className="container mx-auto flex h-16 items-center justify-between px-4">
<div className="flex items-center gap-2">
<ContainerIcon className="h-6 w-6 text-primary" />
<span className="text-lg font-semibold">Container Spawner</span>
</div>
<div className="flex items-center gap-4">
{/* Admin-Link */}
{user.is_admin && (
<Link href="/admin">
<Button variant="outline" size="sm">
<Shield className="mr-2 h-4 w-4" />
Admin
</Button>
</Link>
)}
<div className="flex items-center gap-2">
<Avatar className="h-8 w-8">
<AvatarFallback className="text-xs">
{user.email.slice(0, 2).toUpperCase()}
</AvatarFallback>
</Avatar>
<span className="text-sm font-medium">{user.email}</span>
{user.is_admin && (
<Badge variant="secondary" className="text-xs">
Admin
</Badge>
)}
</div>
<Button variant="ghost" size="sm" onClick={handleLogout}>
<LogOut className="mr-2 h-4 w-4" />
Abmelden
</Button>
</div>
</div>
</header>
{/* Main Content */}
<main className="container mx-auto px-4 py-8">
<div className="mb-8">
<h1 className="text-3xl font-bold">Dashboard</h1>
<>
<div className="mb-6">
<h2 className="text-2xl font-bold">Deine Container</h2>
<p className="text-muted-foreground">
Verwalte deine Development- und Production-Container
</p>
@ -254,7 +205,6 @@ export default function DashboardPage() {
))}
</div>
)}
</main>
</div>
</>
);
}

View File

@ -0,0 +1,76 @@
'use client'
import { useAuth } from '@/hooks/use-auth'
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
export default function SettingsPage() {
const { user } = useAuth()
return (
<>
<div className="mb-6">
<h2 className="text-2xl font-bold">Einstellungen</h2>
<p className="text-muted-foreground">
Verwalte deine Account-Einstellungen
</p>
</div>
<div className="grid gap-6">
<Card>
<CardHeader>
<CardTitle>Profil</CardTitle>
<CardDescription>Deine Account-Informationen</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div>
<span className="text-sm font-medium text-muted-foreground">Email</span>
<p className="text-base font-semibold">{user?.email}</p>
</div>
<div>
<span className="text-sm font-medium text-muted-foreground">Slug</span>
<p className="text-base font-semibold">{user?.slug}</p>
</div>
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-muted-foreground">Status</span>
<Badge variant={user?.state === 'verified' ? 'default' : 'secondary'}>
{user?.state === 'verified' ? 'Verifiziert' : user?.state === 'active' ? 'Aktiv' : 'Registriert'}
</Badge>
</div>
{user?.is_admin && (
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-muted-foreground">Rolle</span>
<Badge variant="default">Administrator</Badge>
</div>
)}
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Account-Info</CardTitle>
<CardDescription>Zusätzliche Informationen</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{user?.created_at && (
<div>
<span className="text-sm font-medium text-muted-foreground">Erstellt am</span>
<p className="text-base font-semibold">
{new Date(user.created_at).toLocaleString('de-DE')}
</p>
</div>
)}
{user?.last_used && (
<div>
<span className="text-sm font-medium text-muted-foreground">Zuletzt verwendet</span>
<p className="text-base font-semibold">
{new Date(user.last_used).toLocaleString('de-DE')}
</p>
</div>
)}
</CardContent>
</Card>
</div>
</>
)
}

View File

@ -23,6 +23,14 @@
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--sidebar: 0 0% 100%;
--sidebar-foreground: 222.2 84% 4.9%;
--sidebar-primary: 222.2 47.4% 11.2%;
--sidebar-primary-foreground: 210 40% 98%;
--sidebar-accent: 210 40% 96.1%;
--sidebar-accent-foreground: 222.2 47.4% 11.2%;
--sidebar-border: 214.3 31.8% 91.4%;
--sidebar-ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
@ -46,6 +54,14 @@
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
--sidebar: 217.2 32.6% 17.5%;
--sidebar-foreground: 210 40% 98%;
--sidebar-primary: 210 40% 98%;
--sidebar-primary-foreground: 222.2 47.4% 11.2%;
--sidebar-accent: 217.2 32.6% 17.5%;
--sidebar-accent-foreground: 210 40% 98%;
--sidebar-border: 217.2 32.6% 17.5%;
--sidebar-ring: 212.7 26.8% 83.9%;
}
}

View File

@ -0,0 +1,129 @@
'use client'
import { Home, Settings, Shield, LogOut } from 'lucide-react'
import { useAuth } from '@/hooks/use-auth'
import { useRouter, usePathname } from 'next/navigation'
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from '@/components/ui/sidebar'
import { Avatar, AvatarFallback } from '@/components/ui/avatar'
import { Separator } from '@/components/ui/separator'
import Link from 'next/link'
export function AppSidebar() {
const { user, logout } = useAuth()
const router = useRouter()
const pathname = usePathname()
const navItems = [
{ title: 'Dashboard', url: '/dashboard', icon: Home },
{ title: 'Einstellungen', url: '/dashboard/settings', icon: Settings },
]
const adminItems = user?.is_admin ? [
{ title: 'Admin', url: '/admin', icon: Shield }
] : []
const handleLogout = async () => {
await logout()
router.push('/login')
}
return (
<Sidebar>
<SidebarHeader>
<div className="flex items-center gap-2 px-4 py-2">
<h2 className="text-lg font-semibold">Container Spawner</h2>
</div>
</SidebarHeader>
<Separator />
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Navigation</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{navItems.map((item) => (
<SidebarMenuItem key={item.url}>
<SidebarMenuButton
asChild
isActive={pathname === item.url}
>
<Link href={item.url}>
<item.icon className="h-4 w-4" />
<span>{item.title}</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
{adminItems.length > 0 && (
<>
<Separator />
<SidebarGroup>
<SidebarGroupLabel>Administration</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{adminItems.map((item) => (
<SidebarMenuItem key={item.url}>
<SidebarMenuButton
asChild
isActive={pathname === item.url}
>
<Link href={item.url}>
<item.icon className="h-4 w-4" />
<span>{item.title}</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</>
)}
</SidebarContent>
<SidebarFooter>
<SidebarMenu>
<SidebarMenuItem>
<div className="flex items-center gap-2 px-4 py-2">
<Avatar className="h-8 w-8">
<AvatarFallback>
{user?.email?.charAt(0).toUpperCase() || 'U'}
</AvatarFallback>
</Avatar>
<div className="flex flex-col flex-1 min-w-0">
<span className="text-sm font-medium truncate">
{user?.email}
</span>
<span className="text-xs text-muted-foreground">
{user?.is_admin ? 'Administrator' : 'Benutzer'}
</span>
</div>
</div>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton onClick={handleLogout}>
<LogOut className="h-4 w-4" />
<span>Abmelden</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
</Sidebar>
)
}

View File

@ -0,0 +1,488 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const SIDEBAR_COOKIE_NAME = "sidebar:state"
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
const SIDEBAR_WIDTH = "16rem"
const SIDEBAR_WIDTH_MOBILE = "18rem"
const SIDEBAR_WIDTH_ICON = "3rem"
const SIDEBAR_KEYBOARD_SHORTCUT = "b"
type SidebarContextType = {
state: "expanded" | "collapsed"
open: boolean
setOpen: (open: boolean) => void
openMobile: boolean
setOpenMobile: (open: boolean) => void
isMobile: boolean
toggleSidebar: () => void
}
const SidebarContext = React.createContext<SidebarContextType | undefined>(undefined)
function useSidebar() {
const context = React.useContext(SidebarContext)
if (!context) {
throw new Error("useSidebar must be used within a SidebarProvider.")
}
return context
}
const SidebarProvider = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & {
defaultOpen?: boolean
open?: boolean
onOpenChange?: (open: boolean) => void
}
>(
(
{
defaultOpen = true,
open: openProp,
onOpenChange: setOpenProp,
className,
style,
children,
...props
},
ref
) => {
const isMobile = useIsMobile()
const [openMobile, setOpenMobile] = React.useState(false)
const [_open, _setOpen] = React.useState(defaultOpen)
const open = openProp ?? _open
const setOpen = React.useCallback(
(open: boolean) => {
setOpenProp?.(open)
_setOpen(open)
document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
},
[setOpenProp]
)
const state = open ? "expanded" : "collapsed"
const toggleSidebar = React.useCallback(() => {
return isMobile ? setOpenMobile(!openMobile) : setOpen(!open)
}, [isMobile, open, setOpen, openMobile])
React.useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
event.preventDefault()
toggleSidebar()
}
}
window.addEventListener("keydown", handleKeyDown)
return () => window.removeEventListener("keydown", handleKeyDown)
}, [toggleSidebar])
return (
<SidebarContext.Provider
value={{
state,
open,
setOpen,
isMobile,
openMobile,
setOpenMobile,
toggleSidebar,
}}
>
<div
style={
{
"--sidebar-width": SIDEBAR_WIDTH,
"--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
...style,
} as React.CSSProperties
}
className="flex h-full w-full"
ref={ref}
{...props}
>
{children}
</div>
</SidebarContext.Provider>
)
}
)
SidebarProvider.displayName = "SidebarProvider"
const Sidebar = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & {
side?: "left" | "right"
variant?: "sidebar" | "floating" | "inset"
collapsible?: "offcanvas" | "icon" | "none"
}
>(
(
{
side = "left",
variant = "sidebar",
collapsible = "offcanvas",
className,
...props
},
ref
) => {
const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
if (collapsible === "none") {
return (
<div
className={cn(
"flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground",
className
)}
ref={ref}
{...props}
/>
)
}
if (isMobile) {
return (
<Sheet open={openMobile} onOpenChange={setOpenMobile}>
<SheetContent side={side} className="w-[--sidebar-width-mobile] bg-sidebar p-0 text-sidebar-foreground">
<div className="flex h-full w-full flex-col" {...props} ref={ref} />
</SheetContent>
</Sheet>
)
}
return (
<div
className={cn(
"group peer hidden md:flex md:flex-col",
state === "collapsed" && "md:w-[--sidebar-width-icon]",
state === "expanded" && "md:w-[--sidebar-width]",
"h-full transition-[width] duration-300 ease-in-out",
variant === "inset" && "border-r"
)}
>
<div
className={cn(
"flex h-full w-full flex-col bg-sidebar text-sidebar-foreground",
className
)}
ref={ref}
{...props}
/>
</div>
)
}
)
Sidebar.displayName = "Sidebar"
const SidebarTrigger = React.forwardRef<
React.ElementRef<"button">,
React.ButtonHTMLAttributes<HTMLButtonElement>
>(({ className, ...props }, ref) => {
const { toggleSidebar } = useSidebar()
return (
<button
ref={ref}
onClick={toggleSidebar}
className={cn(
"inline-flex h-8 w-8 items-center justify-center rounded-md border border-input bg-background text-foreground hover:bg-accent hover:text-accent-foreground",
className
)}
{...props}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="h-4 w-4"
>
<rect width="18" height="18" x="3" y="3" rx="2" />
<path d="M9 3v18" />
</svg>
</button>
)
})
SidebarTrigger.displayName = "SidebarTrigger"
const SidebarInset = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("relative flex min-h-screen w-full flex-col bg-background", className)}
{...props}
/>
))
SidebarInset.displayName = "SidebarInset"
const SidebarContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col gap-4 overflow-hidden px-2 py-4 flex-1", className)}
{...props}
/>
))
SidebarContent.displayName = "SidebarContent"
const SidebarHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col gap-2 overflow-hidden px-2 py-4", className)}
{...props}
/>
))
SidebarHeader.displayName = "SidebarHeader"
const SidebarFooter = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col gap-2 overflow-hidden px-2 py-4", className)}
{...props}
/>
))
SidebarFooter.displayName = "SidebarFooter"
const SidebarSeparator = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("-mx-2 my-2 h-px bg-sidebar-border", className)}
{...props}
/>
))
SidebarSeparator.displayName = "SidebarSeparator"
const SidebarGroup = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("overflow-hidden px-2 py-4", className)}
{...props}
/>
))
SidebarGroup.displayName = "SidebarGroup"
const SidebarGroupLabel = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"px-2 py-1.5 text-xs font-medium text-sidebar-foreground/70",
className
)}
{...props}
/>
))
SidebarGroupLabel.displayName = "SidebarGroupLabel"
const SidebarGroupContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("w-full", className)} {...props} />
))
SidebarGroupContent.displayName = "SidebarGroupContent"
const SidebarMenu = React.forwardRef<
HTMLUListElement,
React.HTMLAttributes<HTMLUListElement>
>(({ className, ...props }, ref) => (
<ul ref={ref} className={cn("flex w-full flex-col gap-1", className)} {...props} />
))
SidebarMenu.displayName = "SidebarMenu"
const SidebarMenuItem = React.forwardRef<
HTMLLIElement,
React.HTMLAttributes<HTMLLIElement>
>(({ className, ...props }, ref) => (
<li ref={ref} className={cn("w-full", className)} {...props} />
))
SidebarMenuItem.displayName = "SidebarMenuItem"
const sidebarMenuButtonVariants = cva(
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md px-2 py-1.5 text-sm font-medium outline-none ring-sidebar-ring transition-all hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
{
variants: {
isActive: {
true: "bg-sidebar-accent text-sidebar-accent-foreground",
false: "text-sidebar-foreground",
},
variant: {
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
outline:
"border border-sidebar-border bg-background text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:border-sidebar-accent",
},
size: {
default: "h-8 px-2",
sm: "h-7 px-1.5 text-xs",
lg: "h-12 px-2 text-base",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
const SidebarMenuButton = React.forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement> &
VariantProps<typeof sidebarMenuButtonVariants> & {
asChild?: boolean
isActive?: boolean
}
>(
(
{ asChild = false, isActive = false, variant = "default", size = "default", ...props },
ref
) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
ref={ref}
className={sidebarMenuButtonVariants({
isActive,
variant,
size,
className: props.className,
})}
{...props}
/>
)
}
)
SidebarMenuButton.displayName = "SidebarMenuButton"
// Sheet component for mobile
const Sheet = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & {
open?: boolean
onOpenChange?: (open: boolean) => void
}
>(({ open, onOpenChange, children, ...props }, ref) => {
const [isOpen, setIsOpen] = React.useState(open ?? false)
React.useEffect(() => {
if (open !== undefined) {
setIsOpen(open)
}
}, [open])
return (
<>
{isOpen && (
<div
className="fixed inset-0 z-50 bg-background/80 backdrop-blur-sm"
onClick={() => {
setIsOpen(false)
onOpenChange?.(false)
}}
/>
)}
<div ref={ref} {...props}>
{children}
</div>
</>
)
})
Sheet.displayName = "Sheet"
interface SheetContentProps extends React.HTMLAttributes<HTMLDivElement> {
side?: "left" | "right" | "top" | "bottom"
}
const SheetContent = React.forwardRef<
HTMLDivElement,
SheetContentProps
>(({ side = "left", className, ...props }, ref) => {
const sideClasses = {
left: "left-0 top-0 h-full w-[--sidebar-width-mobile] border-r",
right: "right-0 top-0 h-full w-[--sidebar-width-mobile] border-l",
top: "top-0 left-0 right-0 h-auto border-b",
bottom: "bottom-0 left-0 right-0 h-auto border-t",
}
return (
<div
ref={ref}
className={cn(
"fixed z-50 bg-background transition-all duration-300",
sideClasses[side],
className
)}
{...props}
/>
)
})
SheetContent.displayName = "SheetContent"
function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
React.useEffect(() => {
const mq = window.matchMedia("(max-width: 768px)")
setIsMobile(mq.matches)
const onChange = (m: MediaQueryListEvent) => {
setIsMobile(m.matches)
}
mq.addEventListener("change", onChange)
return () => mq.removeEventListener("change", onChange)
}, [])
return isMobile ?? false
}
export {
Sidebar,
SidebarProvider,
SidebarTrigger,
SidebarContent,
SidebarHeader,
SidebarFooter,
SidebarSeparator,
SidebarGroup,
SidebarGroupLabel,
SidebarGroupContent,
SidebarMenu,
SidebarMenuItem,
SidebarMenuButton,
SidebarInset,
Sheet,
SheetContent,
useSidebar,
}

View File

@ -43,6 +43,16 @@ const config: Config = {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
sidebar: {
DEFAULT: "hsl(var(--sidebar))",
foreground: "hsl(var(--sidebar-foreground))",
primary: "hsl(var(--sidebar-primary))",
"primary-foreground": "hsl(var(--sidebar-primary-foreground))",
accent: "hsl(var(--sidebar-accent))",
"accent-foreground": "hsl(var(--sidebar-accent-foreground))",
border: "hsl(var(--sidebar-border))",
ring: "hsl(var(--sidebar-ring))",
},
},
borderRadius: {
lg: "var(--radius)",