mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-04-25 08:26:22 +02:00
- Implemented agent selection dropdown in the input area. - Enhanced artifact management with loading, saving, and error handling. - Added new API routes for fetching agent summaries and run details. - Updated sidebar to display agents, configurations, and runs dynamically. - Introduced theme selection options in the user navigation menu.
177 lines
5.4 KiB
TypeScript
177 lines
5.4 KiB
TypeScript
"use client"
|
|
|
|
import {
|
|
BadgeCheck,
|
|
Bell,
|
|
ChevronsUpDown,
|
|
CreditCard,
|
|
LogOut,
|
|
Sparkles,
|
|
Moon,
|
|
Sun,
|
|
MonitorCog,
|
|
} from "lucide-react"
|
|
import { useEffect, useState } from "react"
|
|
|
|
import {
|
|
Avatar,
|
|
AvatarFallback,
|
|
AvatarImage,
|
|
} from "@/components/ui/avatar"
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuGroup,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu"
|
|
import {
|
|
SidebarMenu,
|
|
SidebarMenuButton,
|
|
SidebarMenuItem,
|
|
useSidebar,
|
|
} from "@/components/ui/sidebar"
|
|
|
|
export function NavUser({
|
|
user,
|
|
}: {
|
|
user: {
|
|
name: string
|
|
email: string
|
|
avatar: string
|
|
}
|
|
}) {
|
|
const { isMobile } = useSidebar()
|
|
const [theme, setTheme] = useState<"light" | "dark" | "system">("system")
|
|
|
|
useEffect(() => {
|
|
if (typeof window === "undefined") return
|
|
const saved = (localStorage.getItem("theme") as "light" | "dark" | "system") || "system"
|
|
setTheme(saved)
|
|
applyTheme(saved)
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
if (typeof window === "undefined") return
|
|
if (theme !== "system") return
|
|
const media = window.matchMedia("(prefers-color-scheme: dark)")
|
|
const listener = () => applyTheme("system")
|
|
media.addEventListener("change", listener)
|
|
return () => media.removeEventListener("change", listener)
|
|
}, [theme])
|
|
|
|
const applyTheme = (value: "light" | "dark" | "system") => {
|
|
const resolved =
|
|
value === "system"
|
|
? (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light")
|
|
: value
|
|
const root = document.documentElement
|
|
root.classList.toggle("dark", resolved === "dark")
|
|
localStorage.setItem("theme", value)
|
|
}
|
|
|
|
const handleTheme = (value: "light" | "dark" | "system") => {
|
|
setTheme(value)
|
|
if (typeof window !== "undefined") {
|
|
applyTheme(value)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<SidebarMenu>
|
|
<SidebarMenuItem>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<SidebarMenuButton
|
|
size="lg"
|
|
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
|
>
|
|
<Avatar className="h-8 w-8 rounded-lg">
|
|
<AvatarImage src={user.avatar} alt={user.name} />
|
|
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
|
</Avatar>
|
|
<div className="grid flex-1 text-left text-sm leading-tight">
|
|
<span className="truncate font-medium">{user.name}</span>
|
|
<span className="truncate text-xs">{user.email}</span>
|
|
</div>
|
|
<ChevronsUpDown className="ml-auto size-4" />
|
|
</SidebarMenuButton>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent
|
|
className="w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg"
|
|
side={isMobile ? "bottom" : "right"}
|
|
align="end"
|
|
sideOffset={4}
|
|
>
|
|
<DropdownMenuLabel className="p-0 font-normal">
|
|
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
|
|
<Avatar className="h-8 w-8 rounded-lg">
|
|
<AvatarImage src={user.avatar} alt={user.name} />
|
|
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
|
</Avatar>
|
|
<div className="grid flex-1 text-left text-sm leading-tight">
|
|
<span className="truncate font-medium">{user.name}</span>
|
|
<span className="truncate text-xs">{user.email}</span>
|
|
</div>
|
|
</div>
|
|
</DropdownMenuLabel>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuGroup>
|
|
<DropdownMenuItem>
|
|
<Sparkles />
|
|
Upgrade to Pro
|
|
</DropdownMenuItem>
|
|
</DropdownMenuGroup>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuGroup>
|
|
<DropdownMenuLabel>Theme</DropdownMenuLabel>
|
|
<DropdownMenuItem
|
|
className={theme === "light" ? "bg-muted" : ""}
|
|
onClick={() => handleTheme("light")}
|
|
>
|
|
<Sun className="mr-2" />
|
|
Light
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem
|
|
className={theme === "dark" ? "bg-muted" : ""}
|
|
onClick={() => handleTheme("dark")}
|
|
>
|
|
<Moon className="mr-2" />
|
|
Dark
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem
|
|
className={theme === "system" ? "bg-muted" : ""}
|
|
onClick={() => handleTheme("system")}
|
|
>
|
|
<MonitorCog className="mr-2" />
|
|
System
|
|
</DropdownMenuItem>
|
|
</DropdownMenuGroup>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuGroup>
|
|
<DropdownMenuItem>
|
|
<BadgeCheck />
|
|
Account
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem>
|
|
<CreditCard />
|
|
Billing
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem>
|
|
<Bell />
|
|
Notifications
|
|
</DropdownMenuItem>
|
|
</DropdownMenuGroup>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem>
|
|
<LogOut />
|
|
Log out
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</SidebarMenuItem>
|
|
</SidebarMenu>
|
|
)
|
|
}
|