@gunjo/ui 0.0.1-alpha.1 → 0.0.1-alpha.2

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 (224) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +90 -0
  3. package/README.md +52 -91
  4. package/package.json +47 -6
  5. package/src/components/display/Accordion.tsx +185 -0
  6. package/src/components/display/AccordionGroup.tsx +155 -0
  7. package/src/components/display/ActionDataTable.tsx +413 -0
  8. package/src/components/display/ActivityTimelineCard.tsx +483 -0
  9. package/src/components/display/AnalyticsCard.tsx +167 -0
  10. package/src/components/display/AssetCard.tsx +242 -0
  11. package/src/components/display/AssetGrid.tsx +164 -0
  12. package/src/components/display/Avatar.tsx +127 -0
  13. package/src/components/display/AvatarGroup.tsx +131 -0
  14. package/src/components/{atoms → display}/Badge.tsx +3 -3
  15. package/src/components/display/BarChart.tsx +247 -0
  16. package/src/components/{molecules → display}/Card.tsx +1 -1
  17. package/src/components/display/Carousel.tsx +593 -0
  18. package/src/components/display/ChartLegend.tsx +124 -0
  19. package/src/components/display/ChatMessage.tsx +382 -0
  20. package/src/components/display/ChoroplethMap.tsx +613 -0
  21. package/src/components/display/Code.tsx +42 -0
  22. package/src/components/display/CodeBlock.tsx +338 -0
  23. package/src/components/display/ColorSwatch.tsx +71 -0
  24. package/src/components/display/ConcentricProgressCard.tsx +545 -0
  25. package/src/components/display/DataTable.tsx +522 -0
  26. package/src/components/display/DistributionBar.tsx +102 -0
  27. package/src/components/display/DocNote.tsx +36 -0
  28. package/src/components/display/DonutChart.tsx +257 -0
  29. package/src/components/display/EmptyState.tsx +44 -0
  30. package/src/components/display/FileTree.tsx +180 -0
  31. package/src/components/display/GaugeChart.tsx +219 -0
  32. package/src/components/display/HeatmapChart.tsx +266 -0
  33. package/src/components/display/Icon.tsx +66 -0
  34. package/src/components/display/ImagePreview.tsx +140 -0
  35. package/src/components/{atoms → display}/Img.tsx +46 -12
  36. package/src/components/display/LabeledDonutCard.tsx +475 -0
  37. package/src/components/display/LineChart.tsx +464 -0
  38. package/src/components/{molecules → display}/List.tsx +20 -13
  39. package/src/components/display/MarkdownRenderer.tsx +157 -0
  40. package/src/components/display/MetadataList.tsx +81 -0
  41. package/src/components/display/MiniDistributionBarCard.tsx +314 -0
  42. package/src/components/display/PieChart.tsx +234 -0
  43. package/src/components/display/QuadrantMatrix.tsx +330 -0
  44. package/src/components/display/RadarChart.tsx +335 -0
  45. package/src/components/display/RadialBarChart.tsx +264 -0
  46. package/src/components/display/RetentionCohortCard.tsx +350 -0
  47. package/src/components/display/RibbonChart.tsx +618 -0
  48. package/src/components/display/SearchableAccordion.tsx +270 -0
  49. package/src/components/display/SegmentTimelineCard.tsx +452 -0
  50. package/src/components/display/SegmentedGaugeCard.tsx +607 -0
  51. package/src/components/display/Spacer.tsx +51 -0
  52. package/src/components/display/SparklineChart.tsx +394 -0
  53. package/src/components/display/StackedBarChart.tsx +393 -0
  54. package/src/components/display/Statistic.tsx +70 -0
  55. package/src/components/{molecules → display}/Table.tsx +22 -7
  56. package/src/components/display/Tag.tsx +80 -0
  57. package/src/components/display/TagEditor.tsx +141 -0
  58. package/src/components/display/Timeline.tsx +121 -0
  59. package/src/components/{atoms → display}/ToolPill.tsx +42 -18
  60. package/src/components/display/TreeView.tsx +226 -0
  61. package/src/components/display/chart-tooltip.tsx +423 -0
  62. package/src/components/display/chart-utils.ts +71 -0
  63. package/src/components/display/circular-chart-utils.ts +147 -0
  64. package/src/components/display/generated/default-variant-keys.ts +90 -0
  65. package/src/components/display/generated/variant-keys.ts +169 -0
  66. package/src/components/{atoms → feedback}/Alert.tsx +12 -5
  67. package/src/components/feedback/Banner.tsx +90 -0
  68. package/src/components/{molecules → feedback}/NotificationCenter.tsx +64 -31
  69. package/src/components/feedback/ProgressWidget.tsx +44 -0
  70. package/src/components/{atoms → feedback}/Spinner.tsx +2 -2
  71. package/src/components/{molecules → feedback}/StatusBar.tsx +4 -4
  72. package/src/components/feedback/StatusScreen.tsx +148 -0
  73. package/src/components/{molecules → feedback}/Stepper.tsx +10 -5
  74. package/src/components/feedback/Toast.tsx +108 -0
  75. package/src/components/feedback/ToastProvider.tsx +78 -0
  76. package/src/components/feedback/generated/default-variant-keys.ts +16 -0
  77. package/src/components/feedback/generated/variant-keys.ts +21 -0
  78. package/src/components/generated/component-manifest.ts +1568 -454
  79. package/src/components/generated/component-style-hints.ts +1958 -718
  80. package/src/components/{atoms → inputs}/ButtonVariants.ts +13 -3
  81. package/src/components/inputs/Calendar.tsx +212 -0
  82. package/src/components/inputs/ChatComposer.tsx +75 -0
  83. package/src/components/inputs/ChatInput.tsx +528 -0
  84. package/src/components/{atoms → inputs}/Checkbox.tsx +2 -2
  85. package/src/components/inputs/Combobox.tsx +175 -0
  86. package/src/components/inputs/CopyButton.tsx +187 -0
  87. package/src/components/inputs/DatePicker.tsx +519 -0
  88. package/src/components/inputs/DateRangePicker.tsx +878 -0
  89. package/src/components/inputs/EditableField.tsx +182 -0
  90. package/src/components/{organisms → inputs}/FileUploader.tsx +24 -9
  91. package/src/components/inputs/FilterButton.tsx +163 -0
  92. package/src/components/{molecules → inputs}/Form.tsx +20 -3
  93. package/src/components/{atoms → inputs}/Input.tsx +2 -0
  94. package/src/components/inputs/InputOTP.tsx +75 -0
  95. package/src/components/inputs/Mention.tsx +279 -0
  96. package/src/components/inputs/NumberInput.tsx +109 -0
  97. package/src/components/inputs/PasswordGroup.tsx +138 -0
  98. package/src/components/inputs/PasswordInput.tsx +74 -0
  99. package/src/components/inputs/PasswordRequirementList.tsx +96 -0
  100. package/src/components/inputs/PasswordStrengthMeter.tsx +93 -0
  101. package/src/components/inputs/PhoneInput.tsx +99 -0
  102. package/src/components/inputs/PostalCodeInput.tsx +98 -0
  103. package/src/components/inputs/RangeSlider.tsx +129 -0
  104. package/src/components/inputs/SearchInput.tsx +76 -0
  105. package/src/components/inputs/Select.tsx +39 -0
  106. package/src/components/{atoms → inputs}/Slider.tsx +18 -5
  107. package/src/components/{molecules → inputs}/SortButton.tsx +5 -2
  108. package/src/components/{atoms → inputs}/Switch.tsx +15 -4
  109. package/src/components/inputs/TagInput.tsx +114 -0
  110. package/src/components/{atoms → inputs}/Textarea.tsx +1 -0
  111. package/src/components/inputs/TimePicker.tsx +150 -0
  112. package/src/components/inputs/Toggle.tsx +48 -0
  113. package/src/components/{atoms → inputs}/ToggleGroup.tsx +2 -2
  114. package/src/components/inputs/TooltipButton.tsx +148 -0
  115. package/src/components/inputs/VoiceInputButton.tsx +317 -0
  116. package/src/components/inputs/calendar-holidays.ts +56 -0
  117. package/src/components/inputs/generated/default-variant-keys.ts +32 -0
  118. package/src/components/{atoms → inputs}/generated/variant-keys.ts +19 -27
  119. package/src/components/layout/AspectRatio.tsx +12 -0
  120. package/src/components/layout/AssetInspectorPanel.tsx +416 -0
  121. package/src/components/layout/Cluster.tsx +56 -0
  122. package/src/components/layout/CollapsiblePanelToggle.tsx +94 -0
  123. package/src/components/layout/Container.tsx +43 -0
  124. package/src/components/layout/DeviceFrame.tsx +227 -0
  125. package/src/components/layout/Grid.tsx +65 -0
  126. package/src/components/layout/HStack.tsx +73 -0
  127. package/src/components/{organisms → layout}/InspectorPanel.tsx +6 -5
  128. package/src/components/layout/MarqueeFrame.tsx +158 -0
  129. package/src/components/layout/Resizable.tsx +94 -0
  130. package/src/components/layout/ScrollArea.tsx +71 -0
  131. package/src/components/{organisms → layout}/SpatialCanvas.tsx +12 -7
  132. package/src/components/layout/VStack.tsx +69 -0
  133. package/src/components/layout/generated/default-variant-keys.ts +16 -0
  134. package/src/components/layout/generated/variant-keys.ts +21 -0
  135. package/src/components/{molecules → navigation}/Breadcrumb.tsx +5 -4
  136. package/src/components/navigation/Command.tsx +266 -0
  137. package/src/components/navigation/CommandPalette.tsx +83 -0
  138. package/src/components/navigation/DocumentPager.tsx +171 -0
  139. package/src/components/navigation/Footer.tsx +88 -0
  140. package/src/components/navigation/Header.tsx +80 -0
  141. package/src/components/{molecules → navigation}/Menubar.tsx +45 -12
  142. package/src/components/navigation/NavigationMenu.tsx +128 -0
  143. package/src/components/navigation/PageAside.tsx +84 -0
  144. package/src/components/{molecules → navigation}/Pagination.tsx +60 -7
  145. package/src/components/{organisms → navigation}/RightRail.tsx +1 -1
  146. package/src/components/navigation/Sidebar.tsx +223 -0
  147. package/src/components/navigation/SidebarItem.tsx +160 -0
  148. package/src/components/{molecules → navigation}/Tabs.tsx +2 -2
  149. package/src/components/navigation/TextLink.tsx +71 -0
  150. package/src/components/navigation/generated/default-variant-keys.ts +12 -0
  151. package/src/components/navigation/generated/variant-keys.ts +13 -0
  152. package/src/components/overlay/AIChatInput.tsx +5 -0
  153. package/src/components/overlay/AIChatMessage.tsx +6 -0
  154. package/src/components/overlay/AlertDialog.tsx +145 -0
  155. package/src/components/overlay/ChatPanel.tsx +180 -0
  156. package/src/components/{molecules → overlay}/ContextMenu.tsx +65 -29
  157. package/src/components/{molecules → overlay}/Dialog.tsx +21 -13
  158. package/src/components/overlay/Drawer.tsx +131 -0
  159. package/src/components/{molecules → overlay}/DropdownMenu.tsx +52 -17
  160. package/src/components/overlay/FloatingPanel.tsx +90 -0
  161. package/src/components/overlay/HoverCard.tsx +36 -0
  162. package/src/components/overlay/MediaLightbox.tsx +403 -0
  163. package/src/components/overlay/MediaPickerDialog.tsx +198 -0
  164. package/src/components/overlay/Modal.tsx +103 -0
  165. package/src/components/overlay/OnboardingFlow.tsx +172 -0
  166. package/src/components/overlay/Popover.tsx +36 -0
  167. package/src/components/overlay/ShareModal.tsx +324 -0
  168. package/src/components/{molecules → overlay}/Sheet.tsx +76 -19
  169. package/src/components/overlay/Tooltip.tsx +130 -0
  170. package/src/components/overlay/generated/default-variant-keys.ts +14 -0
  171. package/src/components/overlay/generated/variant-keys.ts +17 -0
  172. package/src/components/patterns/BlogTemplate.tsx +46 -0
  173. package/src/components/{templates → patterns}/DashboardTemplate.tsx +2 -2
  174. package/src/components/patterns/DocsTemplate.tsx +41 -0
  175. package/src/components/{templates → patterns}/MediaLibraryTemplate.tsx +1 -1
  176. package/src/components/patterns/OnboardingTemplate.tsx +32 -0
  177. package/src/components/patterns/PricingTemplate.tsx +106 -0
  178. package/src/globals.css +173 -22
  179. package/src/index.ts +177 -76
  180. package/tailwind-theme-extend.cjs +48 -3
  181. package/design/atoms-metadata.json +0 -82
  182. package/design/molecules-metadata.json +0 -130
  183. package/design/organisms-metadata.json +0 -38
  184. package/design/templates-metadata.json +0 -38
  185. package/src/components/atoms/Avatar.tsx +0 -57
  186. package/src/components/atoms/Select.tsx +0 -28
  187. package/src/components/atoms/generated/default-variant-keys.ts +0 -36
  188. package/src/components/molecules/AIChatInput.tsx +0 -140
  189. package/src/components/molecules/AIChatMessage.tsx +0 -109
  190. package/src/components/molecules/Accordion.tsx +0 -99
  191. package/src/components/molecules/Calendar.tsx +0 -60
  192. package/src/components/molecules/Carousel.tsx +0 -261
  193. package/src/components/molecules/Command.tsx +0 -152
  194. package/src/components/molecules/FilterButton.tsx +0 -133
  195. package/src/components/molecules/HoverCard.tsx +0 -29
  196. package/src/components/molecules/Modal.tsx +0 -66
  197. package/src/components/molecules/Popover.tsx +0 -31
  198. package/src/components/molecules/ProgressWidget.tsx +0 -40
  199. package/src/components/molecules/Resizable.tsx +0 -47
  200. package/src/components/molecules/ScrollArea.tsx +0 -48
  201. package/src/components/molecules/SidebarItem.tsx +0 -134
  202. package/src/components/molecules/Toast.tsx +0 -57
  203. package/src/components/molecules/Tooltip.tsx +0 -30
  204. package/src/components/molecules/generated/default-variant-keys.ts +0 -22
  205. package/src/components/molecules/generated/variant-keys.ts +0 -33
  206. package/src/components/organisms/CommandPalette.tsx +0 -58
  207. package/src/components/organisms/FloatingPanel.tsx +0 -46
  208. package/src/components/organisms/ShareModal.tsx +0 -182
  209. package/src/components/organisms/ToastProvider.tsx +0 -49
  210. /package/src/components/{atoms → display}/Kbd.tsx +0 -0
  211. /package/src/components/{atoms → display}/Separator.tsx +0 -0
  212. /package/src/components/{atoms → display}/Skeleton.tsx +0 -0
  213. /package/src/components/{atoms → feedback}/Progress.tsx +0 -0
  214. /package/src/components/{atoms → inputs}/Button.tsx +0 -0
  215. /package/src/components/{atoms → inputs}/Label.tsx +0 -0
  216. /package/src/components/{atoms → inputs}/RadioGroup.tsx +0 -0
  217. /package/src/components/{organisms → navigation}/AppRail.tsx +0 -0
  218. /package/src/components/{templates → patterns}/AuthTemplate.tsx +0 -0
  219. /package/src/components/{templates → patterns}/BannalyzeTemplate.tsx +0 -0
  220. /package/src/components/{templates → patterns}/ChatTemplate.tsx +0 -0
  221. /package/src/components/{templates → patterns}/EditorTemplate.tsx +0 -0
  222. /package/src/components/{templates → patterns}/KanbanTemplate.tsx +0 -0
  223. /package/src/components/{templates → patterns}/LandingTemplate.tsx +0 -0
  224. /package/src/components/{templates → patterns}/SettingsTemplate.tsx +0 -0
