@allbluecn/ui 0.2.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 (49) hide show
  1. package/package.json +85 -0
  2. package/src/ai-command-button.tsx +36 -0
  3. package/src/ai-stream-text.tsx +37 -0
  4. package/src/alert-dialog.tsx +216 -0
  5. package/src/animated-theme-toggler.tsx +272 -0
  6. package/src/auth-client.ts +108 -0
  7. package/src/auth-layout.tsx +66 -0
  8. package/src/avatar.tsx +129 -0
  9. package/src/badge.tsx +66 -0
  10. package/src/button.tsx +84 -0
  11. package/src/card.tsx +120 -0
  12. package/src/checkbox.tsx +50 -0
  13. package/src/context-menu.tsx +280 -0
  14. package/src/dialog.tsx +183 -0
  15. package/src/dropdown-menu.tsx +286 -0
  16. package/src/empty.tsx +121 -0
  17. package/src/grid-pattern.tsx +87 -0
  18. package/src/icon-packs/index.ts +27 -0
  19. package/src/icon-packs/knowledge.ts +55 -0
  20. package/src/icon-packs/prd.ts +63 -0
  21. package/src/icon-packs/project.ts +59 -0
  22. package/src/icon-picker.tsx +68 -0
  23. package/src/index.ts +23 -0
  24. package/src/input.tsx +36 -0
  25. package/src/item.tsx +213 -0
  26. package/src/kbd.tsx +33 -0
  27. package/src/label.tsx +39 -0
  28. package/src/layout-panel-top.tsx +160 -0
  29. package/src/name-confirm-dialog.tsx +153 -0
  30. package/src/nav-float-button.tsx +301 -0
  31. package/src/notion-avatar.tsx +126 -0
  32. package/src/placeholder-page.tsx +42 -0
  33. package/src/popover.tsx +106 -0
  34. package/src/reference-inline.tsx +53 -0
  35. package/src/reference-search.tsx +52 -0
  36. package/src/resizable.tsx +67 -0
  37. package/src/select.tsx +207 -0
  38. package/src/separator.tsx +45 -0
  39. package/src/sheet.tsx +164 -0
  40. package/src/sidebar.tsx +708 -0
  41. package/src/skeleton.tsx +30 -0
  42. package/src/sonner.tsx +37 -0
  43. package/src/switch.tsx +48 -0
  44. package/src/textarea.tsx +35 -0
  45. package/src/timezone-provider.tsx +55 -0
  46. package/src/tooltip.tsx +72 -0
  47. package/src/use-mobile.ts +36 -0
  48. package/src/user-avatar.tsx +79 -0
  49. package/src/utils.ts +6 -0
