xertica-ui 1.4.13 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,14 +4,28 @@ import {
4
4
  ArrowLeft,
5
5
  LogOut,
6
6
  Settings,
7
- MoreHorizontal,
7
+ MoreVertical,
8
8
  ChevronRight,
9
+ Filter,
9
10
  } from "lucide-react";
10
11
  // routes import removed to make it reusable
11
12
  import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar";
12
13
  import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
13
14
  import { Tooltip, TooltipProvider, TooltipTrigger } from "./ui/tooltip";
14
15
  import * as TooltipPrimitive from "@radix-ui/react-tooltip";
16
+ import {
17
+ DropdownMenu,
18
+ DropdownMenuContent,
19
+ DropdownMenuItem,
20
+ DropdownMenuTrigger,
21
+ DropdownMenuSub,
22
+ DropdownMenuSubTrigger,
23
+ DropdownMenuSubContent,
24
+ DropdownMenuPortal,
25
+ } from "./ui/dropdown-menu";
26
+ import { ScrollArea } from "./ui/scroll-area";
27
+ import { Input } from "./ui/input";
28
+ import { Search as SearchIcon } from "lucide-react";
15
29
  import { cn } from "./ui/utils";
16
30
  import { XerticaLogo } from "./XerticaLogo";
17
31
  import { XerticaXLogo } from "./XerticaXLogo";