@@ -1,8 +1,14 @@
1
1
  import * as React from "react"
2
- import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react"
2
+ import {
3
+ IconChevronLeft as ChevronLeft,
4
+ IconChevronLeftPipe as ChevronLeftPipe,
5
+ IconChevronRight as ChevronRight,
6
+ IconChevronRightPipe as ChevronRightPipe,
7
+ IconDots as MoreHorizontal,
8
+ } from "@tabler/icons-react";
3
9
  import { cn } from "../../lib/utils"
4
- import { ButtonProps } from "../atoms/Button"
5
- import { buttonVariants } from "../atoms/ButtonVariants"
10
+ import { ButtonProps } from "../inputs/Button"
11
+ import { buttonVariants } from "../inputs/ButtonVariants"
6
12
 
7
13
 
8
14
  const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
@@ -40,6 +46,10 @@ type PaginationLinkProps = {
40
46
  } & Pick<ButtonProps, "size"> &
41
47
  React.ComponentProps<"a">
42
48
 
49
+ type PaginationDirectionProps = React.ComponentProps<typeof PaginationLink> & {
50
+ label?: React.ReactNode
51
+ }
52
+
43
53
  const PaginationLink = ({
44
54
  className,
45
55
  isActive,
@@ -53,6 +63,7 @@ const PaginationLink = ({
53
63
  variant: isActive ? "outline" : "ghost",
54
64
  size,
55
65
  }),
66
+ "aria-disabled:pointer-events-none aria-disabled:opacity-50",
56
67
  className
57
68
  )}
58
69
  {...props}
@@ -60,10 +71,30 @@ const PaginationLink = ({
60
71
  )
61
72
  PaginationLink.displayName = "PaginationLink"
62
73
 
74
+ const PaginationFirst = ({
75
+ className,
76
+ children,
77
+ label = "First",
78
+ ...props
79
+ }: PaginationDirectionProps) => (
80
+ <PaginationLink
81
+ aria-label="Go to first page"
82
+ size="default"
83
+ className={cn("gap-1 pl-2.5", className)}
84
+ {...props}
85
+ >
86
+ <ChevronLeftPipe className="h-4 w-4" />
87
+ <span>{children ?? label}</span>
88
+ </PaginationLink>
89
+ )
90
+ PaginationFirst.displayName = "PaginationFirst"
91
+
63
92
  const PaginationPrevious = ({
64
93
  className,
94
+ children,
95
+ label = "Previous",
65
96
  ...props
66
- }: React.ComponentProps<typeof PaginationLink>) => (
97
+ }: PaginationDirectionProps) => (
67
98
  <PaginationLink
68
99
  aria-label="Go to previous page"
69
100
  size="default"
@@ -71,27 +102,47 @@ const PaginationPrevious = ({
71
102
  {...props}
72
103
  >
73
104
  <ChevronLeft className="h-4 w-4" />
74
- <span>Previous</span>
105
+ <span>{children ?? label}</span>
75
106
  </PaginationLink>
76
107
  )
77
108
  PaginationPrevious.displayName = "PaginationPrevious"
78
109
 
79
110
  const PaginationNext = ({
80
111
  className,
112
+ children,
113
+ label = "Next",
81
114
  ...props
82
- }: React.ComponentProps<typeof PaginationLink>) => (
115
+ }: PaginationDirectionProps) => (
83
116
  <PaginationLink
84
117
  aria-label="Go to next page"
85
118
  size="default"
86
119
  className={cn("gap-1 pr-2.5", className)}
87
120
  {...props}
88
121
  >
89
- <span>Next</span>
122
+ <span>{children ?? label}</span>
90
123
  <ChevronRight className="h-4 w-4" />
91
124
  </PaginationLink>
92
125
  )
93
126
  PaginationNext.displayName = "PaginationNext"
94
127
 
128
+ const PaginationLast = ({
129
+ className,
130
+ children,
131
+ label = "Last",
132
+ ...props
133
+ }: PaginationDirectionProps) => (
134
+ <PaginationLink
135
+ aria-label="Go to last page"
136
+ size="default"
137
+ className={cn("gap-1 pr-2.5", className)}
138
+ {...props}
139
+ >
140
+ <span>{children ?? label}</span>
141
+ <ChevronRightPipe className="h-4 w-4" />
142
+ </PaginationLink>
143
+ )
144
+ PaginationLast.displayName = "PaginationLast"
145
+
95
146
  const PaginationEllipsis = ({
96
147
  className,
97
148
  ...props
@@ -111,7 +162,9 @@ export {
111
162
  Pagination,
112
163
  PaginationContent,
113
164
  PaginationEllipsis,
165
+ PaginationFirst,
114
166
  PaginationItem,
167
+ PaginationLast,
115
168
  PaginationLink,
116
169
  PaginationNext,
117
170
  PaginationPrevious,
@@ -13,7 +13,7 @@ const RightRail = React.forwardRef<HTMLDivElement, RightRailProps>(
13
13
  <div
14
14
  ref={ref}
15
15
  className={cn(
16
- "flex flex-col w-[256px] h-[360px] h-full border border-l border-border bg-background z-30 flex-shrink-0",
16
+ "z-30 flex h-full min-h-0 flex-shrink-0 flex-col border-l border-border bg-background",
17
17
  width,
18
18
  className
19
19
  )}
@@ -0,0 +1,223 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import {
5
+ IconChevronLeft as ChevronLeft,
6
+ IconChevronRight as ChevronRight,
7
+ } from "@tabler/icons-react"
8
+
9
+ import { cn } from "../../lib/utils"
10
+ import { TooltipButton, type TooltipButtonProps } from "../inputs/TooltipButton"
11
+
12
+ interface SidebarContextValue {
13
+ collapsed: boolean
14
+ setCollapsed: (collapsed: boolean) => void
15
+ toggleCollapsed: () => void
16
+ }
17
+
18
+ const SidebarContext = React.createContext<SidebarContextValue | null>(null)
19
+
20
+ export function useSidebar() {
21
+ const ctx = React.useContext(SidebarContext)
22
+ if (!ctx)
23
+ throw new Error("useSidebar must be used within <SidebarProvider>")
24
+ return ctx
25
+ }
26
+
27
+ export interface SidebarProviderProps {
28
+ defaultCollapsed?: boolean
29
+ collapsed?: boolean
30
+ onCollapsedChange?: (collapsed: boolean) => void
31
+ children: React.ReactNode
32
+ }
33
+
34
+ const SidebarProvider = ({
35
+ defaultCollapsed = false,
36
+ collapsed: controlledCollapsed,
37
+ onCollapsedChange,
38
+ children,
39
+ }: SidebarProviderProps) => {
40
+ const [internalCollapsed, setInternalCollapsed] =
41
+ React.useState(defaultCollapsed)
42
+ const isControlled = controlledCollapsed !== undefined
43
+ const collapsed = isControlled ? controlledCollapsed : internalCollapsed
44
+
45
+ const setCollapsed = React.useCallback(
46
+ (value: boolean) => {
47
+ if (!isControlled) setInternalCollapsed(value)
48
+ onCollapsedChange?.(value)
49
+ },
50
+ [isControlled, onCollapsedChange]
51
+ )
52
+
53
+ const toggleCollapsed = React.useCallback(
54
+ () => setCollapsed(!collapsed),
55
+ [collapsed, setCollapsed]
56
+ )
57
+
58
+ const value = React.useMemo(
59
+ () => ({ collapsed, setCollapsed, toggleCollapsed }),
60
+ [collapsed, setCollapsed, toggleCollapsed]
61
+ )
62
+
63
+ return (
64
+ <SidebarContext.Provider value={value}>
65
+ {children}
66
+ </SidebarContext.Provider>
67
+ )
68
+ }
69
+ SidebarProvider.displayName = "SidebarProvider"
70
+
71
+ const Sidebar = React.forwardRef<
72
+ HTMLElement,
73
+ React.HTMLAttributes<HTMLElement>
74
+ >(({ className, ...props }, ref) => {
75
+ const { collapsed } = useSidebar()
76
+ return (
77
+ <aside
78
+ ref={ref}
79
+ data-collapsed={collapsed}
80
+ className={cn(
81
+ "relative flex h-full flex-col overflow-visible border-r bg-muted/40 transition-[width] duration-200",
82
+ collapsed ? "w-[60px]" : "w-[240px]",
83
+ className
84
+ )}
85
+ {...props}
86
+ />
87
+ )
88
+ })
89
+ Sidebar.displayName = "Sidebar"
90
+
91
+ const SidebarHeader = React.forwardRef<
92
+ HTMLDivElement,
93
+ React.HTMLAttributes<HTMLDivElement>
94
+ >(({ className, ...props }, ref) => (
95
+ <div
96
+ ref={ref}
97
+ className={cn(
98
+ "flex items-center gap-2 border-b bg-background px-4 py-3",
99
+ className
100
+ )}
101
+ {...props}
102
+ />
103
+ ))
104
+ SidebarHeader.displayName = "SidebarHeader"
105
+
106
+ const SidebarBody = React.forwardRef<
107
+ HTMLDivElement,
108
+ React.HTMLAttributes<HTMLDivElement>
109
+ >(({ className, ...props }, ref) => (
110
+ <div
111
+ ref={ref}
112
+ className={cn(
113
+ "flex-1 overflow-y-auto flex flex-col gap-0.5 p-2",
114
+ // Scrollbar UX: hide by default, reveal a thin, track-less
115
+ // thumb only while the cursor is inside the sidebar. Firefox
116
+ // uses `scrollbar-width` / `scrollbar-color`; WebKit uses
117
+ // ::-webkit-scrollbar pseudo-elements. Consumers can override
118
+ // by passing their own scrollbar utilities through className.
119
+ "[scrollbar-width:none] hover:[scrollbar-width:thin]",
120
+ "[scrollbar-color:transparent_transparent] hover:[scrollbar-color:hsl(var(--border))_transparent]",
121
+ "[&::-webkit-scrollbar]:w-0 hover:[&::-webkit-scrollbar]:w-1.5",
122
+ "[&::-webkit-scrollbar-track]:bg-transparent",
123
+ "[&::-webkit-scrollbar-thumb]:bg-transparent hover:[&::-webkit-scrollbar-thumb]:bg-border/60",
124
+ "[&::-webkit-scrollbar-thumb]:rounded-full",
125
+ className
126
+ )}
127
+ {...props}
128
+ />
129
+ ))
130
+ SidebarBody.displayName = "SidebarBody"
131
+
132
+ const SidebarFooter = React.forwardRef<
133
+ HTMLDivElement,
134
+ React.HTMLAttributes<HTMLDivElement>
135
+ >(({ className, ...props }, ref) => (
136
+ <div
137
+ ref={ref}
138
+ className={cn(
139
+ "flex items-center gap-2 border-t bg-background px-4 py-3",
140
+ className
141
+ )}
142
+ {...props}
143
+ />
144
+ ))
145
+ SidebarFooter.displayName = "SidebarFooter"
146
+
147
+ export interface SidebarToggleProps
148
+ extends Omit<TooltipButtonProps, "children" | "tooltip" | "onClick"> {
149
+ expandLabel?: React.ReactNode
150
+ collapseLabel?: React.ReactNode
151
+ placement?: "center" | "header" | "footer"
152
+ }
153
+
154
+ const SidebarToggle = React.forwardRef<HTMLButtonElement, SidebarToggleProps>(
155
+ (
156
+ {
157
+ className,
158
+ expandLabel = "Expand sidebar",
159
+ collapseLabel = "Collapse sidebar",
160
+ placement = "footer",
161
+ tooltipSide = "right",
162
+ tooltipAlign = "center",
163
+ tooltipSideOffset = 8,
164
+ ...props
165
+ },
166
+ ref
167
+ ) => {
168
+ const { collapsed, toggleCollapsed } = useSidebar()
169
+ const label = collapsed ? expandLabel : collapseLabel
170
+ const placementClass = {
171
+ center: "top-1/2 -translate-y-1/2",
172
+ header: "top-[52px] -translate-y-1/2",
173
+ footer: "bottom-[52px] translate-y-1/2",
174
+ }[placement]
175
+
176
+ return (
177
+ <TooltipButton
178
+ ref={ref}
179
+ type="button"
180
+ variant="outline"
181
+ size="icon"
182
+ className={cn(
183
+ "absolute right-0 z-20 h-7 w-7 translate-x-1/2 rounded-full bg-background shadow-sm",
184
+ placementClass,
185
+ className
186
+ )}
187
+ tooltip={label}
188
+ tooltipSide={tooltipSide}
189
+ tooltipAlign={tooltipAlign}
190
+ tooltipSideOffset={tooltipSideOffset}
191
+ onClick={toggleCollapsed}
192
+ aria-label={typeof label === "string" ? label : undefined}
193
+ {...props}
194
+ >
195
+ {collapsed ? <ChevronRight className="h-4 w-4" /> : <ChevronLeft className="h-4 w-4" />}
196
+ </TooltipButton>
197
+ )
198
+ }
199
+ )
200
+ SidebarToggle.displayName = "SidebarToggle"
201
+
202
+ const SidebarSeparator = React.forwardRef<
203
+ HTMLDivElement,
204
+ React.HTMLAttributes<HTMLDivElement>
205
+ >(({ className, ...props }, ref) => (
206
+ <div
207
+ ref={ref}
208
+ role="separator"
209
+ className={cn("mx-2 my-2 h-px bg-border", className)}
210
+ {...props}
211
+ />
212
+ ))
213
+ SidebarSeparator.displayName = "SidebarSeparator"
214
+
215
+ export {
216
+ Sidebar,
217
+ SidebarProvider,
218
+ SidebarHeader,
219
+ SidebarBody,
220
+ SidebarFooter,
221
+ SidebarToggle,
222
+ SidebarSeparator,
223
+ }
@@ -0,0 +1,160 @@
1
+ "use client"
2
+
3
+ import React, { memo } from 'react';
4
+ import { IconTrash as Trash2, IconChevronRight as ChevronRight } from "@tabler/icons-react";
5
+ import { cn } from '../../lib/utils';
6
+ import type { SidebarItemVariantKey } from './generated/variant-keys';
7
+ import { sidebarItemDefaultVariantKey } from "./generated/default-variant-keys";
8
+ import { TooltipButton } from "../inputs/TooltipButton";
9
+
10
+ export interface SidebarItemProps {
11
+ icon: React.ReactNode;
12
+ label: string;
13
+ count?: number;
14
+ isActive: boolean;
15
+ onClick: () => void;
16
+ onDrop?: (e: React.DragEvent) => void;
17
+ onDragOver?: (e: React.DragEvent) => void;
18
+ dragOverId?: string | null;
19
+ dragAction?: 'nest' | 'reorder-above' | 'reorder-below' | null;
20
+ id: string;
21
+ level?: number;
22
+ hasChildren?: boolean;
23
+ isExpanded?: boolean;
24
+ reserveChevronSpace?: boolean;
25
+ onToggleExpand?: (e: React.MouseEvent) => void;
26
+ onDelete?: (e: React.MouseEvent) => void;
27
+ deleteLabel?: React.ReactNode;
28
+ draggable?: boolean;
29
+ onDragStart?: (e: React.DragEvent) => void;
30
+ onDragEnd?: (e: React.DragEvent) => void;
31
+ className?: string;
32
+ }
33
+
34
+ export const SidebarItem = memo(({
35
+ icon,
36
+ label,
37
+ count,
38
+ isActive,
39
+ onClick,
40
+ onDrop,
41
+ onDragOver,
42
+ dragOverId,
43
+ dragAction,
44
+ id,
45
+ level = 0,
46
+ hasChildren = false,
47
+ isExpanded = false,
48
+ reserveChevronSpace = true,
49
+ onToggleExpand,
50
+ onDelete,
51
+ deleteLabel = "Delete",
52
+ draggable,
53
+ onDragStart,
54
+ onDragEnd,
55
+ className
56
+ }: SidebarItemProps) => {
57
+ const baseVariant: SidebarItemVariantKey = isActive ? "active" : sidebarItemDefaultVariantKey;
58
+ const variantClasses: Record<SidebarItemVariantKey, string> = {
59
+ active: "bg-secondary text-foreground",
60
+ default: "text-muted-foreground hover:bg-muted hover:text-foreground",
61
+ };
62
+
63
+ const dragNestClass =
64
+ dragOverId === id && dragAction === "nest"
65
+ ? "bg-primary-subtle text-primary-subtle-foreground ring-2 ring-primary-border shadow-lg shadow-primary-border scale-[1.02] z-10"
66
+ : null;
67
+ const showChevronSlot = hasChildren || reserveChevronSpace;
68
+ const deleteAriaLabel = typeof deleteLabel === "string" ? deleteLabel : undefined;
69
+
70
+ return (
71
+ <div
72
+ onDragOver={onDragOver}
73
+ onDrop={onDrop}
74
+ draggable={draggable}
75
+ onDragStart={onDragStart}
76
+ onDragEnd={onDragEnd}
77
+ className={cn(
78
+ "group relative flex h-9 w-full cursor-pointer items-center rounded-md text-sm transition-colors",
79
+ dragNestClass ?? variantClasses[baseVariant],
80
+ className
81
+ )}
82
+ >
83
+ {dragOverId === id && dragAction === 'reorder-above' && (
84
+ <div className="absolute top-0 left-0 right-0 h-0.5 bg-primary z-20 pointer-events-none" />
85
+ )}
86
+ {dragOverId === id && dragAction === 'reorder-below' && (
87
+ <div className="absolute bottom-0 left-0 right-0 h-0.5 bg-primary z-20 pointer-events-none" />
88
+ )}
89
+ <button
90
+ type="button"
91
+ onClick={(e) => {
92
+ onClick();
93
+ if (hasChildren && onToggleExpand) {
94
+ onToggleExpand(e);
95
+ }
96
+ }}
97
+ data-sidebar-item-button
98
+ className="flex h-full min-w-0 flex-1 items-center gap-2 overflow-hidden py-1.5 pr-0 text-left"
99
+ style={{ "--sidebar-item-indent": `calc(0.5rem + ${level}rem)` } as React.CSSProperties}
100
+ aria-current={isActive ? "page" : undefined}
101
+ >
102
+ {showChevronSlot ? (
103
+ <div
104
+ onClick={(e) => {
105
+ if (hasChildren && onToggleExpand) {
106
+ e.stopPropagation();
107
+ onToggleExpand(e);
108
+ }
109
+ }}
110
+ className={cn(
111
+ "w-5 h-5 flex items-center justify-center cursor-pointer transition-colors",
112
+ hasChildren ? "" : "pointer-events-none"
113
+ )}
114
+ >
115
+ {hasChildren && (
116
+ <ChevronRight size={12} className={cn("transition-transform", isExpanded ? "rotate-90" : "")} />
117
+ )}
118
+ </div>
119
+ ) : null}
120
+
121
+ <div className={cn("flex-shrink-0", isActive ? "text-primary" : "text-muted-foreground group-hover:text-foreground")}>
122
+ {icon}
123
+ </div>
124
+ <span className="truncate" title={label}>{label}</span>
125
+ </button>
126
+
127
+ {/* Right Side: Delete + Count */}
128
+ <div className="grid w-14 shrink-0 grid-cols-[1.5rem_1.5rem] items-center justify-end">
129
+ {onDelete ? (
130
+ <TooltipButton
131
+ type="button"
132
+ variant="ghost"
133
+ size="icon"
134
+ className={cn(
135
+ "w-6 h-6 transition-opacity",
136
+ isActive
137
+ ? "text-destructive"
138
+ : "text-muted-foreground/50 hover:text-destructive opacity-100 md:opacity-0 md:group-hover:opacity-100"
139
+ )}
140
+ tooltip={deleteLabel}
141
+ tooltipSide="right"
142
+ aria-label={deleteAriaLabel}
143
+ onClick={(e) => {
144
+ e.stopPropagation();
145
+ onDelete(e);
146
+ }}
147
+ >
148
+ <Trash2 size={12} />
149
+ </TooltipButton>
150
+ ) : (
151
+ <div className="h-6 w-6" aria-hidden />
152
+ )}
153
+
154
+ {count !== undefined && (
155
+ <span className="text-xs opacity-60 w-6 text-center tabular-nums text-muted-foreground translate-y-[0.5px]">{count}</span>
156
+ )}
157
+ </div>
158
+ </div>
159
+ );
160
+ });
@@ -23,7 +23,7 @@ const TabsList = React.forwardRef<
23
23
  <TabsPrimitive.List
24
24
  ref={ref}
25
25
  className={cn(
26
- "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
26
+ "inline-flex min-h-12 items-center justify-center overflow-y-hidden rounded-md bg-muted p-1.5 text-muted-foreground",
27
27
  className
28
28
  )}
29
29
  {...props}
@@ -38,7 +38,7 @@ const TabsTrigger = React.forwardRef<
38
38
  <TabsPrimitive.Trigger
39
39
  ref={ref}
40
40
  className={cn(
41
- "inline-flex h-9 items-center justify-center whitespace-nowrap rounded-md px-4 py-2 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
41
+ "inline-flex h-9 cursor-pointer items-center justify-center whitespace-nowrap rounded-md px-4 py-2 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
42
42
  className
43
43
  )}
44
44
  {...props}
@@ -0,0 +1,71 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { IconExternalLink } from "@tabler/icons-react"
5
+
6
+ import { cn } from "../../lib/utils"
7
+ import { Icon } from "../display/Icon"
8
+ import { textLinkDefaultVariantKey } from "./generated/default-variant-keys"
9
+ import type { TextLinkVariantKey } from "./generated/variant-keys"
10
+
11
+ const textLinkVariantClasses: Record<TextLinkVariantKey, string> = {
12
+ default: "font-medium text-primary underline underline-offset-4 hover:text-primary-strong",
13
+ muted: "font-medium text-foreground underline underline-offset-4 hover:text-primary",
14
+ }
15
+
16
+ export interface TextLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
17
+ variant?: TextLinkVariantKey
18
+ newTabLabel?: string
19
+ external?: boolean
20
+ }
21
+
22
+ function normalizeRel(rel: string | undefined, opensNewTab: boolean): string | undefined {
23
+ if (!opensNewTab) return rel
24
+ const tokens = new Set((rel ?? "").split(/\s+/).filter(Boolean))
25
+ tokens.add("noreferrer")
26
+ return Array.from(tokens).join(" ")
27
+ }
28
+
29
+ const TextLink = React.forwardRef<HTMLAnchorElement, TextLinkProps>(
30
+ (
31
+ {
32
+ children,
33
+ className,
34
+ external,
35
+ newTabLabel = "opens in a new tab",
36
+ rel,
37
+ target,
38
+ variant = textLinkDefaultVariantKey,
39
+ ...props
40
+ },
41
+ ref
42
+ ) => {
43
+ const opensNewTab = target === "_blank"
44
+ const showExternalIcon = opensNewTab || Boolean(external)
45
+
46
+ return (
47
+ <a
48
+ ref={ref}
49
+ className={cn(
50
+ "inline-flex items-center gap-1 p-0 align-baseline text-sm transition-colors",
51
+ textLinkVariantClasses[variant],
52
+ className
53
+ )}
54
+ rel={normalizeRel(rel, opensNewTab)}
55
+ target={target}
56
+ {...props}
57
+ >
58
+ <span>{children}</span>
59
+ {showExternalIcon ? (
60
+ <>
61
+ <Icon icon={IconExternalLink} size="xs" decorative className="translate-y-px" />
62
+ {opensNewTab && newTabLabel ? <span className="sr-only">({newTabLabel})</span> : null}
63
+ </>
64
+ ) : null}
65
+ </a>
66
+ )
67
+ }
68
+ )
69
+ TextLink.displayName = "TextLink"
70
+
71
+ export { TextLink }
@@ -0,0 +1,12 @@
1
+ /* eslint-disable */
2
+ // Generated by `npm run design:sync:components`. Do not edit manually.
3
+
4
+ import type { SidebarItemVariantKey, TextLinkVariantKey } from "./variant-keys";
5
+
6
+ export const sidebarItemDefaultVariantKey: SidebarItemVariantKey = "default";
7
+ export const textLinkDefaultVariantKey: TextLinkVariantKey = "default";
8
+
9
+ export const navigationDefaultVariantKeys = {
10
+ sidebarItem: sidebarItemDefaultVariantKey,
11
+ textLink: textLinkDefaultVariantKey,
12
+ } as const;
@@ -0,0 +1,13 @@
1
+ /* eslint-disable */
2
+ // Generated by `npm run design:sync:components`. Do not edit manually.
3
+
4
+ export const sidebarItemVariantKeys = ["active", "default"] as const;
5
+ export type SidebarItemVariantKey = (typeof sidebarItemVariantKeys)[number];
6
+
7
+ export const textLinkVariantKeys = ["default", "muted"] as const;
8
+ export type TextLinkVariantKey = (typeof textLinkVariantKeys)[number];
9
+
10
+ export const navigationVariantKeys = {
11
+ sidebarItem: sidebarItemVariantKeys,
12
+ textLink: textLinkVariantKeys,
13
+ } as const;
@@ -0,0 +1,5 @@
1
+ export { ChatInput as AIChatInput } from "../inputs/ChatInput";
2
+ export type {
3
+ ChatInputLabels as AIChatInputLabels,
4
+ ChatInputProps as AIChatInputProps,
5
+ } from "../inputs/ChatInput";
@@ -0,0 +1,6 @@
1
+ export { ChatMessage as AIChatMessage } from "../display/ChatMessage";
2
+ export type {
3
+ ChatMessageProps as AIChatMessageProps,
4
+ ChatMessageRole as AIChatMessageRole,
5
+ ChatMessageLabels as AIChatMessageLabels,
6
+ } from "../display/ChatMessage";