@@ -0,0 +1,280 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ "use client"
19
+
20
+ import * as React from "react"
21
+ import { ContextMenu as ContextMenuPrimitive } from "radix-ui"
22
+
23
+ import { cn } from "./utils"
24
+ import { ChevronRightIcon, CheckIcon } from "lucide-react"
25
+
26
+ function ContextMenu({
27
+ ...props
28
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Root>) {
29
+ return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />
30
+ }
31
+
32
+ function ContextMenuTrigger({
33
+ className,
34
+ ...props
35
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {
36
+ return (
37
+ <ContextMenuPrimitive.Trigger
38
+ data-slot="context-menu-trigger"
39
+ className={cn("select-none", className)}
40
+ {...props}
41
+ />
42
+ )
43
+ }
44
+
45
+ function ContextMenuGroup({
46
+ ...props
47
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Group>) {
48
+ return (
49
+ <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />
50
+ )
51
+ }
52
+
53
+ function ContextMenuPortal({
54
+ ...props
55
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) {
56
+ return (
57
+ <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />
58
+ )
59
+ }
60
+
61
+ function ContextMenuSub({
62
+ ...props
63
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) {
64
+ return <ContextMenuPrimitive.Sub data-slot="context-menu-sub" {...props} />
65
+ }
66
+
67
+ function ContextMenuRadioGroup({
68
+ ...props
69
+ }: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>) {
70
+ return (
71
+ <ContextMenuPrimitive.RadioGroup
72
+ data-slot="context-menu-radio-group"
73
+ {...props}
74
+ />
75
+ )
76
+ }
77
+
78
+ function ContextMenuContent({
79
+ className,
80
+ ...props
81
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Content> & {
82
+ side?: "top" | "right" | "bottom" | "left"
83
+ }) {
84
+ return (
85
+ <ContextMenuPrimitive.Portal>
86
+ <ContextMenuPrimitive.Content
87
+ data-slot="context-menu-content"
88
+ className={cn("z-50 max-h-(--radix-context-menu-content-available-height) min-w-36 origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 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 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className )}
89
+ {...props}
90
+ />
91
+ </ContextMenuPrimitive.Portal>
92
+ )
93
+ }
94
+
95
+ function ContextMenuItem({
96
+ className,
97
+ inset,
98
+ variant = "default",
99
+ ...props
100
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {
101
+ inset?: boolean
102
+ variant?: "default" | "destructive"
103
+ }) {
104
+ return (
105
+ <ContextMenuPrimitive.Item
106
+ data-slot="context-menu-item"
107
+ data-inset={inset}
108
+ data-variant={variant}
109
+ className={cn(
110
+ "group/context-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 focus:*:[svg]:text-accent-foreground data-[variant=destructive]:*:[svg]:text-destructive",
111
+ className
112
+ )}
113
+ {...props}
114
+ />
115
+ )
116
+ }
117
+
118
+ function ContextMenuSubTrigger({
119
+ className,
120
+ inset,
121
+ children,
122
+ ...props
123
+ }: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {
124
+ inset?: boolean
125
+ }) {
126
+ return (
127
+ <ContextMenuPrimitive.SubTrigger
128
+ data-slot="context-menu-sub-trigger"
129
+ data-inset={inset}
130
+ className={cn(
131
+ "flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
132
+ className
133
+ )}
134
+ {...props}
135
+ >
136
+ {children}
137
+ <ChevronRightIcon className="ml-auto" />
138
+ </ContextMenuPrimitive.SubTrigger>
139
+ )
140
+ }
141
+
142
+ function ContextMenuSubContent({
143
+ className,
144
+ ...props
145
+ }: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) {
146
+ return (
147
+ <ContextMenuPrimitive.SubContent
148
+ data-slot="context-menu-sub-content"
149
+ className={cn("z-50 min-w-32 origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-lg border bg-popover p-1 text-popover-foreground shadow-lg duration-100 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 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className )}
150
+ {...props}
151
+ />
152
+ )
153
+ }
154
+
155
+ function ContextMenuCheckboxItem({
156
+ className,
157
+ children,
158
+ checked,
159
+ inset,
160
+ ...props
161
+ }: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem> & {
162
+ inset?: boolean
163
+ }) {
164
+ return (
165
+ <ContextMenuPrimitive.CheckboxItem
166
+ data-slot="context-menu-checkbox-item"
167
+ data-inset={inset}
168
+ className={cn(
169
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
170
+ className
171
+ )}
172
+ checked={checked}
173
+ {...props}
174
+ >
175
+ <span className="pointer-events-none absolute right-2">
176
+ <ContextMenuPrimitive.ItemIndicator>
177
+ <CheckIcon
178
+ />
179
+ </ContextMenuPrimitive.ItemIndicator>
180
+ </span>
181
+ {children}
182
+ </ContextMenuPrimitive.CheckboxItem>
183
+ )
184
+ }
185
+
186
+ function ContextMenuRadioItem({
187
+ className,
188
+ children,
189
+ inset,
190
+ ...props
191
+ }: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem> & {
192
+ inset?: boolean
193
+ }) {
194
+ return (
195
+ <ContextMenuPrimitive.RadioItem
196
+ data-slot="context-menu-radio-item"
197
+ data-inset={inset}
198
+ className={cn(
199
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
200
+ className
201
+ )}
202
+ {...props}
203
+ >
204
+ <span className="pointer-events-none absolute right-2">
205
+ <ContextMenuPrimitive.ItemIndicator>
206
+ <CheckIcon
207
+ />
208
+ </ContextMenuPrimitive.ItemIndicator>
209
+ </span>
210
+ {children}
211
+ </ContextMenuPrimitive.RadioItem>
212
+ )
213
+ }
214
+
215
+ function ContextMenuLabel({
216
+ className,
217
+ inset,
218
+ ...props
219
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {
220
+ inset?: boolean
221
+ }) {
222
+ return (
223
+ <ContextMenuPrimitive.Label
224
+ data-slot="context-menu-label"
225
+ data-inset={inset}
226
+ className={cn(
227
+ "px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
228
+ className
229
+ )}
230
+ {...props}
231
+ />
232
+ )
233
+ }
234
+
235
+ function ContextMenuSeparator({
236
+ className,
237
+ ...props
238
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {
239
+ return (
240
+ <ContextMenuPrimitive.Separator
241
+ data-slot="context-menu-separator"
242
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
243
+ {...props}
244
+ />
245
+ )
246
+ }
247
+
248
+ function ContextMenuShortcut({
249
+ className,
250
+ ...props
251
+ }: React.ComponentProps<"span">) {
252
+ return (
253
+ <span
254
+ data-slot="context-menu-shortcut"
255
+ className={cn(
256
+ "ml-auto text-xs tracking-widest text-muted-foreground group-focus/context-menu-item:text-accent-foreground",
257
+ className
258
+ )}
259
+ {...props}
260
+ />
261
+ )
262
+ }
263
+
264
+ export {
265
+ ContextMenu,
266
+ ContextMenuTrigger,
267
+ ContextMenuContent,
268
+ ContextMenuItem,
269
+ ContextMenuCheckboxItem,
270
+ ContextMenuRadioItem,
271
+ ContextMenuLabel,
272
+ ContextMenuSeparator,
273
+ ContextMenuShortcut,
274
+ ContextMenuGroup,
275
+ ContextMenuPortal,
276
+ ContextMenuSub,
277
+ ContextMenuSubContent,
278
+ ContextMenuSubTrigger,
279
+ ContextMenuRadioGroup,
280
+ }
package/src/dialog.tsx ADDED
@@ -0,0 +1,183 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ import * as React from "react"
19
+ import { Dialog as DialogPrimitive } from "radix-ui"
20
+
21
+ import { cn } from "./utils"
22
+ import { Button } from "./button"
23
+ import { XIcon } from "lucide-react"
24
+
25
+ function Dialog({
26
+ ...props
27
+ }: React.ComponentProps<typeof DialogPrimitive.Root>) {
28
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />
29
+ }
30
+
31
+ function DialogTrigger({
32
+ ...props
33
+ }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
34
+ return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
35
+ }
36
+
37
+ function DialogPortal({
38
+ ...props
39
+ }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
40
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
41
+ }
42
+
43
+ function DialogClose({
44
+ ...props
45
+ }: React.ComponentProps<typeof DialogPrimitive.Close>) {
46
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
47
+ }
48
+
49
+ function DialogOverlay({
50
+ className,
51
+ ...props
52
+ }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
53
+ return (
54
+ <DialogPrimitive.Overlay
55
+ data-slot="dialog-overlay"
56
+ className={cn(
57
+ "fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
58
+ className
59
+ )}
60
+ {...props}
61
+ />
62
+ )
63
+ }
64
+
65
+ function DialogContent({
66
+ className,
67
+ children,
68
+ showCloseButton = true,
69
+ ...props
70
+ }: React.ComponentProps<typeof DialogPrimitive.Content> & {
71
+ showCloseButton?: boolean
72
+ }) {
73
+ return (
74
+ <DialogPortal>
75
+ <DialogOverlay />
76
+ <DialogPrimitive.Content
77
+ data-slot="dialog-content"
78
+ className={cn(
79
+ "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 dark:border dark:border-primary/15",
80
+ className
81
+ )}
82
+ {...props}
83
+ >
84
+ {children}
85
+ {showCloseButton && (
86
+ <DialogPrimitive.Close data-slot="dialog-close" asChild>
87
+ <Button
88
+ variant="ghost"
89
+ className="absolute top-2 right-2"
90
+ size="icon-sm"
91
+ >
92
+ <XIcon
93
+ />
94
+ <span className="sr-only">Close</span>
95
+ </Button>
96
+ </DialogPrimitive.Close>
97
+ )}
98
+ </DialogPrimitive.Content>
99
+ </DialogPortal>
100
+ )
101
+ }
102
+
103
+ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
104
+ return (
105
+ <div
106
+ data-slot="dialog-header"
107
+ className={cn("flex flex-col gap-2", className)}
108
+ {...props}
109
+ />
110
+ )
111
+ }
112
+
113
+ function DialogFooter({
114
+ className,
115
+ showCloseButton = false,
116
+ children,
117
+ ...props
118
+ }: React.ComponentProps<"div"> & {
119
+ showCloseButton?: boolean
120
+ }) {
121
+ return (
122
+ <div
123
+ data-slot="dialog-footer"
124
+ className={cn(
125
+ "-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end",
126
+ className
127
+ )}
128
+ {...props}
129
+ >
130
+ {children}
131
+ {showCloseButton && (
132
+ <DialogPrimitive.Close asChild>
133
+ <Button variant="outline">Close</Button>
134
+ </DialogPrimitive.Close>
135
+ )}
136
+ </div>
137
+ )
138
+ }
139
+
140
+ function DialogTitle({
141
+ className,
142
+ ...props
143
+ }: React.ComponentProps<typeof DialogPrimitive.Title>) {
144
+ return (
145
+ <DialogPrimitive.Title
146
+ data-slot="dialog-title"
147
+ className={cn(
148
+ "font-heading text-base leading-none font-medium",
149
+ className
150
+ )}
151
+ {...props}
152
+ />
153
+ )
154
+ }
155
+
156
+ function DialogDescription({
157
+ className,
158
+ ...props
159
+ }: React.ComponentProps<typeof DialogPrimitive.Description>) {
160
+ return (
161
+ <DialogPrimitive.Description
162
+ data-slot="dialog-description"
163
+ className={cn(
164
+ "text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
165
+ className
166
+ )}
167
+ {...props}
168
+ />
169
+ )
170
+ }
171
+
172
+ export {
173
+ Dialog,
174
+ DialogClose,
175
+ DialogContent,
176
+ DialogDescription,
177
+ DialogFooter,
178
+ DialogHeader,
179
+ DialogOverlay,
180
+ DialogPortal,
181
+ DialogTitle,
182
+ DialogTrigger,
183
+ }