xertica-ui 1.0.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.
Files changed (141) hide show
  1. package/App.tsx +182 -0
  2. package/README.md +330 -0
  3. package/assets/xertica-logo.svg +38 -0
  4. package/assets/xertica-x-logo.svg +21 -0
  5. package/bin/cli.ts +193 -0
  6. package/components/AssistenteXertica.tsx +2003 -0
  7. package/components/AudioPlayer.tsx +203 -0
  8. package/components/CodeBlock.tsx +242 -0
  9. package/components/DocumentEditor.tsx +504 -0
  10. package/components/ForgotPasswordPage.tsx +170 -0
  11. package/components/FormattedDocument.tsx +87 -0
  12. package/components/HomeContent.tsx +123 -0
  13. package/components/HomePage.tsx +70 -0
  14. package/components/LanguageSelector.tsx +54 -0
  15. package/components/LoginPage.tsx +199 -0
  16. package/components/MarkdownMessage.tsx +62 -0
  17. package/components/ModernChatInput.tsx +502 -0
  18. package/components/PodcastPlayer.tsx +409 -0
  19. package/components/ResetPasswordPage.tsx +234 -0
  20. package/components/Sidebar.tsx +489 -0
  21. package/components/TemplateContent.tsx +629 -0
  22. package/components/TemplatePage.tsx +70 -0
  23. package/components/ThemeToggle.tsx +65 -0
  24. package/components/VerifyEmailPage.tsx +187 -0
  25. package/components/XerticaLogo.tsx +69 -0
  26. package/components/XerticaOrbe.tsx +1339 -0
  27. package/components/XerticaXLogo.tsx +53 -0
  28. package/components/examples/DrawingMapExample.tsx +530 -0
  29. package/components/examples/FilterableMapExample.tsx +380 -0
  30. package/components/examples/LocationPickerExample.tsx +330 -0
  31. package/components/examples/MapExamples.tsx +280 -0
  32. package/components/examples/MapShowcase.tsx +446 -0
  33. package/components/examples/RouteMapExamples.tsx +329 -0
  34. package/components/examples/SimpleFilterableMap.tsx +192 -0
  35. package/components/examples/index.ts +52 -0
  36. package/components/figma/ImageWithFallback.tsx +27 -0
  37. package/components/index.ts +44 -0
  38. package/components/media/AudioPlayer.tsx +278 -0
  39. package/components/media/FloatingMediaWrapper.tsx +166 -0
  40. package/components/media/VideoPlayer.tsx +285 -0
  41. package/components/ui/accordion.tsx +66 -0
  42. package/components/ui/alert-dialog.tsx +159 -0
  43. package/components/ui/alert.tsx +91 -0
  44. package/components/ui/aspect-ratio.tsx +11 -0
  45. package/components/ui/avatar.tsx +65 -0
  46. package/components/ui/badge.tsx +55 -0
  47. package/components/ui/breadcrumb.tsx +109 -0
  48. package/components/ui/button.tsx +78 -0
  49. package/components/ui/calendar.tsx +235 -0
  50. package/components/ui/card.tsx +92 -0
  51. package/components/ui/carousel.tsx +241 -0
  52. package/components/ui/chart.tsx +353 -0
  53. package/components/ui/checkbox.tsx +32 -0
  54. package/components/ui/collapsible.tsx +33 -0
  55. package/components/ui/command.tsx +177 -0
  56. package/components/ui/context-menu.tsx +252 -0
  57. package/components/ui/dialog.tsx +138 -0
  58. package/components/ui/drawer.tsx +134 -0
  59. package/components/ui/dropdown-menu.tsx +257 -0
  60. package/components/ui/empty.tsx +90 -0
  61. package/components/ui/file-upload.tsx +152 -0
  62. package/components/ui/form.tsx +195 -0
  63. package/components/ui/google-maps-loader.tsx +379 -0
  64. package/components/ui/hover-card.tsx +44 -0
  65. package/components/ui/index.ts +242 -0
  66. package/components/ui/input-otp.tsx +77 -0
  67. package/components/ui/input.tsx +38 -0
  68. package/components/ui/label.tsx +24 -0
  69. package/components/ui/map-config.ts +12 -0
  70. package/components/ui/map-layers.tsx +129 -0
  71. package/components/ui/map.exports.ts +31 -0
  72. package/components/ui/map.tsx +412 -0
  73. package/components/ui/menubar.tsx +276 -0
  74. package/components/ui/navigation-menu.tsx +162 -0
  75. package/components/ui/notification-badge.tsx +61 -0
  76. package/components/ui/page-header.tsx +229 -0
  77. package/components/ui/pagination.tsx +127 -0
  78. package/components/ui/popover.tsx +48 -0
  79. package/components/ui/progress.tsx +31 -0
  80. package/components/ui/radio-group.tsx +56 -0
  81. package/components/ui/rating.tsx +102 -0
  82. package/components/ui/resizable.tsx +405 -0
  83. package/components/ui/route-map.tsx +246 -0
  84. package/components/ui/scroll-area.tsx +58 -0
  85. package/components/ui/search.tsx +70 -0
  86. package/components/ui/select.tsx +176 -0
  87. package/components/ui/separator.tsx +28 -0
  88. package/components/ui/sheet.tsx +138 -0
  89. package/components/ui/sidebar.tsx +726 -0
  90. package/components/ui/simple-map.tsx +92 -0
  91. package/components/ui/skeleton.tsx +13 -0
  92. package/components/ui/slider.tsx +58 -0
  93. package/components/ui/sonner.tsx +77 -0
  94. package/components/ui/stats-card.tsx +84 -0
  95. package/components/ui/stepper.tsx +126 -0
  96. package/components/ui/switch.tsx +34 -0
  97. package/components/ui/table.tsx +116 -0
  98. package/components/ui/tabs.tsx +66 -0
  99. package/components/ui/textarea.tsx +26 -0
  100. package/components/ui/timeline.tsx +140 -0
  101. package/components/ui/toggle-group.tsx +71 -0
  102. package/components/ui/toggle.tsx +46 -0
  103. package/components/ui/tooltip.tsx +61 -0
  104. package/components/ui/tree-view.tsx +123 -0
  105. package/components/ui/use-mobile.ts +24 -0
  106. package/components/ui/utils.ts +6 -0
  107. package/components/ui/xertica-assistant.tsx +1420 -0
  108. package/contexts/ApiKeyContext.tsx +123 -0
  109. package/contexts/AssistenteContext.tsx +118 -0
  110. package/contexts/BrandColorsContext.tsx +551 -0
  111. package/contexts/LanguageContext.tsx +36 -0
  112. package/contexts/ThemeContext.tsx +85 -0
  113. package/dist/cli.js +20922 -0
  114. package/eslint.config.js +41 -0
  115. package/guidelines/Guidelines.md +61 -0
  116. package/hooks/useTheme.ts +4 -0
  117. package/imports/Podcast.tsx +389 -0
  118. package/imports/XerticaAi.tsx +46 -0
  119. package/imports/XerticaX.tsx +20 -0
  120. package/imports/svg-aueiaqngck.ts +11 -0
  121. package/imports/svg-v9krss1ozd.ts +16 -0
  122. package/imports/svg-vhrdofe3qe.ts +5 -0
  123. package/index.css +4448 -0
  124. package/index.html +14 -0
  125. package/main.tsx +10 -0
  126. package/package.json +119 -0
  127. package/postcss.config.js +6 -0
  128. package/routes.tsx +33 -0
  129. package/styles/globals.css +15 -0
  130. package/styles/xertica/app-overrides/chat.css +61 -0
  131. package/styles/xertica/app-overrides/scrollbar.css +33 -0
  132. package/styles/xertica/base.css +70 -0
  133. package/styles/xertica/integrations/google-maps.css +76 -0
  134. package/styles/xertica/integrations/sonner.css +73 -0
  135. package/styles/xertica/theme-map.css +88 -0
  136. package/styles/xertica/tokens.css +190 -0
  137. package/tsconfig.json +31 -0
  138. package/tsconfig.node.json +10 -0
  139. package/utils/gemini.ts +140 -0
  140. package/vite-env.d.ts +12 -0
  141. package/vite.config.ts +36 -0
