parthenon-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.
- package/package.json +74 -0
- package/src/components/.gitkeep +0 -0
- package/src/components/avatar.tsx +109 -0
- package/src/components/badge.tsx +52 -0
- package/src/components/button.tsx +122 -0
- package/src/components/card.tsx +108 -0
- package/src/components/checkbox.tsx +37 -0
- package/src/components/collapsible.tsx +21 -0
- package/src/components/color-picker.tsx +270 -0
- package/src/components/command.tsx +195 -0
- package/src/components/context-menu.tsx +270 -0
- package/src/components/dialog.tsx +169 -0
- package/src/components/dropdown-menu.tsx +279 -0
- package/src/components/empty.tsx +104 -0
- package/src/components/index.ts +27 -0
- package/src/components/input-group.tsx +155 -0
- package/src/components/input.tsx +27 -0
- package/src/components/label.tsx +18 -0
- package/src/components/popover.tsx +88 -0
- package/src/components/scroll-area.tsx +55 -0
- package/src/components/select.tsx +201 -0
- package/src/components/separator.tsx +23 -0
- package/src/components/sheet.tsx +138 -0
- package/src/components/sidebar.tsx +729 -0
- package/src/components/skeleton.tsx +13 -0
- package/src/components/sonner.tsx +59 -0
- package/src/components/switch.tsx +51 -0
- package/src/components/table.tsx +375 -0
- package/src/components/tabs.tsx +80 -0
- package/src/components/textarea.tsx +18 -0
- package/src/components/tooltip.tsx +64 -0
- package/src/hooks/.gitkeep +0 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/lib/.gitkeep +0 -0
- package/src/lib/utils.ts +6 -0
- package/src/styles/globals.css +654 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { cn } from "@workspace/ui/lib/utils"
|
|
5
|
+
|
|
6
|
+
interface ColorPickerProps {
|
|
7
|
+
value: string
|
|
8
|
+
onChange: (hex: string) => void
|
|
9
|
+
className?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function hexToHsl(hex: string): { h: number; s: number; l: number } {
|
|
13
|
+
hex = hex.replace("#", "")
|
|
14
|
+
const r = parseInt(hex.substring(0, 2), 16) / 255
|
|
15
|
+
const g = parseInt(hex.substring(2, 4), 16) / 255
|
|
16
|
+
const b = parseInt(hex.substring(4, 6), 16) / 255
|
|
17
|
+
const max = Math.max(r, g, b)
|
|
18
|
+
const min = Math.min(r, g, b)
|
|
19
|
+
const l = (max + min) / 2
|
|
20
|
+
if (max === min) return { h: 0, s: 0, l: Math.round(l * 100) }
|
|
21
|
+
const d = max - min
|
|
22
|
+
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
|
|
23
|
+
let h = 0
|
|
24
|
+
if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6
|
|
25
|
+
else if (max === g) h = ((b - r) / d + 2) / 6
|
|
26
|
+
else h = ((r - g) / d + 4) / 6
|
|
27
|
+
return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function hslToHex(h: number, s: number, l: number): string {
|
|
31
|
+
s /= 100; l /= 100
|
|
32
|
+
const c = (1 - Math.abs(2 * l - 1)) * s
|
|
33
|
+
const x = c * (1 - Math.abs(((h / 60) % 2) - 1))
|
|
34
|
+
const m = l - c / 2
|
|
35
|
+
let r = 0, g = 0, b = 0
|
|
36
|
+
if (h < 60) { r = c; g = x }
|
|
37
|
+
else if (h < 120) { r = x; g = c }
|
|
38
|
+
else if (h < 180) { g = c; b = x }
|
|
39
|
+
else if (h < 240) { g = x; b = c }
|
|
40
|
+
else if (h < 300) { r = x; b = c }
|
|
41
|
+
else { r = c; b = x }
|
|
42
|
+
const toHex = (v: number) => Math.round((v + m) * 255).toString(16).padStart(2, "0")
|
|
43
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function ColorPicker({ value, onChange, className }: ColorPickerProps) {
|
|
47
|
+
const [isOpen, setIsOpen] = React.useState(false)
|
|
48
|
+
const [inputValue, setInputValue] = React.useState(value)
|
|
49
|
+
const [hue, setHue] = React.useState(0)
|
|
50
|
+
const [sat, setSat] = React.useState(100)
|
|
51
|
+
const [lit, setLit] = React.useState(50)
|
|
52
|
+
const [isDraggingCanvas, setIsDraggingCanvas] = React.useState(false)
|
|
53
|
+
const [isDraggingHue, setIsDraggingHue] = React.useState(false)
|
|
54
|
+
const containerRef = React.useRef<HTMLDivElement>(null)
|
|
55
|
+
const canvasRef = React.useRef<HTMLCanvasElement>(null)
|
|
56
|
+
const hueRef = React.useRef<HTMLDivElement>(null)
|
|
57
|
+
|
|
58
|
+
React.useEffect(() => {
|
|
59
|
+
setInputValue(value)
|
|
60
|
+
if (value && /^#[0-9a-fA-F]{6}$/.test(value)) {
|
|
61
|
+
const hsl = hexToHsl(value)
|
|
62
|
+
setHue(hsl.h)
|
|
63
|
+
setSat(hsl.s)
|
|
64
|
+
setLit(hsl.l)
|
|
65
|
+
}
|
|
66
|
+
}, [value])
|
|
67
|
+
|
|
68
|
+
// Draw canvas: saturation (x) × lightness (y)
|
|
69
|
+
React.useEffect(() => {
|
|
70
|
+
const canvas = canvasRef.current
|
|
71
|
+
if (!canvas) return
|
|
72
|
+
const ctx = canvas.getContext("2d")
|
|
73
|
+
if (!ctx) return
|
|
74
|
+
const w = canvas.width
|
|
75
|
+
const h = canvas.height
|
|
76
|
+
const hueColor = hslToHex(hue, 100, 50)
|
|
77
|
+
// Horizontal: white to hue (saturation)
|
|
78
|
+
const gradH = ctx.createLinearGradient(0, 0, w, 0)
|
|
79
|
+
gradH.addColorStop(0, "#ffffff")
|
|
80
|
+
gradH.addColorStop(1, hueColor)
|
|
81
|
+
ctx.fillStyle = gradH
|
|
82
|
+
ctx.fillRect(0, 0, w, h)
|
|
83
|
+
// Vertical: transparent to black (lightness)
|
|
84
|
+
const gradV = ctx.createLinearGradient(0, 0, 0, h)
|
|
85
|
+
gradV.addColorStop(0, "rgba(0,0,0,0)")
|
|
86
|
+
gradV.addColorStop(1, "#000000")
|
|
87
|
+
ctx.fillStyle = gradV
|
|
88
|
+
ctx.fillRect(0, 0, w, h)
|
|
89
|
+
}, [hue])
|
|
90
|
+
|
|
91
|
+
React.useEffect(() => {
|
|
92
|
+
if (!isOpen) return
|
|
93
|
+
const handler = (e: MouseEvent) => {
|
|
94
|
+
if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
|
|
95
|
+
setIsOpen(false)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
document.addEventListener("mousedown", handler)
|
|
99
|
+
return () => document.removeEventListener("mousedown", handler)
|
|
100
|
+
}, [isOpen])
|
|
101
|
+
|
|
102
|
+
// Canvas controls both saturation (x) and lightness (y)
|
|
103
|
+
const updateCanvas = React.useCallback((clientX: number, clientY: number) => {
|
|
104
|
+
const canvas = canvasRef.current
|
|
105
|
+
if (!canvas) return
|
|
106
|
+
const rect = canvas.getBoundingClientRect()
|
|
107
|
+
const x = Math.max(0, Math.min(clientX - rect.left, rect.width))
|
|
108
|
+
const y = Math.max(0, Math.min(clientY - rect.top, rect.height))
|
|
109
|
+
const newSat = Math.round((x / rect.width) * 100)
|
|
110
|
+
const newLit = Math.round((1 - y / rect.height) * 100)
|
|
111
|
+
setSat(newSat)
|
|
112
|
+
setLit(newLit)
|
|
113
|
+
const hex = hslToHex(hue, newSat, newLit)
|
|
114
|
+
setInputValue(hex)
|
|
115
|
+
onChange(hex)
|
|
116
|
+
}, [hue, onChange])
|
|
117
|
+
|
|
118
|
+
const updateHue = React.useCallback((clientX: number) => {
|
|
119
|
+
const el = hueRef.current
|
|
120
|
+
if (!el) return
|
|
121
|
+
const rect = el.getBoundingClientRect()
|
|
122
|
+
const x = Math.max(0, Math.min(clientX - rect.left, rect.width))
|
|
123
|
+
const newHue = Math.round((x / rect.width) * 360)
|
|
124
|
+
setHue(newHue)
|
|
125
|
+
const hex = hslToHex(newHue, sat, lit)
|
|
126
|
+
setInputValue(hex)
|
|
127
|
+
onChange(hex)
|
|
128
|
+
}, [sat, lit, onChange])
|
|
129
|
+
|
|
130
|
+
React.useEffect(() => {
|
|
131
|
+
if (!isDraggingCanvas && !isDraggingHue) return
|
|
132
|
+
const handleMove = (e: MouseEvent) => {
|
|
133
|
+
if (isDraggingCanvas) updateCanvas(e.clientX, e.clientY)
|
|
134
|
+
if (isDraggingHue) updateHue(e.clientX)
|
|
135
|
+
}
|
|
136
|
+
const handleUp = () => {
|
|
137
|
+
setIsDraggingCanvas(false)
|
|
138
|
+
setIsDraggingHue(false)
|
|
139
|
+
}
|
|
140
|
+
document.addEventListener("mousemove", handleMove)
|
|
141
|
+
document.addEventListener("mouseup", handleUp)
|
|
142
|
+
return () => {
|
|
143
|
+
document.removeEventListener("mousemove", handleMove)
|
|
144
|
+
document.removeEventListener("mouseup", handleUp)
|
|
145
|
+
}
|
|
146
|
+
}, [isDraggingCanvas, isDraggingHue, updateCanvas, updateHue])
|
|
147
|
+
|
|
148
|
+
const handleCanvasDown = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
|
149
|
+
setIsDraggingCanvas(true)
|
|
150
|
+
updateCanvas(e.clientX, e.clientY)
|
|
151
|
+
}
|
|
152
|
+
const handleHueDown = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
153
|
+
setIsDraggingHue(true)
|
|
154
|
+
updateHue(e.clientX)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const handleHexInput = (v: string) => {
|
|
158
|
+
setInputValue(v)
|
|
159
|
+
if (/^#[0-9a-fA-F]{6}$/.test(v)) onChange(v)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const handleClear = (e: React.MouseEvent) => {
|
|
163
|
+
e.stopPropagation()
|
|
164
|
+
onChange("")
|
|
165
|
+
setInputValue("")
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const currentColor = value || "#808080"
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<div ref={containerRef} className={cn("relative", className)}>
|
|
172
|
+
<button
|
|
173
|
+
type="button"
|
|
174
|
+
onClick={() => setIsOpen(!isOpen)}
|
|
175
|
+
className="flex items-center gap-3 rounded-xl border border-border/50 px-3 py-2 hover:bg-muted/50 transition-colors"
|
|
176
|
+
>
|
|
177
|
+
<div
|
|
178
|
+
className="size-10 rounded-xl border-2 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.15),0_2px_4px_rgba(0,0,0,0.15)]"
|
|
179
|
+
style={{ backgroundColor: currentColor, borderColor: currentColor }}
|
|
180
|
+
/>
|
|
181
|
+
<div className="flex flex-col items-start">
|
|
182
|
+
<span className="text-xs font-medium text-foreground">{value ? "Custom" : "Default"}</span>
|
|
183
|
+
<span className="text-[11px] font-mono text-muted-foreground">{value || "—"}</span>
|
|
184
|
+
</div>
|
|
185
|
+
{value && (
|
|
186
|
+
<span
|
|
187
|
+
role="button"
|
|
188
|
+
tabIndex={0}
|
|
189
|
+
onClick={handleClear}
|
|
190
|
+
onKeyDown={(e) => e.key === "Enter" && handleClear(e)}
|
|
191
|
+
className="ml-2 text-muted-foreground/50 hover:text-muted-foreground text-xs cursor-pointer"
|
|
192
|
+
>
|
|
193
|
+
×
|
|
194
|
+
</span>
|
|
195
|
+
)}
|
|
196
|
+
</button>
|
|
197
|
+
|
|
198
|
+
{isOpen && (
|
|
199
|
+
<div className="absolute top-full left-0 mt-2 z-50 w-72 rounded-2xl border border-border bg-popover p-4 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.1),inset_0_-2px_0_0_rgba(0,0,0,0.1),0_0_0_1px_rgba(0,0,0,0.05),0_2px_0_0_rgba(0,0,0,0.08),0_4px_0_0_rgba(0,0,0,0.06),0_6px_0_0_rgba(0,0,0,0.04),0_8px_0_0_rgba(0,0,0,0.02),0_12px_24px_-4px_rgba(0,0,0,0.15)]">
|
|
200
|
+
{/* Current color preview */}
|
|
201
|
+
<div className="flex items-center gap-3 mb-3">
|
|
202
|
+
<div
|
|
203
|
+
className="size-12 rounded-xl border-2 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.15),0_2px_4px_rgba(0,0,0,0.15)]"
|
|
204
|
+
style={{ backgroundColor: currentColor, borderColor: currentColor }}
|
|
205
|
+
/>
|
|
206
|
+
<div>
|
|
207
|
+
<p className="text-xs font-medium text-foreground">Current color</p>
|
|
208
|
+
<p className="text-[11px] font-mono text-muted-foreground">{value || "Default (theme)"}</p>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
|
|
212
|
+
{/* Canvas with pointer */}
|
|
213
|
+
<div className="relative h-[160px] rounded-xl border border-border overflow-hidden cursor-crosshair select-none">
|
|
214
|
+
<canvas
|
|
215
|
+
ref={canvasRef}
|
|
216
|
+
width={248}
|
|
217
|
+
height={160}
|
|
218
|
+
className="absolute inset-0 w-full h-full"
|
|
219
|
+
onMouseDown={handleCanvasDown}
|
|
220
|
+
/>
|
|
221
|
+
{/* 3D pointer */}
|
|
222
|
+
<div
|
|
223
|
+
className="absolute w-4 h-4 -translate-x-1/2 -translate-y-1/2 pointer-events-none rounded-full"
|
|
224
|
+
style={{
|
|
225
|
+
left: `${sat}%`,
|
|
226
|
+
top: `${(1 - lit / 100) * 100}%`,
|
|
227
|
+
boxShadow: "0 1px 3px rgba(0,0,0,0.4), 0 0 0 1.5px rgba(255,255,255,0.9), inset 0 1px 0 rgba(255,255,255,0.5)",
|
|
228
|
+
}}
|
|
229
|
+
/>
|
|
230
|
+
</div>
|
|
231
|
+
|
|
232
|
+
{/* Hue slider */}
|
|
233
|
+
<div className="mt-3">
|
|
234
|
+
<p className="text-[10px] font-medium text-muted-foreground mb-1.5">Hue</p>
|
|
235
|
+
<div
|
|
236
|
+
ref={hueRef}
|
|
237
|
+
className="relative h-5 rounded-full cursor-pointer border border-border select-none"
|
|
238
|
+
style={{
|
|
239
|
+
background: "linear-gradient(to right, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000)",
|
|
240
|
+
}}
|
|
241
|
+
onMouseDown={handleHueDown}
|
|
242
|
+
>
|
|
243
|
+
<div
|
|
244
|
+
className="absolute top-1/2 -translate-y-1/2 -translate-x-1/2 size-5 rounded-full border-2 border-white shadow-[0_0_0_1px_rgba(0,0,0,0.2),0_1px_3px_rgba(0,0,0,0.3)] pointer-events-none"
|
|
245
|
+
style={{ left: `${(hue / 360) * 100}%`, backgroundColor: hslToHex(hue, 100, 50) }}
|
|
246
|
+
/>
|
|
247
|
+
</div>
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
{/* Hex input */}
|
|
251
|
+
<div className="mt-3 flex items-center gap-2">
|
|
252
|
+
<div
|
|
253
|
+
className="size-10 rounded-xl border-2 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.15),0_2px_4px_rgba(0,0,0,0.15)]"
|
|
254
|
+
style={{ backgroundColor: currentColor, borderColor: currentColor }}
|
|
255
|
+
/>
|
|
256
|
+
<input
|
|
257
|
+
type="text"
|
|
258
|
+
value={inputValue}
|
|
259
|
+
onChange={(e) => handleHexInput(e.target.value)}
|
|
260
|
+
placeholder="#000000"
|
|
261
|
+
className="flex-1 text-xs font-mono bg-muted/50 border border-border rounded-lg px-2.5 py-2 focus:outline-none focus:ring-1 focus:ring-ring"
|
|
262
|
+
/>
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
)}
|
|
266
|
+
</div>
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export { ColorPicker }
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Command as CommandPrimitive } from "cmdk"
|
|
3
|
+
|
|
4
|
+
import { cn } from "@workspace/ui/lib/utils"
|
|
5
|
+
import {
|
|
6
|
+
Dialog,
|
|
7
|
+
DialogContent,
|
|
8
|
+
DialogDescription,
|
|
9
|
+
DialogHeader,
|
|
10
|
+
DialogTitle,
|
|
11
|
+
} from "@workspace/ui/components/dialog"
|
|
12
|
+
import {
|
|
13
|
+
InputGroup,
|
|
14
|
+
InputGroupAddon,
|
|
15
|
+
} from "@workspace/ui/components/input-group"
|
|
16
|
+
import { HugeiconsIcon } from "@hugeicons/react"
|
|
17
|
+
import { SearchIcon, Tick02Icon } from "@hugeicons/core-free-icons"
|
|
18
|
+
|
|
19
|
+
function Command({
|
|
20
|
+
className,
|
|
21
|
+
...props
|
|
22
|
+
}: React.ComponentProps<typeof CommandPrimitive>) {
|
|
23
|
+
return (
|
|
24
|
+
<CommandPrimitive
|
|
25
|
+
data-slot="command"
|
|
26
|
+
className={cn(
|
|
27
|
+
"flex size-full flex-col overflow-hidden rounded-4xl bg-popover p-1 text-popover-foreground",
|
|
28
|
+
className
|
|
29
|
+
)}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function CommandDialog({
|
|
36
|
+
title = "Command Palette",
|
|
37
|
+
description = "Search for a command to run...",
|
|
38
|
+
children,
|
|
39
|
+
className,
|
|
40
|
+
showCloseButton = false,
|
|
41
|
+
...props
|
|
42
|
+
}: Omit<React.ComponentProps<typeof Dialog>, "children"> & {
|
|
43
|
+
title?: string
|
|
44
|
+
description?: string
|
|
45
|
+
className?: string
|
|
46
|
+
showCloseButton?: boolean
|
|
47
|
+
children: React.ReactNode
|
|
48
|
+
}) {
|
|
49
|
+
return (
|
|
50
|
+
<Dialog {...props}>
|
|
51
|
+
<DialogHeader className="sr-only">
|
|
52
|
+
<DialogTitle>{title}</DialogTitle>
|
|
53
|
+
<DialogDescription>{description}</DialogDescription>
|
|
54
|
+
</DialogHeader>
|
|
55
|
+
<DialogContent
|
|
56
|
+
className={cn(
|
|
57
|
+
"top-1/3 translate-y-0 overflow-hidden rounded-4xl! p-0",
|
|
58
|
+
className
|
|
59
|
+
)}
|
|
60
|
+
showCloseButton={showCloseButton}
|
|
61
|
+
>
|
|
62
|
+
{children}
|
|
63
|
+
</DialogContent>
|
|
64
|
+
</Dialog>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function CommandInput({
|
|
69
|
+
className,
|
|
70
|
+
...props
|
|
71
|
+
}: React.ComponentProps<typeof CommandPrimitive.Input>) {
|
|
72
|
+
return (
|
|
73
|
+
<div data-slot="command-input-wrapper" className="p-1 pb-0">
|
|
74
|
+
<InputGroup className="h-9 bg-input/30">
|
|
75
|
+
<CommandPrimitive.Input
|
|
76
|
+
data-slot="command-input"
|
|
77
|
+
className={cn(
|
|
78
|
+
"w-full text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
|
|
79
|
+
className
|
|
80
|
+
)}
|
|
81
|
+
{...props}
|
|
82
|
+
/>
|
|
83
|
+
<InputGroupAddon>
|
|
84
|
+
<HugeiconsIcon icon={SearchIcon} strokeWidth={2} className="size-4 shrink-0 opacity-50" />
|
|
85
|
+
</InputGroupAddon>
|
|
86
|
+
</InputGroup>
|
|
87
|
+
</div>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function CommandList({
|
|
92
|
+
className,
|
|
93
|
+
...props
|
|
94
|
+
}: React.ComponentProps<typeof CommandPrimitive.List>) {
|
|
95
|
+
return (
|
|
96
|
+
<CommandPrimitive.List
|
|
97
|
+
data-slot="command-list"
|
|
98
|
+
className={cn(
|
|
99
|
+
"no-scrollbar max-h-72 scroll-py-1 overflow-x-hidden overflow-y-auto outline-none",
|
|
100
|
+
className
|
|
101
|
+
)}
|
|
102
|
+
{...props}
|
|
103
|
+
/>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function CommandEmpty({
|
|
108
|
+
className,
|
|
109
|
+
...props
|
|
110
|
+
}: React.ComponentProps<typeof CommandPrimitive.Empty>) {
|
|
111
|
+
return (
|
|
112
|
+
<CommandPrimitive.Empty
|
|
113
|
+
data-slot="command-empty"
|
|
114
|
+
className={cn("py-6 text-center text-sm", className)}
|
|
115
|
+
{...props}
|
|
116
|
+
/>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function CommandGroup({
|
|
121
|
+
className,
|
|
122
|
+
...props
|
|
123
|
+
}: React.ComponentProps<typeof CommandPrimitive.Group>) {
|
|
124
|
+
return (
|
|
125
|
+
<CommandPrimitive.Group
|
|
126
|
+
data-slot="command-group"
|
|
127
|
+
className={cn(
|
|
128
|
+
"overflow-hidden p-1 text-foreground **:[[cmdk-group-heading]]:px-3 **:[[cmdk-group-heading]]:py-2 **:[[cmdk-group-heading]]:text-xs **:[[cmdk-group-heading]]:font-medium **:[[cmdk-group-heading]]:text-muted-foreground",
|
|
129
|
+
className
|
|
130
|
+
)}
|
|
131
|
+
{...props}
|
|
132
|
+
/>
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function CommandSeparator({
|
|
137
|
+
className,
|
|
138
|
+
...props
|
|
139
|
+
}: React.ComponentProps<typeof CommandPrimitive.Separator>) {
|
|
140
|
+
return (
|
|
141
|
+
<CommandPrimitive.Separator
|
|
142
|
+
data-slot="command-separator"
|
|
143
|
+
className={cn("my-1 h-px bg-border/50", className)}
|
|
144
|
+
{...props}
|
|
145
|
+
/>
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function CommandItem({
|
|
150
|
+
className,
|
|
151
|
+
children,
|
|
152
|
+
...props
|
|
153
|
+
}: React.ComponentProps<typeof CommandPrimitive.Item>) {
|
|
154
|
+
return (
|
|
155
|
+
<CommandPrimitive.Item
|
|
156
|
+
data-slot="command-item"
|
|
157
|
+
className={cn(
|
|
158
|
+
"group/command-item relative flex cursor-default items-center gap-2 rounded-lg px-3 py-2 text-sm outline-hidden select-none in-data-[slot=dialog-content]:rounded-2xl data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-selected:bg-muted data-selected:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-selected:*:[svg]:text-foreground",
|
|
159
|
+
className
|
|
160
|
+
)}
|
|
161
|
+
{...props}
|
|
162
|
+
>
|
|
163
|
+
{children}
|
|
164
|
+
<HugeiconsIcon icon={Tick02Icon} strokeWidth={2} className="ms-auto opacity-0 group-has-data-[slot=command-shortcut]/command-item:hidden group-data-[checked=true]/command-item:opacity-100" />
|
|
165
|
+
</CommandPrimitive.Item>
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function CommandShortcut({
|
|
170
|
+
className,
|
|
171
|
+
...props
|
|
172
|
+
}: React.ComponentProps<"span">) {
|
|
173
|
+
return (
|
|
174
|
+
<span
|
|
175
|
+
data-slot="command-shortcut"
|
|
176
|
+
className={cn(
|
|
177
|
+
"ms-auto text-xs tracking-widest text-muted-foreground group-data-selected/command-item:text-foreground",
|
|
178
|
+
className
|
|
179
|
+
)}
|
|
180
|
+
{...props}
|
|
181
|
+
/>
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export {
|
|
186
|
+
Command,
|
|
187
|
+
CommandDialog,
|
|
188
|
+
CommandInput,
|
|
189
|
+
CommandList,
|
|
190
|
+
CommandEmpty,
|
|
191
|
+
CommandGroup,
|
|
192
|
+
CommandItem,
|
|
193
|
+
CommandShortcut,
|
|
194
|
+
CommandSeparator,
|
|
195
|
+
}
|