2026-01-08 19:10:40 +02:00
|
|
|
"use client";
|
|
|
|
|
|
2026-04-28 23:58:00 +05:30
|
|
|
import { Plus, SquarePen } from "lucide-react";
|
2026-01-08 19:10:40 +02:00
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
|
|
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
|
|
|
|
import { cn } from "@/lib/utils";
|
2026-04-28 23:58:00 +05:30
|
|
|
import type { NavItem, SearchSpace } from "../../types/layout.types";
|
2026-04-28 19:29:14 +05:30
|
|
|
import type { User } from "../../types/layout.types";
|
|
|
|
|
import { SidebarUserProfile } from "../sidebar/SidebarUserProfile";
|
2026-01-12 15:47:56 +02:00
|
|
|
import { SearchSpaceAvatar } from "./SearchSpaceAvatar";
|
2026-01-08 19:10:40 +02:00
|
|
|
|
|
|
|
|
interface IconRailProps {
|
2026-01-12 15:47:56 +02:00
|
|
|
searchSpaces: SearchSpace[];
|
|
|
|
|
activeSearchSpaceId: number | null;
|
|
|
|
|
onSearchSpaceSelect: (id: number) => void;
|
2026-01-13 01:45:58 -08:00
|
|
|
onSearchSpaceDelete?: (searchSpace: SearchSpace) => void;
|
|
|
|
|
onSearchSpaceSettings?: (searchSpace: SearchSpace) => void;
|
2026-01-12 15:47:56 +02:00
|
|
|
onAddSearchSpace: () => void;
|
2026-04-28 23:58:00 +05:30
|
|
|
isSingleRailMode?: boolean;
|
|
|
|
|
onNewChat?: () => void;
|
|
|
|
|
navItems?: NavItem[];
|
|
|
|
|
onNavItemClick?: (item: NavItem) => void;
|
2026-04-28 19:29:14 +05:30
|
|
|
user: User;
|
|
|
|
|
onUserSettings?: () => void;
|
2026-05-03 18:42:29 +05:30
|
|
|
onAnnouncements?: () => void;
|
|
|
|
|
announcementUnreadCount?: number;
|
2026-04-28 19:29:14 +05:30
|
|
|
onLogout?: () => void;
|
|
|
|
|
theme?: string;
|
|
|
|
|
setTheme?: (theme: "light" | "dark" | "system") => void;
|
2026-01-08 19:10:40 +02:00
|
|
|
className?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function IconRail({
|
2026-01-12 15:47:56 +02:00
|
|
|
searchSpaces,
|
|
|
|
|
activeSearchSpaceId,
|
|
|
|
|
onSearchSpaceSelect,
|
2026-01-13 01:45:58 -08:00
|
|
|
onSearchSpaceDelete,
|
|
|
|
|
onSearchSpaceSettings,
|
2026-01-12 15:47:56 +02:00
|
|
|
onAddSearchSpace,
|
2026-04-28 23:58:00 +05:30
|
|
|
isSingleRailMode = false,
|
|
|
|
|
onNewChat,
|
|
|
|
|
navItems = [],
|
|
|
|
|
onNavItemClick,
|
2026-04-28 19:29:14 +05:30
|
|
|
user,
|
|
|
|
|
onUserSettings,
|
2026-05-03 18:42:29 +05:30
|
|
|
onAnnouncements,
|
|
|
|
|
announcementUnreadCount = 0,
|
2026-04-28 19:29:14 +05:30
|
|
|
onLogout,
|
|
|
|
|
theme,
|
|
|
|
|
setTheme,
|
2026-01-08 19:10:40 +02:00
|
|
|
className,
|
|
|
|
|
}: IconRailProps) {
|
2026-04-28 23:58:00 +05:30
|
|
|
const actionItems = isSingleRailMode
|
|
|
|
|
? [
|
|
|
|
|
...(onNewChat
|
|
|
|
|
? [
|
|
|
|
|
{
|
|
|
|
|
key: "new-chat",
|
|
|
|
|
label: "New chat",
|
|
|
|
|
onClick: onNewChat,
|
|
|
|
|
icon: SquarePen,
|
|
|
|
|
isActive: false,
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
|
|
|
|
...navItems.map((item) => ({
|
|
|
|
|
key: item.url,
|
|
|
|
|
label: item.title,
|
|
|
|
|
onClick: () => onNavItemClick?.(item),
|
|
|
|
|
icon: item.icon,
|
|
|
|
|
isActive: !!item.isActive,
|
|
|
|
|
})),
|
|
|
|
|
]
|
|
|
|
|
: [];
|
|
|
|
|
|
2026-01-08 19:10:40 +02:00
|
|
|
return (
|
2026-04-28 19:29:14 +05:30
|
|
|
<div className={cn("flex h-full w-14 min-h-0 flex-col items-center", className)}>
|
|
|
|
|
<ScrollArea className="w-full min-h-0 flex-1">
|
2026-01-08 19:10:40 +02:00
|
|
|
<div className="flex flex-col items-center gap-2 px-1.5 py-3">
|
2026-01-12 15:47:56 +02:00
|
|
|
{searchSpaces.map((searchSpace) => (
|
|
|
|
|
<SearchSpaceAvatar
|
|
|
|
|
key={searchSpace.id}
|
|
|
|
|
name={searchSpace.name}
|
|
|
|
|
isActive={searchSpace.id === activeSearchSpaceId}
|
2026-01-13 01:45:58 -08:00
|
|
|
isShared={searchSpace.memberCount > 1}
|
|
|
|
|
isOwner={searchSpace.isOwner}
|
2026-01-12 15:47:56 +02:00
|
|
|
onClick={() => onSearchSpaceSelect(searchSpace.id)}
|
2026-01-13 01:45:58 -08:00
|
|
|
onDelete={onSearchSpaceDelete ? () => onSearchSpaceDelete(searchSpace) : undefined}
|
|
|
|
|
onSettings={
|
|
|
|
|
onSearchSpaceSettings ? () => onSearchSpaceSettings(searchSpace) : undefined
|
|
|
|
|
}
|
2026-01-08 19:10:40 +02:00
|
|
|
size="md"
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
|
|
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger asChild>
|
|
|
|
|
<Button
|
|
|
|
|
variant="ghost"
|
|
|
|
|
size="icon"
|
2026-01-12 15:47:56 +02:00
|
|
|
onClick={onAddSearchSpace}
|
2026-01-08 19:10:40 +02:00
|
|
|
className="h-10 w-10 rounded-lg border-2 border-dashed border-muted-foreground/30 hover:border-muted-foreground/50"
|
|
|
|
|
>
|
|
|
|
|
<Plus className="h-5 w-5 text-muted-foreground" />
|
2026-01-12 15:47:56 +02:00
|
|
|
<span className="sr-only">Add search space</span>
|
2026-01-08 19:10:40 +02:00
|
|
|
</Button>
|
|
|
|
|
</TooltipTrigger>
|
|
|
|
|
<TooltipContent side="right" sideOffset={8}>
|
2026-01-12 15:47:56 +02:00
|
|
|
Add search space
|
2026-01-08 19:10:40 +02:00
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
2026-04-28 23:58:00 +05:30
|
|
|
|
|
|
|
|
{actionItems.length > 0 && (
|
|
|
|
|
<>
|
|
|
|
|
<div className="my-1 h-px w-8 bg-border/60" />
|
|
|
|
|
{actionItems.map(({ key, label, onClick, icon: Icon, isActive }) => (
|
|
|
|
|
<Tooltip key={key}>
|
|
|
|
|
<TooltipTrigger asChild>
|
|
|
|
|
<Button
|
|
|
|
|
variant="ghost"
|
|
|
|
|
size="icon"
|
|
|
|
|
onClick={onClick}
|
|
|
|
|
className={cn(
|
|
|
|
|
"h-10 w-10 rounded-lg",
|
|
|
|
|
isActive && "bg-accent text-accent-foreground"
|
|
|
|
|
)}
|
|
|
|
|
>
|
|
|
|
|
<Icon className="h-4 w-4" />
|
|
|
|
|
<span className="sr-only">{label}</span>
|
|
|
|
|
</Button>
|
|
|
|
|
</TooltipTrigger>
|
|
|
|
|
<TooltipContent side="right" sideOffset={8}>
|
|
|
|
|
{label}
|
|
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
))}
|
|
|
|
|
</>
|
|
|
|
|
)}
|
2026-01-08 19:10:40 +02:00
|
|
|
</div>
|
|
|
|
|
</ScrollArea>
|
2026-04-28 19:29:14 +05:30
|
|
|
<SidebarUserProfile
|
|
|
|
|
user={user}
|
|
|
|
|
onUserSettings={onUserSettings}
|
2026-05-03 18:42:29 +05:30
|
|
|
onAnnouncements={onAnnouncements}
|
|
|
|
|
announcementUnreadCount={announcementUnreadCount}
|
2026-04-28 19:29:14 +05:30
|
|
|
onLogout={onLogout}
|
|
|
|
|
isCollapsed
|
|
|
|
|
theme={theme}
|
|
|
|
|
setTheme={setTheme}
|
|
|
|
|
/>
|
2026-01-08 19:10:40 +02:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|