@@ -45,17 +59,29 @@ function SidebarTooltipContent({
45
59
  }
46
60
 
47
61
  // Interface for Route Config (copied/imported type)
62
+ export interface ActionMenuItem {
63
+ label: string;
64
+ icon?: React.ComponentType<any>;
65
+ onClick?: (item: any) => void;
66
+ variant?: "default" | "destructive";
67
+ children?: ActionMenuItem[];
68
+ }
69
+
48
70
  export interface RouteConfig {
49
71
  path: string;
50
72
  label: string;
51
73
  icon: React.ComponentType<any>;
52
74
  component?: React.ComponentType<any>;
75
+ actions?: ActionMenuItem[]; // Menus de hover (elipses)
76
+ description?: React.ReactNode; // Conteúdo auxiliar quando selecionado
53
77
  }
54
78
 
55
79
  interface SubMenuItem {
56
80
  id: string;
57
81
  label: string;
58
82
  path: string;
83
+ icon?: React.ComponentType<any>;
84
+ actions?: ActionMenuItem[];
59
85
  }
60
86
 
61
87
  interface NavigationItem {
@@ -66,6 +92,33 @@ interface NavigationItem {
66
92
  subItems?: SubMenuItem[];
67
93
  }
68
94
 
95
+ export interface SidebarFilterConfig {
96
+ show: boolean;
97
+ content?: React.ReactNode;
98
+ icon?: React.ReactNode;
99
+ }
100
+
101
+ export interface SidebarSearchConfig {
102
+ show: boolean;
103
+ placeholder?: string;
104
+ value?: string;
105
+ onChange?: (value: string) => void;
106
+ filter?: SidebarFilterConfig;
107
+ }
108
+
109
+ export interface SidebarFixedAreaConfig {
110
+ show: boolean;
111
+ content?: React.ReactNode;
112
+ }
113
+
114
+ export interface RouteGroup {
115
+ id: string;
116
+ label?: string; // Título do grupo
117
+ icon?: React.ComponentType<any>; // Ícone do grupo
118
+ items: RouteConfig[];
119
+ actions?: ActionMenuItem[]; // Menu contextual para o grupo inteiro
120
+ }
121
+
69
122
  interface SidebarProps {
70
123
  expanded: boolean;
71
124
  onToggle: () => void;
@@ -73,9 +126,17 @@ interface SidebarProps {
73
126
  onLogout: () => void;
74
127
  location: { pathname: string };
75
128
  navigate: (path: string) => void;
76
- routes: RouteConfig[];
129
+ routes?: RouteConfig[]; // tornado opcional devido ao assistant
77
130
  logo?: React.ReactNode;
78
131
  logoCollapsed?: React.ReactNode;
132
+
133
+ // Prop para definir qual comportamento renderizar
134
+ variant?: "default" | "assistant";
135
+
136
+ // Específicos do Assistant
137
+ fixedArea?: SidebarFixedAreaConfig;
138
+ search?: SidebarSearchConfig;
139
+ navigationGroups?: RouteGroup[];
79
140
  }
80
141
 
81
142
  export function Sidebar({
@@ -88,8 +149,13 @@ export function Sidebar({
88
149
  routes,
89
150
  logo,
90
151
  logoCollapsed,
152
+ variant = "default",
153
+ fixedArea,
154
+ search,
155
+ navigationGroups = [],
91
156
  }: SidebarProps) {
92
157
  const navRef = useRef<HTMLDivElement>(null);
158
+ const [localActiveItem, setLocalActiveItem] = useState<string | null>(null);
93
159
  const [hasOverflow, setHasOverflow] = useState(false);
94
160
  const [visibleItems, setVisibleItems] = useState<NavigationItem[]>([]);
95
161
  const [overflowItems, setOverflowItems] = useState<NavigationItem[]>([]);
@@ -111,7 +177,7 @@ export function Sidebar({
111
177
  ],
112
178
  };
113
179
 
114
- const navigationItems: NavigationItem[] = routes.map((route) => ({
180
+ const navigationItems: NavigationItem[] = (routes || []).map((route) => ({
115
181
  ...route,
116
182
  label:
117
183
  labelTranslations[route.label.toLowerCase()] ||
@@ -126,6 +192,7 @@ export function Sidebar({
126
192
  useEffect(() => {
127
193
  const checkOverflow = () => {
128
194
  if (!navRef.current) return;
195
+ if (variant === "assistant") return;
129
196
 
130
197
  const navHeight = navRef.current.clientHeight;
131
198
  const itemHeight = 44; // h-10 + gap
@@ -148,6 +215,7 @@ export function Sidebar({
148
215
  }, [navigationItems.length]);
149
216
 
150
217
  const handleNavigate = (path: string) => {
218
+ setLocalActiveItem(path);
151
219
  navigate(path);
152
220
  setOpenSubmenu(null);
153
221
  // Fecha o menu no mobile após navegar
@@ -181,7 +249,7 @@ export function Sidebar({
181
249
  {item.label}
182
250
  </span>
183
251
  {hasSubItems && (
184
- <MoreHorizontal className="w-4 h-4 flex-shrink-0 text-sidebar-foreground/60" />
252
+ <MoreVertical className="w-4 h-4 flex-shrink-0 text-sidebar-foreground/60" />
185
253
  )}
186
254
  </>
187
255
  )}
@@ -292,6 +360,132 @@ export function Sidebar({
292
360
  return simpleButton;
293
361
  };
294
362
 
363
+ const renderActionItems = (actions: ActionMenuItem[]) => {
364
+ return actions.map((action, idx) => {
365
+ const Icon = action.icon;
366
+
367
+ if (action.children && action.children.length > 0) {
368
+ return (
369
+ <DropdownMenuSub key={idx}>
370
+ <DropdownMenuSubTrigger>
371
+ {Icon && <Icon className="mr-2 h-4 w-4" />}
372
+ <span>{action.label}</span>
373
+ </DropdownMenuSubTrigger>
374
+ <DropdownMenuPortal>
375
+ <DropdownMenuSubContent className="w-48 bg-popover border-border">
376
+ {renderActionItems(action.children)}
377
+ </DropdownMenuSubContent>
378
+ </DropdownMenuPortal>
379
+ </DropdownMenuSub>
380
+ );
381
+ }
382
+
383
+ return (
384
+ <DropdownMenuItem
385
+ key={idx}
386
+ className={cn(
387
+ "flex items-center gap-2",
388
+ action.variant === "destructive" ? "text-destructive focus:text-destructive" : ""
389
+ )}
390
+ onClick={(e) => {
391
+ e.stopPropagation();
392
+ action.onClick?.(null);
393
+ }}
394
+ >
395
+ {Icon && <Icon className="h-4 w-4 flex-shrink-0" />}
396
+ <span>{action.label}</span>
397
+ </DropdownMenuItem>
398
+ );
399
+ });
400
+ };
401
+
402
+ const renderAssistantActionMenu = (actions?: ActionMenuItem[], isHeader: boolean = false) => {
403
+ if (!actions || actions.length === 0) return null;
404
+
405
+ return (
406
+ <DropdownMenu>
407
+ <DropdownMenuTrigger asChild>
408
+ <Button
409
+ variant="ghost"
410
+ size="icon"
411
+ className={cn(
412
+ "h-8 w-8 text-sidebar-foreground/60 hover:bg-sidebar-foreground/20 hover:text-sidebar-foreground rounded-full transition-all",
413
+ !isHeader && "opacity-0 group-hover/item:opacity-100"
414
+ )}
415
+ >
416
+ <MoreVertical className="h-4 w-4" />
417
+ </Button>
418
+ </DropdownMenuTrigger>
419
+ <DropdownMenuContent align="end" className="w-48 bg-popover border-border p-1">
420
+ {renderActionItems(actions)}
421
+ </DropdownMenuContent>
422
+ </DropdownMenu>
423
+ );
424
+ };
425
+
426
+ const renderAssistantGroup = (group: RouteGroup) => {
427
+ return (
428
+ <div key={group.id} className="py-2 group">
429
+ {(group.label || group.icon) && (
430
+ <div className="flex items-center justify-between px-3 mb-1">
431
+ <div className="flex items-center gap-2 text-sidebar-foreground/60 text-xs font-semibold uppercase tracking-wider">
432
+ {group.icon && <group.icon className="h-4 w-4" />}
433
+ {expanded && group.label && <span>{group.label}</span>}
434
+ </div>
435
+ {expanded && renderAssistantActionMenu(group.actions, true)}
436
+ </div>
437
+ )}
438
+ <div className="space-y-1">
439
+ {group.items.map(item => {
440
+ const isRouteActive = location.pathname === item.path || location.pathname.startsWith(item.path + "/");
441
+ const isActive = isRouteActive || localActiveItem === item.path;
442
+ const Icon = item.icon;
443
+
444
+ const simpleBtn = (
445
+ <div
446
+ className={expanded
447
+ ? `group/item flex items-start justify-between px-3 min-h-[36px] py-2.5 rounded-[var(--radius-button)] cursor-pointer transition-all duration-200 ${isActive ? 'bg-sidebar-foreground/15 text-sidebar-foreground' : 'text-sidebar-foreground/80 hover:bg-sidebar-foreground/10 hover:text-sidebar-foreground'}`
448
+ : `group/item flex items-center justify-center h-10 px-0 rounded-[var(--radius-button)] cursor-pointer transition-all duration-200 ${isActive ? 'bg-sidebar-foreground/15 text-sidebar-foreground' : 'text-sidebar-foreground/80 hover:bg-sidebar-foreground/10 hover:text-sidebar-foreground'}`
449
+ }
450
+ onClick={() => handleNavigate(item.path)}
451
+ >
452
+ <div className="flex flex-col min-w-0 flex-1">
453
+ <div className="flex items-center gap-3 overflow-hidden h-5">
454
+ <Icon className="w-4 h-4 flex-shrink-0" />
455
+ {expanded && <span className="truncate text-sm font-medium leading-none">{item.label}</span>}
456
+ </div>
457
+ {expanded && isActive && item.description && (
458
+ <div className="ml-7 text-[11px] text-sidebar-foreground/60 mt-1.5 animate-in fade-in slide-in-from-top-1 duration-200">
459
+ {item.description}
460
+ </div>
461
+ )}
462
+ </div>
463
+ {expanded && (
464
+ <div className="h-5 flex items-center ml-1">
465
+ {renderAssistantActionMenu(item.actions)}
466
+ </div>
467
+ )}
468
+ </div>
469
+ );
470
+
471
+ return (
472
+ <div key={item.path}>
473
+ {!expanded ? (
474
+ <Tooltip>
475
+ <TooltipTrigger asChild>{simpleBtn}</TooltipTrigger>
476
+ <SidebarTooltipContent side="right" sideOffset={0}>
477
+ <p>{item.label}</p>
478
+ </SidebarTooltipContent>
479
+ </Tooltip>
480
+ ) : simpleBtn}
481
+ </div>
482
+ );
483
+ })}
484
+ </div>
485
+ </div>
486
+ );
487
+ };
488
+
295
489
  return (
296
490
  <TooltipProvider delayDuration={300}>
297
491
  {/* Sidebar */}
@@ -302,7 +496,7 @@ export function Sidebar({
302
496
  }`}
303
497
  >
304
498
  {/* Botão Toggle Menu */}
305
- <div className="p-[14px] pt-[13px] pr-[14px] pb-[12px] pl-[14px]">
499
+ <div className="flex-shrink-0 p-[14px] pt-[13px] pr-[14px] pb-[12px] pl-[14px]">
306
500
  <button
307
501
  onClick={onToggle}
308
502
  className="w-full h-10 flex items-center gap-3 px-3 justify-center rounded-[var(--radius-button)] transition-all duration-200 text-sidebar-foreground/80 hover:bg-sidebar-foreground/15 hover:text-sidebar-foreground"
@@ -316,7 +510,7 @@ export function Sidebar({
316
510
  </div>
317
511
 
318
512
  {/* Logo */}
319
- <div className="px-4 py-4">
513
+ <div className="flex-shrink-0 px-4 py-4">
320
514
  <div
321
515
  className={`flex items-center h-10 ${expanded ? "justify-center" : "justify-center"}`}
322
516
  >
@@ -340,62 +534,121 @@ export function Sidebar({
340
534
  </div>
341
535
  </div>
342
536
 
343
- {/* Navegação */}
344
- <nav className="flex-1 px-4 py-4 overflow-hidden" ref={navRef}>
345
- <div className="space-y-1">
346
- {/* Itens visíveis */}
347
- {(hasOverflow ? visibleItems : navigationItems).map((item) =>
348
- renderMenuItem(item)
537
+ {/* Assistant-specific Header (Search/Fixed Area) - Always fixed when present */}
538
+ {variant === "assistant" && ((fixedArea && fixedArea.show) || (search && search.show)) && (
539
+ <div className="flex-shrink-0 px-4 pb-4 space-y-4 border-b border-sidebar-border/30 mb-2">
540
+ {fixedArea?.show && fixedArea.content && expanded && (
541
+ <div className="animate-in fade-in slide-in-from-top-1 duration-300">
542
+ {fixedArea.content}
543
+ </div>
349
544
  )}
350
-
351
- {/* Botão de overflow (ellipsis) */}
352
- {hasOverflow && (
353
- <Popover>
354
- <PopoverTrigger asChild>
355
- <button
356
- className={
357
- expanded
358
- ? "w-full h-10 flex items-center gap-3 px-3 justify-start rounded-[var(--radius-button)] transition-all duration-200 text-sidebar-foreground/80 hover:bg-sidebar-foreground/15 hover:text-sidebar-foreground"
359
- : "w-full h-10 flex items-center justify-center px-0 rounded-[var(--radius-button)] transition-all duration-200 text-sidebar-foreground/80 hover:bg-sidebar-foreground/15 hover:text-sidebar-foreground"
360
- }
361
- >
362
- <MoreHorizontal className="w-5 h-5 flex-shrink-0" />
363
- {expanded && (
364
- <span className="truncate text-sidebar-foreground">
365
- Mais opções
366
- </span>
367
- )}
368
- </button>
369
- </PopoverTrigger>
370
- <PopoverContent
371
- side="right"
372
- align="start"
373
- className="w-56 p-2 bg-popover border border-border rounded-[var(--radius-card)] shadow-lg"
374
- sideOffset={8}
375
- >
376
- <div className="space-y-1">
377
- {overflowItems.map((item) => {
378
- const Icon = item.icon;
379
- return (
380
- <button
381
- key={item.path}
382
- onClick={() => handleNavigate(item.path)}
383
- className="w-full h-9 flex items-center gap-2 px-3 rounded-[var(--radius-button)] transition-all duration-200 text-popover-foreground/80 hover:bg-accent hover:text-accent-foreground text-left"
384
- >
385
- <Icon className="w-4 h-4 flex-shrink-0" />
386
- <span className="truncate">{item.label}</span>
387
- </button>
388
- );
389
- })}
390
- </div>
391
- </PopoverContent>
392
- </Popover>
545
+ {search?.show && expanded && (
546
+ <div className="flex items-center gap-2">
547
+ <div className="relative flex-1">
548
+ <SearchIcon className="absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-sidebar-foreground/50" />
549
+ <Input
550
+ type="text"
551
+ placeholder={search.placeholder || "Buscar..."}
552
+ value={search.value}
553
+ onChange={(e) => search.onChange?.(e.target.value)}
554
+ className="w-full h-9 bg-sidebar-foreground/10 border-sidebar-border text-sidebar-foreground placeholder:text-sidebar-foreground/50 pl-9 focus-visible:ring-1 focus-visible:ring-sidebar-foreground/30 focus-visible:ring-offset-0"
555
+ />
556
+ </div>
557
+ {search.filter?.show && search.filter.content && (
558
+ <Popover>
559
+ <PopoverTrigger asChild>
560
+ <Button variant="ghost" size="icon" className="h-9 w-9 text-sidebar-foreground hover:bg-sidebar-foreground/15 hover:text-sidebar-foreground">
561
+ {search.filter.icon || <Filter className="h-4 w-4" />}
562
+ </Button>
563
+ </PopoverTrigger>
564
+ <PopoverContent side="bottom" align="end" className="w-64 p-0 bg-popover border-border">
565
+ {search.filter.content}
566
+ </PopoverContent>
567
+ </Popover>
568
+ )}
569
+ </div>
570
+ )}
571
+ {(!expanded && (fixedArea?.show || search?.show)) && (
572
+ <div className="flex flex-col items-center gap-2">
573
+ {search?.show && (
574
+ <Tooltip>
575
+ <TooltipTrigger asChild>
576
+ <button className="h-10 w-10 flex items-center justify-center rounded-[var(--radius-button)] text-sidebar-foreground/80 hover:bg-sidebar-foreground/15 hover:text-sidebar-foreground">
577
+ <SearchIcon className="h-5 w-5" />
578
+ </button>
579
+ </TooltipTrigger>
580
+ <SidebarTooltipContent side="right">Buscar</SidebarTooltipContent>
581
+ </Tooltip>
582
+ )}
583
+ </div>
393
584
  )}
394
585
  </div>
395
- </nav>
586
+ )}
587
+
588
+ {/* Main Content Area - Scrollable */}
589
+ <div className="flex-1 min-h-0 overflow-hidden">
590
+ {variant === "default" ? (
591
+ <nav className="h-full px-4 py-4 overflow-hidden" ref={navRef}>
592
+ <div className="space-y-1">
593
+ {/* Itens visíveis */}
594
+ {(hasOverflow ? visibleItems : navigationItems).map((item) =>
595
+ renderMenuItem(item)
596
+ )}
597
+
598
+ {/* Botão de overflow (ellipsis) */}
599
+ {hasOverflow && (
600
+ <Popover>
601
+ <PopoverTrigger asChild>
602
+ <button
603
+ className={
604
+ expanded
605
+ ? "w-full h-10 flex items-center gap-3 px-3 justify-start rounded-[var(--radius-button)] transition-all duration-200 text-sidebar-foreground/80 hover:bg-sidebar-foreground/15 hover:text-sidebar-foreground"
606
+ : "w-full h-10 flex items-center justify-center px-0 rounded-[var(--radius-button)] transition-all duration-200 text-sidebar-foreground/80 hover:bg-sidebar-foreground/15 hover:text-sidebar-foreground"
607
+ }
608
+ >
609
+ <MoreVertical className="w-5 h-5 flex-shrink-0" />
610
+ {expanded && (
611
+ <span className="truncate text-sidebar-foreground">
612
+ Mais opções
613
+ </span>
614
+ )}
615
+ </button>
616
+ </PopoverTrigger>
617
+ <PopoverContent
618
+ side="right"
619
+ align="start"
620
+ className="w-56 p-2 bg-popover border border-border rounded-[var(--radius-card)] shadow-lg"
621
+ sideOffset={8}
622
+ >
623
+ <div className="space-y-1">
624
+ {overflowItems.map((item) => {
625
+ const Icon = item.icon;
626
+ return (
627
+ <button
628
+ key={item.path}
629
+ onClick={() => handleNavigate(item.path)}
630
+ className="w-full h-9 flex items-center gap-2 px-3 rounded-[var(--radius-button)] transition-all duration-200 text-popover-foreground/80 hover:bg-accent hover:text-accent-foreground text-left"
631
+ >
632
+ <Icon className="w-4 h-4 flex-shrink-0" />
633
+ <span className="truncate">{item.label}</span>
634
+ </button>
635
+ );
636
+ })}
637
+ </div>
638
+ </PopoverContent>
639
+ </Popover>
640
+ )}
641
+ </div>
642
+ </nav>
643
+ ) : (
644
+ <ScrollArea className="h-full px-4">
645
+ {navigationGroups.map(group => renderAssistantGroup(group))}
646
+ </ScrollArea>
647
+ )}
648
+ </div>
396
649
 
397
650
  {/* Footer da sidebar - Usuário */}
398
- <div className="p-4 space-y-2">
651
+ <div className="flex-shrink-0 p-4 space-y-2">
399
652
  {/* Avatar do usuário */}
400
653
  {!expanded ? (
401
654
  <Tooltip>
@@ -14,7 +14,7 @@ import { Textarea } from './ui/textarea';
14
14
  import { Progress } from './ui/progress';
15
15
  import { Separator } from './ui/separator';
16
16
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from './ui/table';
17
- import { Settings, User, Mail, Phone, Calendar, Search, Menu, ChevronRight, Home, Users } from 'lucide-react';
17
+ import { Settings, User, Mail, Phone, Calendar, Search, Menu, ChevronRight, Home, Users, Plus, Trash2, Archive, ArrowRightLeft, History, FileEdit, Filter, Clock, Map } from 'lucide-react';
18
18
  import { Slider } from './ui/slider';
19
19
  import { toast } from 'sonner';
20
20
  import { ScrollArea } from './ui/scroll-area';
@@ -22,6 +22,7 @@ import { ThemeToggle } from './ThemeToggle';
22
22
  import { LanguageSelector } from './LanguageSelector';
23
23
  import { MapShowcase } from './examples/MapShowcase';
24
24
  import { Header } from './Header';
25
+ import { Sidebar } from './Sidebar';
25
26
  import {
26
27
  Dialog,
27
28
  DialogTrigger,
@@ -713,6 +714,134 @@ export function TemplateContent({ }: TemplateContentProps) {
713
714
 
714
715
  <Separator className="my-8" />
715
716
 
717
+ {/* Sidebar Variations */}
718
+ <section>
719
+ <h3 className="mb-4">Sidebar Variations</h3>
720
+ <Card>
721
+ <CardHeader>
722
+ <CardTitle>Sidebar Assistant Mode vs Default</CardTitle>
723
+ <CardDescription>
724
+ A Sidebar suporta flexibilidade com a propriedade variant.
725
+ </CardDescription>
726
+ </CardHeader>
727
+ <CardContent>
728
+ <Tabs defaultValue="assistant" className="w-full">
729
+ <TabsList className="mb-4">
730
+ <TabsTrigger value="assistant">Modo Assistant</TabsTrigger>
731
+ <TabsTrigger value="default">Modo Padrão</TabsTrigger>
732
+ </TabsList>
733
+
734
+ <TabsContent value="assistant">
735
+ <div className="relative h-[600px] border rounded-[var(--radius-lg)] bg-muted/20 overflow-hidden" style={{ transform: "translateZ(0)" }}>
736
+ <Sidebar
737
+ expanded={true}
738
+ onToggle={() => { }}
739
+ user={{ email: "admin@xertica.com" }}
740
+ onLogout={() => toast("Saiu")}
741
+ location={{ pathname: "/assistant/current" }}
742
+ navigate={() => { }}
743
+ variant="assistant"
744
+ search={{
745
+ show: true,
746
+ placeholder: "Pesquisar tópicos..."
747
+ }}
748
+ fixedArea={{
749
+ show: true,
750
+ content: (
751
+ <Button className="w-full bg-sidebar-primary hover:bg-sidebar-primary/90 text-sidebar-primary-foreground shadow-lg font-bold border-none transition-all duration-300 transform hover:scale-[1.02] active:scale-[0.98]">
752
+ <Plus className="w-4 h-4 mr-2" />
753
+ Nova Conversa
754
+ </Button>
755
+ )
756
+ }}
757
+ navigationGroups={[
758
+ {
759
+ id: "recent",
760
+ label: "Recentes",
761
+ icon: Clock,
762
+ items: [
763
+ {
764
+ path: "/assistant/refatoracao",
765
+ label: "Refatoração Sidebar",
766
+ icon: History,
767
+ description: "Ativa agora",
768
+ actions: [
769
+ { label: "Renomear", icon: FileEdit, onClick: () => toast("Abrir renomear...") },
770
+ {
771
+ label: "Mover",
772
+ icon: ArrowRightLeft,
773
+ children: [
774
+ { label: "Projetos Ativos", onClick: () => toast("Movido para Projetos Ativos") },
775
+ { label: "Monitoramento", onClick: () => toast("Movido para Monitoramento") },
776
+ { label: "Arquivo", onClick: () => toast("Movido para Arquivo") }
777
+ ]
778
+ },
779
+ { label: "Limpar", icon: Trash2, onClick: () => toast("Histórico Limpo!"), variant: "destructive" }
780
+ ]
781
+ },
782
+ ]
783
+ },
784
+ {
785
+ id: "projects",
786
+ label: "Monitoramento de Obras",
787
+ icon: Map,
788
+ actions: [
789
+ { label: "Nova Categoria", icon: Plus, onClick: () => toast("Criar nova categoria...") },
790
+ { label: "Arquivar Grupo", icon: Archive, onClick: () => toast("Arquivando grupo...") }
791
+ ],
792
+ items: [
793
+ {
794
+ path: "/assistant/br163",
795
+ label: "Restauração BR-163",
796
+ icon: () => <div className="w-2 h-2 rounded-full bg-yellow-500" />,
797
+ description: (
798
+ <div className="space-y-1.5 min-w-[160px]">
799
+ <Progress value={67} className="h-1.5 bg-sidebar-foreground/10" />
800
+ <div className="flex justify-between items-center text-[10px] text-sidebar-foreground/60">
801
+ <span>Cuiabá, MT</span>
802
+ <span>67%</span>
803
+ </div>
804
+ </div>
805
+ )
806
+ }
807
+ ]
808
+ }
809
+ ]}
810
+ />
811
+ <div className="absolute inset-y-0 right-0 left-64 p-8 flex items-center justify-center">
812
+ <p className="text-muted-foreground text-center">Conteúdo do Assistant Mode</p>
813
+ </div>
814
+ </div>
815
+ </TabsContent>
816
+
817
+ <TabsContent value="default">
818
+ <div className="relative h-[600px] border rounded-[var(--radius-lg)] bg-muted/20 overflow-hidden" style={{ transform: "translateZ(0)" }}>
819
+ <Sidebar
820
+ expanded={true}
821
+ onToggle={() => { }}
822
+ user={{ email: "admin@xertica.com" }}
823
+ onLogout={() => toast("Saiu")}
824
+ location={{ pathname: "/home" }}
825
+ navigate={() => { }}
826
+ variant="default"
827
+ routes={[
828
+ { path: "/home", label: "Início", icon: Home },
829
+ { path: "/dashboard", label: "Dashboard", icon: Users },
830
+ { path: "/settings", label: "Configurações", icon: Settings },
831
+ ]}
832
+ />
833
+ <div className="absolute inset-y-0 right-0 left-64 p-8 flex items-center justify-center">
834
+ <p className="text-muted-foreground text-center">Navegação Tradicional do Sistema</p>
835
+ </div>
836
+ </div>
837
+ </TabsContent>
838
+ </Tabs>
839
+ </CardContent>
840
+ </Card>
841
+ </section>
842
+
843
+ <Separator className="my-8" />
844
+
716
845
  {/* Footer Note */}
717
846
  <Card className="mt-8">
718
847
  <CardHeader>