@@ -0,0 +1,140 @@
1
+ import * as React from "react";
2
+ import { cn } from "./utils";
3
+
4
+ const Timeline = React.forwardRef<
5
+ HTMLOListElement,
6
+ React.HTMLAttributes<HTMLOListElement>
7
+ >(({ className, ...props }, ref) => (
8
+ <ol
9
+ ref={ref}
10
+ className={cn("relative border-l border-border", className)}
11
+ {...props}
12
+ />
13
+ ));
14
+ Timeline.displayName = "Timeline";
15
+
16
+ const TimelineItem = React.forwardRef<
17
+ HTMLLIElement,
18
+ React.HTMLAttributes<HTMLLIElement>
19
+ >(({ className, ...props }, ref) => (
20
+ <li
21
+ ref={ref}
22
+ className={cn("mb-10 ml-6", className)}
23
+ {...props}
24
+ />
25
+ ));
26
+ TimelineItem.displayName = "TimelineItem";
27
+
28
+ const TimelineDot = React.forwardRef<
29
+ HTMLDivElement,
30
+ React.HTMLAttributes<HTMLDivElement> & {
31
+ variant?: "default" | "primary" | "success" | "warning" | "destructive";
32
+ icon?: React.ReactNode;
33
+ }
34
+ >(({ className, variant = "default", icon, children, ...props }, ref) => {
35
+ const variantStyles = {
36
+ default: "bg-muted border-border",
37
+ primary: "bg-primary border-primary",
38
+ success: "bg-[rgb(5,150,105)] border-[rgb(5,150,105)]",
39
+ warning: "bg-[rgb(245,158,11)] border-[rgb(245,158,11)]",
40
+ destructive: "bg-destructive border-destructive",
41
+ };
42
+
43
+ const iconColorStyles = {
44
+ default: "text-muted-foreground",
45
+ primary: "text-primary-foreground",
46
+ success: "text-white",
47
+ warning: "text-white",
48
+ destructive: "text-destructive-foreground",
49
+ };
50
+
51
+ // Se tem ícone, usar tamanho maior
52
+ if (icon || children) {
53
+ return (
54
+ <div
55
+ ref={ref}
56
+ className={cn(
57
+ "absolute -left-[17px] mt-0.5 h-8 w-8 rounded-full border-2 flex items-center justify-center",
58
+ variantStyles[variant],
59
+ className
60
+ )}
61
+ {...props}
62
+ >
63
+ <span className={cn("h-4 w-4", iconColorStyles[variant])}>
64
+ {icon || children}
65
+ </span>
66
+ </div>
67
+ );
68
+ }
69
+
70
+ return (
71
+ <div
72
+ ref={ref}
73
+ className={cn(
74
+ "absolute -left-[9px] mt-1.5 h-4 w-4 rounded-full border-2",
75
+ variantStyles[variant],
76
+ className
77
+ )}
78
+ {...props}
79
+ />
80
+ );
81
+ });
82
+ TimelineDot.displayName = "TimelineDot";
83
+
84
+ const TimelineContent = React.forwardRef<
85
+ HTMLDivElement,
86
+ React.HTMLAttributes<HTMLDivElement>
87
+ >(({ className, ...props }, ref) => (
88
+ <div
89
+ ref={ref}
90
+ className={cn("", className)}
91
+ {...props}
92
+ />
93
+ ));
94
+ TimelineContent.displayName = "TimelineContent";
95
+
96
+ const TimelineHeading = React.forwardRef<
97
+ HTMLHeadingElement,
98
+ React.HTMLAttributes<HTMLHeadingElement>
99
+ >(({ className, ...props }, ref) => (
100
+ <h3
101
+ ref={ref}
102
+ className={cn("mb-1 text-foreground", className)}
103
+ {...props}
104
+ />
105
+ ));
106
+ TimelineHeading.displayName = "TimelineHeading";
107
+
108
+ const TimelineTime = React.forwardRef<
109
+ HTMLTimeElement,
110
+ React.HTMLAttributes<HTMLTimeElement>
111
+ >(({ className, ...props }, ref) => (
112
+ <time
113
+ ref={ref}
114
+ className={cn("mb-2 block text-muted-foreground", className)}
115
+ {...props}
116
+ />
117
+ ));
118
+ TimelineTime.displayName = "TimelineTime";
119
+
120
+ const TimelineDescription = React.forwardRef<
121
+ HTMLParagraphElement,
122
+ React.HTMLAttributes<HTMLParagraphElement>
123
+ >(({ className, ...props }, ref) => (
124
+ <p
125
+ ref={ref}
126
+ className={cn("text-muted-foreground", className)}
127
+ {...props}
128
+ />
129
+ ));
130
+ TimelineDescription.displayName = "TimelineDescription";
131
+
132
+ export {
133
+ Timeline,
134
+ TimelineItem,
135
+ TimelineDot,
136
+ TimelineContent,
137
+ TimelineHeading,
138
+ TimelineTime,
139
+ TimelineDescription,
140
+ };
@@ -0,0 +1,71 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"
5
+ import { type VariantProps } from "class-variance-authority"
6
+
7
+ import { cn } from "./utils"
8
+ import { toggleVariants } from "./toggle"
9
+
10
+ const ToggleGroupContext = React.createContext<
11
+ VariantProps<typeof toggleVariants>
12
+ >({
13
+ size: "default",
14
+ variant: "default",
15
+ })
16
+
17
+ const ToggleGroup = React.forwardRef<
18
+ React.ElementRef<typeof ToggleGroupPrimitive.Root>,
19
+ React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
20
+ VariantProps<typeof toggleVariants>
21
+ >(({ className, variant, size, children, ...props }, ref) => (
22
+ <ToggleGroupPrimitive.Root
23
+ ref={ref}
24
+ data-slot="toggle-group"
25
+ data-variant={variant}
26
+ data-size={size}
27
+ className={cn(
28
+ "group/toggle-group flex w-fit items-center rounded-md data-[variant=outline]:shadow-xs",
29
+ className
30
+ )}
31
+ {...props}
32
+ >
33
+ <ToggleGroupContext.Provider value={{ variant, size }}>
34
+ {children}
35
+ </ToggleGroupContext.Provider>
36
+ </ToggleGroupPrimitive.Root>
37
+ ))
38
+
39
+ ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName
40
+
41
+ const ToggleGroupItem = React.forwardRef<
42
+ React.ElementRef<typeof ToggleGroupPrimitive.Item>,
43
+ React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
44
+ VariantProps<typeof toggleVariants>
45
+ >(({ className, children, variant, size, ...props }, ref) => {
46
+ const context = React.useContext(ToggleGroupContext)
47
+
48
+ return (
49
+ <ToggleGroupPrimitive.Item
50
+ ref={ref}
51
+ data-slot="toggle-group-item"
52
+ data-variant={context.variant || variant}
53
+ data-size={context.size || size}
54
+ className={cn(
55
+ toggleVariants({
56
+ variant: context.variant || variant,
57
+ size: context.size || size,
58
+ }),
59
+ "min-w-0 flex-1 shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l",
60
+ className
61
+ )}
62
+ {...props}
63
+ >
64
+ {children}
65
+ </ToggleGroupPrimitive.Item>
66
+ )
67
+ })
68
+
69
+ ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName
70
+
71
+ export { ToggleGroup, ToggleGroupItem }
@@ -0,0 +1,46 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as TogglePrimitive from "@radix-ui/react-toggle"
5
+ import { cva, type VariantProps } from "class-variance-authority"
6
+
7
+ import { cn } from "./utils"
8
+
9
+ const toggleVariants = cva(
10
+ "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap",
11
+ {
12
+ variants: {
13
+ variant: {
14
+ default: "bg-transparent",
15
+ outline:
16
+ "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
17
+ },
18
+ size: {
19
+ default: "h-9 px-2 min-w-9",
20
+ sm: "h-8 px-1.5 min-w-8",
21
+ lg: "h-10 px-2.5 min-w-10",
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ variant: "default",
26
+ size: "default",
27
+ },
28
+ }
29
+ )
30
+
31
+ const Toggle = React.forwardRef<
32
+ React.ElementRef<typeof TogglePrimitive.Root>,
33
+ React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
34
+ VariantProps<typeof toggleVariants>
35
+ >(({ className, variant, size, ...props }, ref) => (
36
+ <TogglePrimitive.Root
37
+ ref={ref}
38
+ data-slot="toggle"
39
+ className={cn(toggleVariants({ variant, size, className }))}
40
+ {...props}
41
+ />
42
+ ))
43
+
44
+ Toggle.displayName = TogglePrimitive.Root.displayName
45
+
46
+ export { Toggle, toggleVariants }
@@ -0,0 +1,61 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
5
+
6
+ import { cn } from "./utils";
7
+
8
+ function TooltipProvider({
9
+ delayDuration = 0,
10
+ ...props
11
+ }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
12
+ return (
13
+ <TooltipPrimitive.Provider
14
+ data-slot="tooltip-provider"
15
+ delayDuration={delayDuration}
16
+ {...props}
17
+ />
18
+ );
19
+ }
20
+
21
+ function Tooltip({
22
+ ...props
23
+ }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
24
+ return (
25
+ <TooltipProvider>
26
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
27
+ </TooltipProvider>
28
+ );
29
+ }
30
+
31
+ function TooltipTrigger({
32
+ ...props
33
+ }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
34
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
35
+ }
36
+
37
+ function TooltipContent({
38
+ className,
39
+ sideOffset = 0,
40
+ children,
41
+ ...props
42
+ }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
43
+ return (
44
+ <TooltipPrimitive.Portal>
45
+ <TooltipPrimitive.Content
46
+ data-slot="tooltip-content"
47
+ sideOffset={sideOffset}
48
+ className={cn(
49
+ "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
50
+ className,
51
+ )}
52
+ {...props}
53
+ >
54
+ {children}
55
+ <TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
56
+ </TooltipPrimitive.Content>
57
+ </TooltipPrimitive.Portal>
58
+ );
59
+ }
60
+
61
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -0,0 +1,123 @@
1
+ import * as React from "react";
2
+ import { ChevronRight, ChevronDown } from "lucide-react";
3
+ import { cn } from "./utils";
4
+
5
+ export interface TreeNode {
6
+ id: string;
7
+ label: string;
8
+ icon?: React.ReactNode;
9
+ children?: TreeNode[];
10
+ }
11
+
12
+ interface TreeViewProps extends React.HTMLAttributes<HTMLDivElement> {
13
+ data: TreeNode[];
14
+ onNodeClick?: (node: TreeNode) => void;
15
+ defaultExpanded?: string[];
16
+ }
17
+
18
+ const TreeView = React.forwardRef<HTMLDivElement, TreeViewProps>(
19
+ ({ className, data, onNodeClick, defaultExpanded = [], ...props }, ref) => {
20
+ const [expanded, setExpanded] = React.useState<Set<string>>(
21
+ new Set(defaultExpanded)
22
+ );
23
+
24
+ const toggleExpand = (nodeId: string) => {
25
+ setExpanded((prev) => {
26
+ const newSet = new Set(prev);
27
+ if (newSet.has(nodeId)) {
28
+ newSet.delete(nodeId);
29
+ } else {
30
+ newSet.add(nodeId);
31
+ }
32
+ return newSet;
33
+ });
34
+ };
35
+
36
+ return (
37
+ <div ref={ref} className={cn("w-full", className)} {...props}>
38
+ {data.map((node) => (
39
+ <TreeNodeComponent
40
+ key={node.id}
41
+ node={node}
42
+ level={0}
43
+ expanded={expanded}
44
+ onToggle={toggleExpand}
45
+ onNodeClick={onNodeClick}
46
+ />
47
+ ))}
48
+ </div>
49
+ );
50
+ }
51
+ );
52
+ TreeView.displayName = "TreeView";
53
+
54
+ interface TreeNodeComponentProps {
55
+ node: TreeNode;
56
+ level: number;
57
+ expanded: Set<string>;
58
+ onToggle: (nodeId: string) => void;
59
+ onNodeClick?: (node: TreeNode) => void;
60
+ }
61
+
62
+ const TreeNodeComponent: React.FC<TreeNodeComponentProps> = ({
63
+ node,
64
+ level,
65
+ expanded,
66
+ onToggle,
67
+ onNodeClick,
68
+ }) => {
69
+ const hasChildren = node.children && node.children.length > 0;
70
+ const isExpanded = expanded.has(node.id);
71
+
72
+ const handleClick = () => {
73
+ if (hasChildren) {
74
+ onToggle(node.id);
75
+ }
76
+ onNodeClick?.(node);
77
+ };
78
+
79
+ return (
80
+ <div>
81
+ <button
82
+ onClick={handleClick}
83
+ className={cn(
84
+ "flex w-full items-center gap-2 rounded-[var(--radius)] px-2 py-1.5 text-left transition-colors hover:bg-muted",
85
+ "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
86
+ )}
87
+ style={{ paddingLeft: `${level * 1.5 + 0.5}rem` }}
88
+ >
89
+ {hasChildren && (
90
+ <span className="flex-shrink-0 text-muted-foreground">
91
+ {isExpanded ? (
92
+ <ChevronDown className="h-4 w-4" />
93
+ ) : (
94
+ <ChevronRight className="h-4 w-4" />
95
+ )}
96
+ </span>
97
+ )}
98
+ {!hasChildren && <span className="w-4" />}
99
+ {node.icon && (
100
+ <span className="flex-shrink-0 text-muted-foreground">{node.icon}</span>
101
+ )}
102
+ <span className="flex-1 text-foreground">{node.label}</span>
103
+ </button>
104
+ {hasChildren && isExpanded && (
105
+ <div>
106
+ {node.children!.map((child) => (
107
+ <TreeNodeComponent
108
+ key={child.id}
109
+ node={child}
110
+ level={level + 1}
111
+ expanded={expanded}
112
+ onToggle={onToggle}
113
+ onNodeClick={onNodeClick}
114
+ />
115
+ ))}
116
+ </div>
117
+ )}
118
+ </div>
119
+ );
120
+ };
121
+
122
+ export { TreeView };
123
+ export type { TreeViewProps, TreeNode };
@@ -0,0 +1,24 @@
1
+ import * as React from "react";
2
+
3
+ const MOBILE_BREAKPOINT = 768;
4
+
5
+ export function useIsMobile() {
6
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
7
+ undefined,
8
+ );
9
+
10
+ React.useEffect(() => {
11
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
12
+ const onChange = () => {
13
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
14
+ };
15
+ mql.addEventListener("change", onChange);
16
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
17
+ return () => mql.removeEventListener("change", onChange);
18
+ }, []);
19
+
20
+ return !!isMobile;
21
+ }
22
+
23
+ // Alias for compatibility
24
+ export const useMobile = useIsMobile;
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }