@traky-app/ui 0.0.0-stage → 1.1.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 (195) hide show
  1. package/README.md +23 -2
  2. package/package.json +71 -4
  3. package/registry/registry.json +6 -0
  4. package/registry/traky/hooks/use-mobile.ts +19 -0
  5. package/registry/traky/json/accordion.json +18 -0
  6. package/registry/traky/json/alert-dialog.json +20 -0
  7. package/registry/traky/json/alert.json +17 -0
  8. package/registry/traky/json/animated-beam.json +14 -0
  9. package/registry/traky/json/animated-list.json +14 -0
  10. package/registry/traky/json/avatar.json +17 -0
  11. package/registry/traky/json/badge.json +18 -0
  12. package/registry/traky/json/bento-grid.json +20 -0
  13. package/registry/traky/json/breadcrumb.json +18 -0
  14. package/registry/traky/json/bubble.json +18 -0
  15. package/registry/traky/json/button-group.json +21 -0
  16. package/registry/traky/json/button.json +18 -0
  17. package/registry/traky/json/calendar.json +21 -0
  18. package/registry/traky/json/card.json +14 -0
  19. package/registry/traky/json/carousel.json +21 -0
  20. package/registry/traky/json/chart.json +17 -0
  21. package/registry/traky/json/checkbox.json +18 -0
  22. package/registry/traky/json/checkpoint.json +22 -0
  23. package/registry/traky/json/code-block.json +21 -0
  24. package/registry/traky/json/collapsible.json +17 -0
  25. package/registry/traky/json/command.json +22 -0
  26. package/registry/traky/json/context-menu.json +18 -0
  27. package/registry/traky/json/dialog.json +18 -0
  28. package/registry/traky/json/drawer.json +17 -0
  29. package/registry/traky/json/dropdown-menu.json +18 -0
  30. package/registry/traky/json/empty.json +17 -0
  31. package/registry/traky/json/field.json +21 -0
  32. package/registry/traky/json/globe.json +17 -0
  33. package/registry/traky/json/hook-use-mobile.json +14 -0
  34. package/registry/traky/json/hover-card.json +17 -0
  35. package/registry/traky/json/input-group.json +22 -0
  36. package/registry/traky/json/input-otp.json +18 -0
  37. package/registry/traky/json/input.json +17 -0
  38. package/registry/traky/json/item.json +21 -0
  39. package/registry/traky/json/kbd.json +14 -0
  40. package/registry/traky/json/label.json +17 -0
  41. package/registry/traky/json/lib-disable-input-autofill.json +14 -0
  42. package/registry/traky/json/lib-sidebar-persistence.json +14 -0
  43. package/registry/traky/json/lib-utils.json +18 -0
  44. package/registry/traky/json/map.json +19 -0
  45. package/registry/traky/json/marker.json +18 -0
  46. package/registry/traky/json/marquee.json +14 -0
  47. package/registry/traky/json/message.json +14 -0
  48. package/registry/traky/json/navigation-menu.json +19 -0
  49. package/registry/traky/json/number-ticker.json +14 -0
  50. package/registry/traky/json/pagination.json +20 -0
  51. package/registry/traky/json/popover.json +17 -0
  52. package/registry/traky/json/progress.json +17 -0
  53. package/registry/traky/json/select.json +18 -0
  54. package/registry/traky/json/separator.json +17 -0
  55. package/registry/traky/json/sheet.json +18 -0
  56. package/registry/traky/json/sidebar.json +29 -0
  57. package/registry/traky/json/skeleton.json +14 -0
  58. package/registry/traky/json/sonner.json +18 -0
  59. package/registry/traky/json/spinner.json +17 -0
  60. package/registry/traky/json/switch.json +17 -0
  61. package/registry/traky/json/table.json +14 -0
  62. package/registry/traky/json/tabs.json +17 -0
  63. package/registry/traky/json/textarea.json +17 -0
  64. package/registry/traky/json/toggle-group.json +21 -0
  65. package/registry/traky/json/toggle.json +18 -0
  66. package/registry/traky/json/tooltip.json +17 -0
  67. package/registry/traky/json/trace.json +20 -0
  68. package/registry/traky/lib/disable-input-autofill.ts +23 -0
  69. package/registry/traky/lib/sidebar-persistence.ts +76 -0
  70. package/registry/traky/lib/utils.ts +6 -0
  71. package/registry/traky/registry.json +637 -0
  72. package/registry/traky/ui/accordion.tsx +65 -0
  73. package/registry/traky/ui/alert-dialog.tsx +163 -0
  74. package/registry/traky/ui/alert.tsx +66 -0
  75. package/registry/traky/ui/animated-beam.tsx +185 -0
  76. package/registry/traky/ui/animated-list.tsx +71 -0
  77. package/registry/traky/ui/avatar.tsx +53 -0
  78. package/registry/traky/ui/badge.tsx +46 -0
  79. package/registry/traky/ui/bento-grid.tsx +109 -0
  80. package/registry/traky/ui/breadcrumb.tsx +108 -0
  81. package/registry/traky/ui/bubble.tsx +125 -0
  82. package/registry/traky/ui/button-group.tsx +83 -0
  83. package/registry/traky/ui/button.tsx +64 -0
  84. package/registry/traky/ui/calendar.tsx +213 -0
  85. package/registry/traky/ui/card.tsx +92 -0
  86. package/registry/traky/ui/carousel.tsx +240 -0
  87. package/registry/traky/ui/chart.tsx +380 -0
  88. package/registry/traky/ui/checkbox.tsx +31 -0
  89. package/registry/traky/ui/checkpoint.tsx +94 -0
  90. package/registry/traky/ui/code-block.tsx +232 -0
  91. package/registry/traky/ui/collapsible.tsx +33 -0
  92. package/registry/traky/ui/command.tsx +191 -0
  93. package/registry/traky/ui/context-menu.tsx +251 -0
  94. package/registry/traky/ui/dialog.tsx +142 -0
  95. package/registry/traky/ui/drawer.tsx +135 -0
  96. package/registry/traky/ui/dropdown-menu.tsx +256 -0
  97. package/registry/traky/ui/empty.tsx +104 -0
  98. package/registry/traky/ui/field.tsx +248 -0
  99. package/registry/traky/ui/globe.tsx +234 -0
  100. package/registry/traky/ui/hover-card.tsx +44 -0
  101. package/registry/traky/ui/input-group.tsx +170 -0
  102. package/registry/traky/ui/input-otp.tsx +77 -0
  103. package/registry/traky/ui/input.tsx +24 -0
  104. package/registry/traky/ui/item.tsx +193 -0
  105. package/registry/traky/ui/kbd.tsx +28 -0
  106. package/registry/traky/ui/label.tsx +24 -0
  107. package/registry/traky/ui/map.tsx +2226 -0
  108. package/registry/traky/ui/marker.tsx +69 -0
  109. package/registry/traky/ui/marquee.tsx +74 -0
  110. package/registry/traky/ui/message.tsx +92 -0
  111. package/registry/traky/ui/navigation-menu.tsx +169 -0
  112. package/registry/traky/ui/number-ticker.tsx +90 -0
  113. package/registry/traky/ui/pagination.tsx +122 -0
  114. package/registry/traky/ui/popover.tsx +48 -0
  115. package/registry/traky/ui/progress.tsx +31 -0
  116. package/registry/traky/ui/select.tsx +193 -0
  117. package/registry/traky/ui/separator.tsx +28 -0
  118. package/registry/traky/ui/sheet.tsx +143 -0
  119. package/registry/traky/ui/sidebar.tsx +764 -0
  120. package/registry/traky/ui/skeleton.tsx +13 -0
  121. package/registry/traky/ui/sonner.tsx +71 -0
  122. package/registry/traky/ui/spinner.tsx +15 -0
  123. package/registry/traky/ui/switch.tsx +41 -0
  124. package/registry/traky/ui/table.tsx +116 -0
  125. package/registry/traky/ui/tabs.tsx +66 -0
  126. package/registry/traky/ui/textarea.tsx +20 -0
  127. package/registry/traky/ui/toggle-group.tsx +83 -0
  128. package/registry/traky/ui/toggle.tsx +47 -0
  129. package/registry/traky/ui/tooltip.tsx +61 -0
  130. package/registry/traky/ui/trace.tsx +165 -0
  131. package/schema/components.json +24 -0
  132. package/src/hooks/use-document-theme.ts +25 -0
  133. package/src/hooks/use-mobile.ts +19 -0
  134. package/src/lib/disable-input-autofill.ts +23 -0
  135. package/src/lib/sidebar-persistence.ts +76 -0
  136. package/src/lib/utils.ts +30 -0
  137. package/src/ui/accordion.tsx +65 -0
  138. package/src/ui/alert-dialog.tsx +163 -0
  139. package/src/ui/alert.tsx +66 -0
  140. package/src/ui/animated-beam.tsx +185 -0
  141. package/src/ui/animated-list.tsx +71 -0
  142. package/src/ui/avatar.tsx +53 -0
  143. package/src/ui/badge.tsx +46 -0
  144. package/src/ui/bento-grid.tsx +109 -0
  145. package/src/ui/breadcrumb.tsx +108 -0
  146. package/src/ui/bubble.tsx +125 -0
  147. package/src/ui/button-group.tsx +83 -0
  148. package/src/ui/button.tsx +64 -0
  149. package/src/ui/calendar.tsx +213 -0
  150. package/src/ui/card.tsx +92 -0
  151. package/src/ui/carousel.tsx +240 -0
  152. package/src/ui/chart.tsx +380 -0
  153. package/src/ui/checkbox.tsx +31 -0
  154. package/src/ui/checkpoint.tsx +94 -0
  155. package/src/ui/code-block.tsx +232 -0
  156. package/src/ui/collapsible.tsx +33 -0
  157. package/src/ui/command.tsx +191 -0
  158. package/src/ui/context-menu.tsx +251 -0
  159. package/src/ui/dialog.tsx +142 -0
  160. package/src/ui/drawer.tsx +135 -0
  161. package/src/ui/dropdown-menu.tsx +256 -0
  162. package/src/ui/empty.tsx +104 -0
  163. package/src/ui/field.tsx +248 -0
  164. package/src/ui/globe.tsx +234 -0
  165. package/src/ui/hover-card.tsx +44 -0
  166. package/src/ui/input-group.tsx +170 -0
  167. package/src/ui/input-otp.tsx +77 -0
  168. package/src/ui/input.tsx +24 -0
  169. package/src/ui/item.tsx +193 -0
  170. package/src/ui/kbd.tsx +28 -0
  171. package/src/ui/label.tsx +24 -0
  172. package/src/ui/map.tsx +2226 -0
  173. package/src/ui/marker.tsx +69 -0
  174. package/src/ui/marquee.tsx +74 -0
  175. package/src/ui/message.tsx +92 -0
  176. package/src/ui/navigation-menu.tsx +169 -0
  177. package/src/ui/number-ticker.tsx +90 -0
  178. package/src/ui/pagination.tsx +122 -0
  179. package/src/ui/popover.tsx +48 -0
  180. package/src/ui/progress.tsx +31 -0
  181. package/src/ui/select.tsx +193 -0
  182. package/src/ui/separator.tsx +28 -0
  183. package/src/ui/sheet.tsx +143 -0
  184. package/src/ui/sidebar.tsx +764 -0
  185. package/src/ui/skeleton.tsx +13 -0
  186. package/src/ui/sonner.tsx +71 -0
  187. package/src/ui/spinner.tsx +15 -0
  188. package/src/ui/switch.tsx +41 -0
  189. package/src/ui/table.tsx +116 -0
  190. package/src/ui/tabs.tsx +66 -0
  191. package/src/ui/textarea.tsx +20 -0
  192. package/src/ui/toggle-group.tsx +83 -0
  193. package/src/ui/toggle.tsx +47 -0
  194. package/src/ui/tooltip.tsx +61 -0
  195. package/src/ui/trace.tsx +165 -0
@@ -0,0 +1,185 @@
1
+ "use client"
2
+
3
+ import { RefObject, useEffect, useId, useState } from "react"
4
+ import { motion } from "motion/react"
5
+
6
+ import { cn } from "../lib/utils"
7
+
8
+ export interface AnimatedBeamProps {
9
+ className?: string
10
+ containerRef: RefObject<HTMLElement | null> // Container ref
11
+ fromRef: RefObject<HTMLElement | null>
12
+ toRef: RefObject<HTMLElement | null>
13
+ curvature?: number
14
+ reverse?: boolean
15
+ pathColor?: string
16
+ pathWidth?: number
17
+ pathOpacity?: number
18
+ gradientStartColor?: string
19
+ gradientStopColor?: string
20
+ delay?: number
21
+ duration?: number
22
+ startXOffset?: number
23
+ startYOffset?: number
24
+ endXOffset?: number
25
+ endYOffset?: number
26
+ }
27
+
28
+ export const AnimatedBeam: React.FC<AnimatedBeamProps> = ({
29
+ className,
30
+ containerRef,
31
+ fromRef,
32
+ toRef,
33
+ curvature = 0,
34
+ reverse = false, // Include the reverse prop
35
+ duration = Math.random() * 3 + 4,
36
+ delay = 0,
37
+ pathColor = "gray",
38
+ pathWidth = 2,
39
+ pathOpacity = 0.2,
40
+ gradientStartColor = "#ffaa40",
41
+ gradientStopColor = "#9c40ff",
42
+ startXOffset = 0,
43
+ startYOffset = 0,
44
+ endXOffset = 0,
45
+ endYOffset = 0,
46
+ }) => {
47
+ const id = useId()
48
+ const [pathD, setPathD] = useState("")
49
+ const [svgDimensions, setSvgDimensions] = useState({ width: 0, height: 0 })
50
+
51
+ // Calculate the gradient coordinates based on the reverse prop
52
+ const gradientCoordinates = reverse
53
+ ? {
54
+ x1: ["90%", "-10%"],
55
+ x2: ["100%", "0%"],
56
+ y1: ["0%", "0%"],
57
+ y2: ["0%", "0%"],
58
+ }
59
+ : {
60
+ x1: ["10%", "110%"],
61
+ x2: ["0%", "100%"],
62
+ y1: ["0%", "0%"],
63
+ y2: ["0%", "0%"],
64
+ }
65
+
66
+ useEffect(() => {
67
+ const updatePath = () => {
68
+ if (containerRef.current && fromRef.current && toRef.current) {
69
+ const containerRect = containerRef.current.getBoundingClientRect()
70
+ const rectA = fromRef.current.getBoundingClientRect()
71
+ const rectB = toRef.current.getBoundingClientRect()
72
+
73
+ const svgWidth = containerRect.width
74
+ const svgHeight = containerRect.height
75
+ setSvgDimensions({ width: svgWidth, height: svgHeight })
76
+
77
+ const startX =
78
+ rectA.left - containerRect.left + rectA.width / 2 + startXOffset
79
+ const startY =
80
+ rectA.top - containerRect.top + rectA.height / 2 + startYOffset
81
+ const endX =
82
+ rectB.left - containerRect.left + rectB.width / 2 + endXOffset
83
+ const endY =
84
+ rectB.top - containerRect.top + rectB.height / 2 + endYOffset
85
+
86
+ const controlY = startY - curvature
87
+ const d = `M ${startX},${startY} Q ${
88
+ (startX + endX) / 2
89
+ },${controlY} ${endX},${endY}`
90
+ setPathD(d)
91
+ }
92
+ }
93
+
94
+ // Initialize ResizeObserver
95
+ const resizeObserver = new ResizeObserver(() => {
96
+ updatePath()
97
+ })
98
+
99
+ // Observe the container element
100
+ if (containerRef.current) {
101
+ resizeObserver.observe(containerRef.current)
102
+ }
103
+
104
+ // Call the updatePath initially to set the initial path
105
+ updatePath()
106
+
107
+ // Clean up the observer on component unmount
108
+ return () => {
109
+ resizeObserver.disconnect()
110
+ }
111
+ }, [
112
+ containerRef,
113
+ fromRef,
114
+ toRef,
115
+ curvature,
116
+ startXOffset,
117
+ startYOffset,
118
+ endXOffset,
119
+ endYOffset,
120
+ ])
121
+
122
+ return (
123
+ <svg
124
+ fill="none"
125
+ width={svgDimensions.width}
126
+ height={svgDimensions.height}
127
+ xmlns="http://www.w3.org/2000/svg"
128
+ className={cn(
129
+ "pointer-events-none absolute top-0 left-0 transform-gpu stroke-2",
130
+ className
131
+ )}
132
+ viewBox={`0 0 ${svgDimensions.width} ${svgDimensions.height}`}
133
+ >
134
+ <path
135
+ d={pathD}
136
+ stroke={pathColor}
137
+ strokeWidth={pathWidth}
138
+ strokeOpacity={pathOpacity}
139
+ strokeLinecap="round"
140
+ />
141
+ <path
142
+ d={pathD}
143
+ strokeWidth={pathWidth}
144
+ stroke={`url(#${id})`}
145
+ strokeOpacity="1"
146
+ strokeLinecap="round"
147
+ />
148
+ <defs>
149
+ <motion.linearGradient
150
+ className="transform-gpu"
151
+ id={id}
152
+ gradientUnits={"userSpaceOnUse"}
153
+ initial={{
154
+ x1: "0%",
155
+ x2: "0%",
156
+ y1: "0%",
157
+ y2: "0%",
158
+ }}
159
+ animate={{
160
+ x1: gradientCoordinates.x1,
161
+ x2: gradientCoordinates.x2,
162
+ y1: gradientCoordinates.y1,
163
+ y2: gradientCoordinates.y2,
164
+ }}
165
+ transition={{
166
+ delay,
167
+ duration,
168
+ ease: [0.16, 1, 0.3, 1], // https://easings.net/#easeOutExpo
169
+ repeat: Infinity,
170
+ repeatDelay: 0,
171
+ }}
172
+ >
173
+ <stop stopColor={gradientStartColor} stopOpacity="0"></stop>
174
+ <stop stopColor={gradientStartColor}></stop>
175
+ <stop offset="32.5%" stopColor={gradientStopColor}></stop>
176
+ <stop
177
+ offset="100%"
178
+ stopColor={gradientStopColor}
179
+ stopOpacity="0"
180
+ ></stop>
181
+ </motion.linearGradient>
182
+ </defs>
183
+ </svg>
184
+ )
185
+ }
@@ -0,0 +1,71 @@
1
+ "use client"
2
+
3
+ import React, {
4
+ ComponentPropsWithoutRef,
5
+ useEffect,
6
+ useMemo,
7
+ useState,
8
+ } from "react"
9
+ import { AnimatePresence, motion, MotionProps } from "motion/react"
10
+
11
+ import { cn } from "../lib/utils"
12
+
13
+ export function AnimatedListItem({ children }: { children: React.ReactNode }) {
14
+ const animations: MotionProps = {
15
+ initial: { scale: 0, opacity: 0 },
16
+ animate: { scale: 1, opacity: 1, originY: 0 },
17
+ exit: { scale: 0, opacity: 0 },
18
+ transition: { type: "spring", stiffness: 350, damping: 40 },
19
+ }
20
+
21
+ return (
22
+ <motion.div {...animations} layout className="mx-auto w-full">
23
+ {children}
24
+ </motion.div>
25
+ )
26
+ }
27
+
28
+ export interface AnimatedListProps extends ComponentPropsWithoutRef<"div"> {
29
+ children: React.ReactNode
30
+ delay?: number
31
+ }
32
+
33
+ export const AnimatedList = React.memo(
34
+ ({ children, className, delay = 1000, ...props }: AnimatedListProps) => {
35
+ const [index, setIndex] = useState(0)
36
+ const childrenArray = useMemo(
37
+ () => React.Children.toArray(children),
38
+ [children]
39
+ )
40
+
41
+ useEffect(() => {
42
+ const timeout = setTimeout(() => {
43
+ setIndex((prevIndex) => (prevIndex + 1) % childrenArray.length)
44
+ }, delay)
45
+
46
+ return () => clearTimeout(timeout)
47
+ }, [index, delay, childrenArray.length])
48
+
49
+ const itemsToShow = useMemo(() => {
50
+ const result = childrenArray.slice(0, index + 1).reverse()
51
+ return result
52
+ }, [index, childrenArray])
53
+
54
+ return (
55
+ <div
56
+ className={cn(`flex flex-col items-center gap-4`, className)}
57
+ {...props}
58
+ >
59
+ <AnimatePresence>
60
+ {itemsToShow.map((item) => (
61
+ <AnimatedListItem key={(item as React.ReactElement).key}>
62
+ {item}
63
+ </AnimatedListItem>
64
+ ))}
65
+ </AnimatePresence>
66
+ </div>
67
+ )
68
+ }
69
+ )
70
+
71
+ AnimatedList.displayName = "AnimatedList"
@@ -0,0 +1,53 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as AvatarPrimitive from "@radix-ui/react-avatar"
5
+
6
+ import { cn } from "../lib/utils"
7
+
8
+ function Avatar({
9
+ className,
10
+ ...props
11
+ }: React.ComponentProps<typeof AvatarPrimitive.Root>) {
12
+ return (
13
+ <AvatarPrimitive.Root
14
+ data-slot="avatar"
15
+ className={cn(
16
+ "relative flex size-8 shrink-0 overflow-hidden rounded-full",
17
+ className
18
+ )}
19
+ {...props}
20
+ />
21
+ )
22
+ }
23
+
24
+ function AvatarImage({
25
+ className,
26
+ ...props
27
+ }: React.ComponentProps<typeof AvatarPrimitive.Image>) {
28
+ return (
29
+ <AvatarPrimitive.Image
30
+ data-slot="avatar-image"
31
+ className={cn("aspect-square size-full", className)}
32
+ {...props}
33
+ />
34
+ )
35
+ }
36
+
37
+ function AvatarFallback({
38
+ className,
39
+ ...props
40
+ }: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
41
+ return (
42
+ <AvatarPrimitive.Fallback
43
+ data-slot="avatar-fallback"
44
+ className={cn(
45
+ "bg-muted flex size-full items-center justify-center rounded-full",
46
+ className
47
+ )}
48
+ {...props}
49
+ />
50
+ )
51
+ }
52
+
53
+ export { Avatar, AvatarImage, AvatarFallback }
@@ -0,0 +1,46 @@
1
+ import * as React from "react"
2
+ import { Slot } from "@radix-ui/react-slot"
3
+ import { cva, type VariantProps } from "class-variance-authority"
4
+
5
+ import { cn } from "../lib/utils"
6
+
7
+ const badgeVariants = cva(
8
+ "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default:
13
+ "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
14
+ secondary:
15
+ "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
16
+ destructive:
17
+ "border-transparent bg-destructive text-destructive-foreground [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
18
+ outline:
19
+ "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
20
+ },
21
+ },
22
+ defaultVariants: {
23
+ variant: "default",
24
+ },
25
+ }
26
+ )
27
+
28
+ function Badge({
29
+ className,
30
+ variant,
31
+ asChild = false,
32
+ ...props
33
+ }: React.ComponentProps<"span"> &
34
+ VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
35
+ const Comp = asChild ? Slot : "span"
36
+
37
+ return (
38
+ <Comp
39
+ data-slot="badge"
40
+ className={cn(badgeVariants({ variant }), className)}
41
+ {...props}
42
+ />
43
+ )
44
+ }
45
+
46
+ export { Badge, badgeVariants }
@@ -0,0 +1,109 @@
1
+ import { ComponentPropsWithoutRef, ReactNode } from "react"
2
+ import { IconArrowRight } from "@tabler/icons-react"
3
+
4
+ import { cn } from "../lib/utils"
5
+ import { Button } from "./button"
6
+
7
+ interface BentoGridProps extends ComponentPropsWithoutRef<"div"> {
8
+ children: ReactNode
9
+ className?: string
10
+ }
11
+
12
+ interface BentoCardProps extends ComponentPropsWithoutRef<"div"> {
13
+ name: string
14
+ className: string
15
+ background: ReactNode
16
+ Icon: React.ElementType
17
+ description: string
18
+ href: string
19
+ cta: string
20
+ }
21
+
22
+ const BentoGrid = ({ children, className, ...props }: BentoGridProps) => {
23
+ return (
24
+ <div
25
+ className={cn(
26
+ "grid w-full auto-rows-[22rem] grid-cols-3 gap-4",
27
+ className
28
+ )}
29
+ {...props}
30
+ >
31
+ {children}
32
+ </div>
33
+ )
34
+ }
35
+
36
+ const BentoCard = ({
37
+ name,
38
+ className,
39
+ background,
40
+ Icon,
41
+ description,
42
+ href,
43
+ cta,
44
+ ...props
45
+ }: BentoCardProps) => (
46
+ <div
47
+ key={name}
48
+ className={cn(
49
+ "group relative col-span-3 flex flex-col justify-between overflow-hidden rounded-xl",
50
+ // light styles
51
+ "bg-background [box-shadow:0_0_0_1px_rgba(0,0,0,.03),0_2px_4px_rgba(0,0,0,.05),0_12px_24px_rgba(0,0,0,.05)]",
52
+ // dark styles
53
+ "dark:bg-background transform-gpu dark:[box-shadow:0_-20px_80px_-20px_#ffffff1f_inset] dark:[border:1px_solid_rgba(255,255,255,.1)]",
54
+ className
55
+ )}
56
+ {...props}
57
+ >
58
+ <div>{background}</div>
59
+ <div className="p-4">
60
+ <div className="pointer-events-none z-10 flex transform-gpu flex-col gap-1 transition-all duration-300 lg:group-hover:-translate-y-10">
61
+ <Icon className="h-12 w-12 origin-left transform-gpu text-neutral-700 transition-all duration-300 ease-in-out group-hover:scale-75" />
62
+ <h3 className="text-xl font-semibold text-neutral-700 dark:text-neutral-300">
63
+ {name}
64
+ </h3>
65
+ <p className="max-w-lg text-neutral-400">{description}</p>
66
+ </div>
67
+
68
+ <div
69
+ className={cn(
70
+ "pointer-events-none flex w-full translate-y-0 transform-gpu flex-row items-center transition-all duration-300 group-hover:translate-y-0 group-hover:opacity-100 lg:hidden"
71
+ )}
72
+ >
73
+ <Button
74
+ variant="link"
75
+ asChild
76
+ size="sm"
77
+ className="pointer-events-auto p-0"
78
+ >
79
+ <a href={href}>
80
+ {cta}
81
+ <IconArrowRight className="ms-2 size-4 rtl:rotate-180" />
82
+ </a>
83
+ </Button>
84
+ </div>
85
+ </div>
86
+
87
+ <div
88
+ className={cn(
89
+ "pointer-events-none absolute bottom-0 hidden w-full translate-y-10 transform-gpu flex-row items-center p-4 opacity-0 transition-all duration-300 group-hover:translate-y-0 group-hover:opacity-100 lg:flex"
90
+ )}
91
+ >
92
+ <Button
93
+ variant="link"
94
+ asChild
95
+ size="sm"
96
+ className="pointer-events-auto p-0"
97
+ >
98
+ <a href={href}>
99
+ {cta}
100
+ <IconArrowRight className="ms-2 size-4 rtl:rotate-180" />
101
+ </a>
102
+ </Button>
103
+ </div>
104
+
105
+ <div className="pointer-events-none absolute inset-0 transform-gpu transition-all duration-300 group-hover:bg-black/[.03] group-hover:dark:bg-neutral-800/10" />
106
+ </div>
107
+ )
108
+
109
+ export { BentoCard, BentoGrid }
@@ -0,0 +1,108 @@
1
+ import { IconChevronRight, IconDots } from "@tabler/icons-react";
2
+ import * as React from "react"
3
+ import { Slot } from "@radix-ui/react-slot"
4
+ import { cn } from "../lib/utils"
5
+
6
+ function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
7
+ return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />
8
+ }
9
+
10
+ function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
11
+ return (
12
+ <ol
13
+ data-slot="breadcrumb-list"
14
+ className={cn(
15
+ "text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
16
+ className
17
+ )}
18
+ {...props}
19
+ />
20
+ )
21
+ }
22
+
23
+ function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
24
+ return (
25
+ <li
26
+ data-slot="breadcrumb-item"
27
+ className={cn("inline-flex items-center gap-1.5", className)}
28
+ {...props}
29
+ />
30
+ )
31
+ }
32
+
33
+ function BreadcrumbLink({
34
+ asChild,
35
+ className,
36
+ ...props
37
+ }: React.ComponentProps<"a"> & {
38
+ asChild?: boolean
39
+ }) {
40
+ const Comp = asChild ? Slot : "a"
41
+
42
+ return (
43
+ <Comp
44
+ data-slot="breadcrumb-link"
45
+ className={cn("hover:text-foreground transition-colors", className)}
46
+ {...props}
47
+ />
48
+ )
49
+ }
50
+
51
+ function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
52
+ return (
53
+ <span
54
+ data-slot="breadcrumb-page"
55
+ role="link"
56
+ aria-disabled="true"
57
+ aria-current="page"
58
+ className={cn("text-foreground font-normal", className)}
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ function BreadcrumbSeparator({
65
+ children,
66
+ className,
67
+ ...props
68
+ }: React.ComponentProps<"li">) {
69
+ return (
70
+ <li
71
+ data-slot="breadcrumb-separator"
72
+ role="presentation"
73
+ aria-hidden="true"
74
+ className={cn("[&>svg]:size-3.5", className)}
75
+ {...props}
76
+ >
77
+ {children ?? <IconChevronRight />}
78
+ </li>
79
+ )
80
+ }
81
+
82
+ function BreadcrumbEllipsis({
83
+ className,
84
+ ...props
85
+ }: React.ComponentProps<"span">) {
86
+ return (
87
+ <span
88
+ data-slot="breadcrumb-ellipsis"
89
+ role="presentation"
90
+ aria-hidden="true"
91
+ className={cn("flex size-9 items-center justify-center", className)}
92
+ {...props}
93
+ >
94
+ <IconDots className="size-4" />
95
+ <span className="sr-only">More</span>
96
+ </span>
97
+ )
98
+ }
99
+
100
+ export {
101
+ Breadcrumb,
102
+ BreadcrumbList,
103
+ BreadcrumbItem,
104
+ BreadcrumbLink,
105
+ BreadcrumbPage,
106
+ BreadcrumbSeparator,
107
+ BreadcrumbEllipsis,
108
+ }
@@ -0,0 +1,125 @@
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+ import { Slot } from "radix-ui"
4
+
5
+ import { cn } from "../lib/utils"
6
+
7
+ function BubbleGroup({ className, ...props }: React.ComponentProps<"div">) {
8
+ return (
9
+ <div
10
+ data-slot="bubble-group"
11
+ className={cn("flex min-w-0 flex-col gap-2", className)}
12
+ {...props}
13
+ />
14
+ )
15
+ }
16
+
17
+ const bubbleVariants = cva(
18
+ "group/bubble relative flex w-fit max-w-[80%] min-w-0 flex-col gap-1 group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full",
19
+ {
20
+ variants: {
21
+ variant: {
22
+ default:
23
+ "*:data-[slot=bubble-content]:bg-primary *:data-[slot=bubble-content]:text-primary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-primary/80",
24
+ secondary:
25
+ "*:data-[slot=bubble-content]:bg-secondary *:data-[slot=bubble-content]:text-secondary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)]",
26
+ muted:
27
+ "*:data-[slot=bubble-content]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--muted),var(--foreground)_5%)]",
28
+ tinted:
29
+ "*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.93_calc(c*0.4)_h)] *:data-[slot=bubble-content]:text-foreground dark:*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.3_calc(c*0.4)_h)] [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.88_calc(c*0.5)_h)] dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.35_calc(c*0.5)_h)]",
30
+ outline:
31
+ "*:data-[slot=bubble-content]:border-border *:data-[slot=bubble-content]:bg-background [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-input/30",
32
+ ghost:
33
+ "border-none *:data-[slot=bubble-content]:rounded-none *:data-[slot=bubble-content]:bg-transparent *:data-[slot=bubble-content]:p-0 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted/50",
34
+ destructive:
35
+ "*:data-[slot=bubble-content]:bg-destructive/10 *:data-[slot=bubble-content]:text-destructive dark:*:data-[slot=bubble-content]:bg-destructive/20 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/20 dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/30",
36
+ },
37
+ },
38
+ defaultVariants: {
39
+ variant: "default",
40
+ },
41
+ }
42
+ )
43
+
44
+ function Bubble({
45
+ variant = "default",
46
+ align = "start",
47
+ className,
48
+ ...props
49
+ }: React.ComponentProps<"div"> &
50
+ VariantProps<typeof bubbleVariants> & {
51
+ align?: "start" | "end"
52
+ }) {
53
+ return (
54
+ <div
55
+ data-slot="bubble"
56
+ data-variant={variant}
57
+ data-align={align}
58
+ className={cn(bubbleVariants({ variant }), className)}
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ function BubbleContent({
65
+ asChild = false,
66
+ className,
67
+ ...props
68
+ }: React.ComponentProps<"div"> & {
69
+ asChild?: boolean
70
+ }) {
71
+ const Comp = asChild ? Slot.Root : "div"
72
+
73
+ return (
74
+ <Comp
75
+ data-slot="bubble-content"
76
+ className={cn(
77
+ "w-fit max-w-full min-w-0 overflow-hidden rounded-xl border border-transparent px-3 py-2 text-sm leading-relaxed wrap-break-word group-data-[align=end]/bubble:self-end [button]:text-left [button,a]:transition-colors [button,a]:outline-none [button,a]:focus-visible:border-ring [button,a]:focus-visible:ring-3 [button,a]:focus-visible:ring-ring/50",
78
+ className
79
+ )}
80
+ {...props}
81
+ />
82
+ )
83
+ }
84
+
85
+ const bubbleReactionsVariants = cva(
86
+ "absolute z-10 flex w-fit shrink-0 items-center justify-center gap-1 rounded-full bg-muted px-1.5 py-0.5 text-sm ring-3 ring-card has-[button]:p-0",
87
+ {
88
+ variants: {
89
+ side: {
90
+ top: "top-0 -translate-y-3/4",
91
+ bottom: "bottom-0 translate-y-3/4",
92
+ },
93
+ align: {
94
+ start: "left-3",
95
+ end: "right-3",
96
+ },
97
+ },
98
+ defaultVariants: {
99
+ side: "bottom",
100
+ align: "end",
101
+ },
102
+ }
103
+ )
104
+
105
+ function BubbleReactions({
106
+ side = "bottom",
107
+ align = "end",
108
+ className,
109
+ ...props
110
+ }: React.ComponentProps<"div"> & {
111
+ align?: "start" | "end"
112
+ side?: "top" | "bottom"
113
+ }) {
114
+ return (
115
+ <div
116
+ data-slot="bubble-reactions"
117
+ data-align={align}
118
+ data-side={side}
119
+ className={cn(bubbleReactionsVariants({ side, align }), className)}
120
+ {...props}
121
+ />
122
+ )
123
+ }
124
+
125
+ export { BubbleGroup, Bubble, BubbleContent, BubbleReactions }