@turtleclub/ui 0.3.0 → 0.4.0-beta.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/.turbo/turbo-build.log +46 -44
- package/CHANGELOG.md +12 -0
- package/dist/index.cjs +72 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +8872 -7439
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/components/features/data-table/data-table.d.ts +19 -0
- package/dist/types/components/features/data-table/data-table.d.ts.map +1 -0
- package/dist/types/components/features/data-table/expand-toggle.d.ts +5 -0
- package/dist/types/components/features/data-table/expand-toggle.d.ts.map +1 -0
- package/dist/types/components/features/data-table/fuzzy-filter.d.ts +4 -0
- package/dist/types/components/features/data-table/fuzzy-filter.d.ts.map +1 -0
- package/dist/types/components/features/data-table/index.d.ts +3 -0
- package/dist/types/components/features/data-table/index.d.ts.map +1 -0
- package/dist/types/components/features/data-table/sortable-header.d.ts +5 -0
- package/dist/types/components/features/data-table/sortable-header.d.ts.map +1 -0
- package/dist/types/components/features/page-heading.d.ts +1 -1
- package/dist/types/components/features/page-heading.d.ts.map +1 -1
- package/dist/types/components/features/sidebar-layout.d.ts.map +1 -1
- package/dist/types/components/icons/beta.d.ts.map +1 -1
- package/dist/types/components/icons/dot.d.ts.map +1 -1
- package/dist/types/components/icons/issue.d.ts.map +1 -1
- package/dist/types/components/icons/turtle.d.ts.map +1 -1
- package/dist/types/components/icons/update.d.ts.map +1 -1
- package/dist/types/components/icons/warning.d.ts.map +1 -1
- package/dist/types/components/molecules/opportunity/opportunity-disclaimer.d.ts.map +1 -1
- package/dist/types/components/molecules/opportunity/opportunity-list/hooks/use-opportunity-grouping.d.ts.map +1 -1
- package/dist/types/components/molecules/opportunity/opportunity-list/opportunity-list.d.ts.map +1 -1
- package/dist/types/components/molecules/opportunity/opportunity-rate-estimator.d.ts.map +1 -1
- package/dist/types/components/molecules/opportunity/opportunity-section.d.ts.map +1 -1
- package/dist/types/components/molecules/opportunity/opportunity-selector.d.ts +1 -1
- package/dist/types/components/molecules/opportunity/opportunity-selector.d.ts.map +1 -1
- package/dist/types/components/molecules/slippage-selector.d.ts.map +1 -1
- package/dist/types/components/molecules/swap-details.d.ts.map +1 -1
- package/dist/types/components/molecules/swap-input.d.ts.map +1 -1
- package/dist/types/components/molecules/tabs.d.ts +1 -1
- package/dist/types/components/molecules/tabs.d.ts.map +1 -1
- package/dist/types/components/molecules/token-selector.d.ts.map +1 -1
- package/dist/types/components/molecules/tx-status.d.ts.map +1 -1
- package/dist/types/components/molecules/widget/asset-list/asset-filters.d.ts.map +1 -1
- package/dist/types/components/molecules/widget/asset-list/asset-list.d.ts.map +1 -1
- package/dist/types/components/molecules/widget/asset-list/hooks/use-asset-filtering.d.ts.map +1 -1
- package/dist/types/components/molecules/widget/asset-list/hooks/use-asset-grouping.d.ts.map +1 -1
- package/dist/types/components/molecules/widget/campaign-item.d.ts.map +1 -1
- package/dist/types/components/molecules/widget/deal-item.d.ts.map +1 -1
- package/dist/types/components/molecules/widget/index.d.ts +1 -1
- package/dist/types/components/molecules/widget/index.d.ts.map +1 -1
- package/dist/types/components/molecules/widget/opportunity-item.d.ts.map +1 -1
- package/dist/types/components/ui/alert-dialog.d.ts.map +1 -1
- package/dist/types/components/ui/avatar.d.ts.map +1 -1
- package/dist/types/components/ui/badge.d.ts.map +1 -1
- package/dist/types/components/ui/banner.d.ts.map +1 -1
- package/dist/types/components/ui/button.d.ts.map +1 -1
- package/dist/types/components/ui/card.d.ts +1 -1
- package/dist/types/components/ui/card.d.ts.map +1 -1
- package/dist/types/components/ui/checkbox.d.ts.map +1 -1
- package/dist/types/components/ui/chip.d.ts.map +1 -1
- package/dist/types/components/ui/collapsible.d.ts.map +1 -1
- package/dist/types/components/ui/combobox.d.ts.map +1 -1
- package/dist/types/components/ui/command.d.ts.map +1 -1
- package/dist/types/components/ui/dialog.d.ts.map +1 -1
- package/dist/types/components/ui/dropdown.d.ts.map +1 -1
- package/dist/types/components/ui/field.d.ts.map +1 -1
- package/dist/types/components/ui/heading.d.ts.map +1 -1
- package/dist/types/components/ui/hover-card.d.ts +1 -1
- package/dist/types/components/ui/hover-card.d.ts.map +1 -1
- package/dist/types/components/ui/icon-list.d.ts.map +1 -1
- package/dist/types/components/ui/info-card.d.ts.map +1 -1
- package/dist/types/components/ui/input-group.d.ts.map +1 -1
- package/dist/types/components/ui/input.d.ts.map +1 -1
- package/dist/types/components/ui/label.d.ts.map +1 -1
- package/dist/types/components/ui/multi-select.d.ts.map +1 -1
- package/dist/types/components/ui/navigation-bar.d.ts +1 -1
- package/dist/types/components/ui/navigation-bar.d.ts.map +1 -1
- package/dist/types/components/ui/navigation-menu.d.ts.map +1 -1
- package/dist/types/components/ui/opportunity-details-v1.d.ts.map +1 -1
- package/dist/types/components/ui/popover.d.ts.map +1 -1
- package/dist/types/components/ui/scroll-area.d.ts.map +1 -1
- package/dist/types/components/ui/select.d.ts.map +1 -1
- package/dist/types/components/ui/separator.d.ts.map +1 -1
- package/dist/types/components/ui/sheet.d.ts.map +1 -1
- package/dist/types/components/ui/sidebar.d.ts.map +1 -1
- package/dist/types/components/ui/slider.d.ts.map +1 -1
- package/dist/types/components/ui/switch.d.ts.map +1 -1
- package/dist/types/components/ui/table-shadcn.d.ts.map +1 -1
- package/dist/types/components/ui/table.d.ts.map +1 -1
- package/dist/types/components/ui/toggle-group.d.ts.map +1 -1
- package/dist/types/components/ui/toggle.d.ts.map +1 -1
- package/dist/types/components/ui/tooltip.d.ts.map +1 -1
- package/dist/types/hooks/useIsMobile.d.ts.map +1 -1
- package/dist/types/lib/utils.d.ts.map +1 -1
- package/dist/types/tokens/index.d.ts +5 -5
- package/dist/types/tokens/index.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/components/features/data-table/data-table.tsx +150 -0
- package/src/components/features/data-table/expand-toggle.tsx +17 -0
- package/src/components/features/data-table/fuzzy-filter.tsx +34 -0
- package/src/components/features/data-table/index.ts +2 -0
- package/src/components/features/data-table/sortable-header.tsx +37 -0
- package/src/components/features/page-heading.tsx +6 -1
- package/src/components/features/search-bar.tsx +1 -1
- package/src/components/features/sidebar-layout.tsx +6 -3
- package/src/components/icons/beta.tsx +11 -2
- package/src/components/icons/dot.tsx +16 -3
- package/src/components/icons/issue.tsx +11 -2
- package/src/components/icons/turtle.tsx +16 -3
- package/src/components/icons/update.tsx +6 -1
- package/src/components/icons/warning.tsx +11 -2
- package/src/components/molecules/opportunity/opportunity-disclaimer.tsx +13 -5
- package/src/components/molecules/opportunity/opportunity-list/hooks/index.ts +1 -1
- package/src/components/molecules/opportunity/opportunity-list/hooks/use-opportunity-filtering.ts +3 -3
- package/src/components/molecules/opportunity/opportunity-list/hooks/use-opportunity-grouping.ts +7 -3
- package/src/components/molecules/opportunity/opportunity-list/index.ts +1 -1
- package/src/components/molecules/opportunity/opportunity-list/opportunity-list.tsx +10 -4
- package/src/components/molecules/opportunity/opportunity-rate-estimator.tsx +5 -6
- package/src/components/molecules/opportunity/opportunity-section.tsx +23 -6
- package/src/components/molecules/opportunity/opportunity-selector.tsx +7 -3
- package/src/components/molecules/slippage-selector.tsx +44 -20
- package/src/components/molecules/swap-details.tsx +14 -5
- package/src/components/molecules/swap-input.tsx +12 -6
- package/src/components/molecules/tabs.tsx +16 -4
- package/src/components/molecules/token-selector.tsx +38 -20
- package/src/components/molecules/tx-status.tsx +105 -54
- package/src/components/molecules/widget/asset-list/asset-filters.tsx +4 -2
- package/src/components/molecules/widget/asset-list/asset-list.tsx +8 -3
- package/src/components/molecules/widget/asset-list/asset-row.tsx +1 -1
- package/src/components/molecules/widget/asset-list/hooks/index.ts +1 -1
- package/src/components/molecules/widget/asset-list/hooks/use-asset-filtering.ts +4 -2
- package/src/components/molecules/widget/asset-list/hooks/use-asset-grouping.ts +15 -6
- package/src/components/molecules/widget/base-selector.tsx +5 -5
- package/src/components/molecules/widget/campaign-item.tsx +12 -6
- package/src/components/molecules/widget/deal-item.tsx +20 -8
- package/src/components/molecules/widget/index.ts +4 -1
- package/src/components/molecules/widget/opportunity-item.tsx +22 -8
- package/src/components/molecules/widget/widget-item-stats.tsx +2 -2
- package/src/components/ui/alert-dialog.tsx +26 -9
- package/src/components/ui/animated-background/animated-background.tsx +14 -6
- package/src/components/ui/animated-background/index.ts +1 -1
- package/src/components/ui/avatar.tsx +12 -3
- package/src/components/ui/badge.tsx +5 -3
- package/src/components/ui/banner.tsx +9 -3
- package/src/components/ui/button.tsx +10 -5
- package/src/components/ui/card.tsx +32 -5
- package/src/components/ui/checkbox.tsx +5 -2
- package/src/components/ui/chip.tsx +10 -6
- package/src/components/ui/collapsible.tsx +15 -3
- package/src/components/ui/combobox.tsx +52 -25
- package/src/components/ui/command.tsx +31 -11
- package/src/components/ui/dialog.tsx +22 -8
- package/src/components/ui/dropdown.tsx +57 -20
- package/src/components/ui/field.tsx +40 -28
- package/src/components/ui/heading.tsx +31 -6
- package/src/components/ui/hover-card.tsx +35 -10
- package/src/components/ui/icon-animation.tsx +12 -12
- package/src/components/ui/icon-list.tsx +45 -18
- package/src/components/ui/info-card.tsx +13 -5
- package/src/components/ui/input-group.tsx +32 -20
- package/src/components/ui/input.tsx +5 -3
- package/src/components/ui/label.tsx +5 -2
- package/src/components/ui/multi-select.tsx +133 -61
- package/src/components/ui/navigation-bar.tsx +39 -22
- package/src/components/ui/navigation-menu.tsx +16 -9
- package/src/components/ui/opportunity-details-v1.tsx +9 -5
- package/src/components/ui/popover.tsx +10 -4
- package/src/components/ui/scroll-area.tsx +5 -3
- package/src/components/ui/select.tsx +25 -10
- package/src/components/ui/separator.tsx +6 -6
- package/src/components/ui/sheet.tsx +15 -6
- package/src/components/ui/sidebar.tsx +62 -26
- package/src/components/ui/slider.tsx +10 -5
- package/src/components/ui/switch.tsx +6 -3
- package/src/components/ui/table-shadcn.tsx +19 -9
- package/src/components/ui/table.tsx +12 -5
- package/src/components/ui/textarea.tsx +1 -1
- package/src/components/ui/toggle-group.tsx +12 -12
- package/src/components/ui/toggle.tsx +14 -14
- package/src/components/ui/tooltip.tsx +7 -3
- package/src/hooks/useIsMobile.ts +5 -2
- package/src/lib/utils.ts +3 -3
- package/src/styles/themes/index.css +1 -1
- package/src/styles/themes/semantic.css +51 -17
- package/src/styles/tokens/colors.css +54 -18
- package/src/styles/tokens/index.css +1 -1
- package/src/styles/tokens/spacing.css +39 -33
- package/src/styles/tokens/typography.css +61 -60
- package/src/tokens/index.ts +82 -82
- package/dist/types/components/features/data-table.d.ts +0 -9
- package/dist/types/components/features/data-table.d.ts.map +0 -1
- package/src/components/features/data-table.tsx +0 -96
|
@@ -14,7 +14,7 @@ function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
|
|
|
14
14
|
className={cn(
|
|
15
15
|
"flex flex-col gap-6",
|
|
16
16
|
"has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3",
|
|
17
|
-
className
|
|
17
|
+
className,
|
|
18
18
|
)}
|
|
19
19
|
{...props}
|
|
20
20
|
/>
|
|
@@ -34,7 +34,7 @@ function FieldLegend({
|
|
|
34
34
|
"mb-3 font-medium",
|
|
35
35
|
"data-[variant=legend]:text-base",
|
|
36
36
|
"data-[variant=label]:text-sm",
|
|
37
|
-
className
|
|
37
|
+
className,
|
|
38
38
|
)}
|
|
39
39
|
{...props}
|
|
40
40
|
/>
|
|
@@ -47,33 +47,36 @@ function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
47
47
|
data-slot="field-group"
|
|
48
48
|
className={cn(
|
|
49
49
|
"group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4",
|
|
50
|
-
className
|
|
50
|
+
className,
|
|
51
51
|
)}
|
|
52
52
|
{...props}
|
|
53
53
|
/>
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
const fieldVariants = cva(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"flex-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
57
|
+
const fieldVariants = cva(
|
|
58
|
+
"group/field data-[invalid=true]:text-destructive flex w-full gap-3",
|
|
59
|
+
{
|
|
60
|
+
variants: {
|
|
61
|
+
orientation: {
|
|
62
|
+
vertical: ["flex-col [&>*]:w-full [&>.sr-only]:w-auto"],
|
|
63
|
+
horizontal: [
|
|
64
|
+
"flex-row items-center",
|
|
65
|
+
"[&>[data-slot=field-label]]:flex-auto",
|
|
66
|
+
"has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
|
|
67
|
+
],
|
|
68
|
+
responsive: [
|
|
69
|
+
"flex-col @md/field-group:flex-row @md/field-group:items-center [&>*]:w-full @md/field-group:[&>*]:w-auto [&>.sr-only]:w-auto",
|
|
70
|
+
"@md/field-group:[&>[data-slot=field-label]]:flex-auto",
|
|
71
|
+
"@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
defaultVariants: {
|
|
76
|
+
orientation: "vertical",
|
|
71
77
|
},
|
|
72
78
|
},
|
|
73
|
-
|
|
74
|
-
orientation: "vertical",
|
|
75
|
-
},
|
|
76
|
-
});
|
|
79
|
+
);
|
|
77
80
|
|
|
78
81
|
function Field({
|
|
79
82
|
className,
|
|
@@ -95,13 +98,19 @@ function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
95
98
|
return (
|
|
96
99
|
<div
|
|
97
100
|
data-slot="field-content"
|
|
98
|
-
className={cn(
|
|
101
|
+
className={cn(
|
|
102
|
+
"group/field-content flex flex-1 flex-col gap-1.5 leading-snug",
|
|
103
|
+
className,
|
|
104
|
+
)}
|
|
99
105
|
{...props}
|
|
100
106
|
/>
|
|
101
107
|
);
|
|
102
108
|
}
|
|
103
109
|
|
|
104
|
-
function FieldLabel({
|
|
110
|
+
function FieldLabel({
|
|
111
|
+
className,
|
|
112
|
+
...props
|
|
113
|
+
}: React.ComponentProps<typeof Label>) {
|
|
105
114
|
return (
|
|
106
115
|
<Label
|
|
107
116
|
data-slot="field-label"
|
|
@@ -109,7 +118,7 @@ function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>)
|
|
|
109
118
|
"group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50",
|
|
110
119
|
"has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>*]:data-[slot=field]:p-4",
|
|
111
120
|
"has-data-[state=checked]:bg-primary/5 has-data-[state=checked]:border-primary dark:has-data-[state=checked]:bg-primary/10",
|
|
112
|
-
className
|
|
121
|
+
className,
|
|
113
122
|
)}
|
|
114
123
|
{...props}
|
|
115
124
|
/>
|
|
@@ -122,7 +131,7 @@ function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
122
131
|
data-slot="field-label"
|
|
123
132
|
className={cn(
|
|
124
133
|
"flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50",
|
|
125
|
-
className
|
|
134
|
+
className,
|
|
126
135
|
)}
|
|
127
136
|
{...props}
|
|
128
137
|
/>
|
|
@@ -137,7 +146,7 @@ function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
|
|
|
137
146
|
"text-muted-foreground text-sm leading-normal font-normal group-has-[[data-orientation=horizontal]]/field:text-balance",
|
|
138
147
|
"last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5",
|
|
139
148
|
"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
|
|
140
|
-
className
|
|
149
|
+
className,
|
|
141
150
|
)}
|
|
142
151
|
{...props}
|
|
143
152
|
/>
|
|
@@ -157,7 +166,7 @@ function FieldSeparator({
|
|
|
157
166
|
data-content={!!children}
|
|
158
167
|
className={cn(
|
|
159
168
|
"relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2",
|
|
160
|
-
className
|
|
169
|
+
className,
|
|
161
170
|
)}
|
|
162
171
|
{...props}
|
|
163
172
|
>
|
|
@@ -197,7 +206,10 @@ function FieldError({
|
|
|
197
206
|
|
|
198
207
|
return (
|
|
199
208
|
<ul className="ml-4 flex list-disc flex-col gap-1">
|
|
200
|
-
{errors.map(
|
|
209
|
+
{errors.map(
|
|
210
|
+
(error, index) =>
|
|
211
|
+
error?.message && <li key={index}>{error.message}</li>,
|
|
212
|
+
)}
|
|
201
213
|
</ul>
|
|
202
214
|
);
|
|
203
215
|
}, [children, errors]);
|
|
@@ -5,7 +5,12 @@ export type TypographyProps = { children: React.ReactNode; className?: string };
|
|
|
5
5
|
|
|
6
6
|
export function HeadingH1({ children, className }: TypographyProps) {
|
|
7
7
|
return (
|
|
8
|
-
<h1
|
|
8
|
+
<h1
|
|
9
|
+
className={cn(
|
|
10
|
+
"scroll-m-20 text-4xl font-semibold tracking-tight text-balance",
|
|
11
|
+
className,
|
|
12
|
+
)}
|
|
13
|
+
>
|
|
9
14
|
{children}
|
|
10
15
|
</h1>
|
|
11
16
|
);
|
|
@@ -13,7 +18,12 @@ export function HeadingH1({ children, className }: TypographyProps) {
|
|
|
13
18
|
|
|
14
19
|
export function HeadingH2({ children, className }: TypographyProps) {
|
|
15
20
|
return (
|
|
16
|
-
<h2
|
|
21
|
+
<h2
|
|
22
|
+
className={cn(
|
|
23
|
+
"scroll-m-20 text-3xl font-normal tracking-tight first:mt-0",
|
|
24
|
+
className,
|
|
25
|
+
)}
|
|
26
|
+
>
|
|
17
27
|
{children}
|
|
18
28
|
</h2>
|
|
19
29
|
);
|
|
@@ -21,18 +31,33 @@ export function HeadingH2({ children, className }: TypographyProps) {
|
|
|
21
31
|
|
|
22
32
|
export function HeadingH3({ children, className }: TypographyProps) {
|
|
23
33
|
return (
|
|
24
|
-
<h3
|
|
34
|
+
<h3
|
|
35
|
+
className={cn(
|
|
36
|
+
"scroll-m-20 text-xl font-normal tracking-tight",
|
|
37
|
+
className,
|
|
38
|
+
)}
|
|
39
|
+
>
|
|
40
|
+
{children}
|
|
41
|
+
</h3>
|
|
25
42
|
);
|
|
26
43
|
}
|
|
27
44
|
|
|
28
45
|
export function HeadingH4({ children, className }: TypographyProps) {
|
|
29
46
|
return (
|
|
30
|
-
<h4
|
|
47
|
+
<h4
|
|
48
|
+
className={cn("scroll-m-20 text-lg font-light tracking-tight", className)}
|
|
49
|
+
>
|
|
50
|
+
{children}
|
|
51
|
+
</h4>
|
|
31
52
|
);
|
|
32
53
|
}
|
|
33
54
|
|
|
34
55
|
export function HeadingH5({ children, className }: TypographyProps) {
|
|
35
|
-
return
|
|
56
|
+
return (
|
|
57
|
+
<h5 className={cn("scroll-m-20 font-light tracking-tight", className)}>
|
|
58
|
+
{children}
|
|
59
|
+
</h5>
|
|
60
|
+
);
|
|
36
61
|
}
|
|
37
62
|
|
|
38
63
|
export function HeadingH6({ children, className }: TypographyProps) {
|
|
@@ -40,7 +65,7 @@ export function HeadingH6({ children, className }: TypographyProps) {
|
|
|
40
65
|
<h6
|
|
41
66
|
className={cn(
|
|
42
67
|
"text-muted-foreground scroll-m-20 text-sm font-light tracking-tight",
|
|
43
|
-
className
|
|
68
|
+
className,
|
|
44
69
|
)}
|
|
45
70
|
>
|
|
46
71
|
{children}
|
|
@@ -45,15 +45,21 @@ const hoverCardContentVariants = cva(
|
|
|
45
45
|
rounded: "default",
|
|
46
46
|
gradientBorder: "none",
|
|
47
47
|
},
|
|
48
|
-
}
|
|
48
|
+
},
|
|
49
49
|
);
|
|
50
50
|
|
|
51
|
-
function HoverCard({
|
|
51
|
+
function HoverCard({
|
|
52
|
+
...props
|
|
53
|
+
}: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
|
|
52
54
|
return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
function HoverCardTrigger({
|
|
56
|
-
|
|
57
|
+
function HoverCardTrigger({
|
|
58
|
+
...props
|
|
59
|
+
}: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
|
|
60
|
+
return (
|
|
61
|
+
<HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
|
|
62
|
+
);
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
function HoverCardContent({
|
|
@@ -68,16 +74,25 @@ function HoverCardContent({
|
|
|
68
74
|
}: React.ComponentProps<typeof HoverCardPrimitive.Content> &
|
|
69
75
|
VariantProps<typeof hoverCardContentVariants>) {
|
|
70
76
|
// Auto-apply gradient border for container variant if not specified
|
|
71
|
-
const finalGradientBorder =
|
|
77
|
+
const finalGradientBorder =
|
|
78
|
+
gradientBorder ?? (variant === "container" ? "white" : "none");
|
|
72
79
|
|
|
73
80
|
const hasGradientBorder = finalGradientBorder !== "none";
|
|
74
81
|
|
|
75
82
|
// Get the gradient border classes
|
|
76
|
-
const gradientClasses = hoverCardContentVariants({
|
|
83
|
+
const gradientClasses = hoverCardContentVariants({
|
|
84
|
+
gradientBorder: finalGradientBorder,
|
|
85
|
+
});
|
|
77
86
|
|
|
78
87
|
// Get the main hover card classes without gradient
|
|
79
88
|
const hoverCardClasses = cn(
|
|
80
|
-
hoverCardContentVariants({
|
|
89
|
+
hoverCardContentVariants({
|
|
90
|
+
variant,
|
|
91
|
+
padding,
|
|
92
|
+
rounded,
|
|
93
|
+
gradientBorder: "none",
|
|
94
|
+
className,
|
|
95
|
+
}),
|
|
81
96
|
);
|
|
82
97
|
|
|
83
98
|
// Get the rounded class for the wrapper
|
|
@@ -85,7 +100,9 @@ function HoverCardContent({
|
|
|
85
100
|
|
|
86
101
|
return (
|
|
87
102
|
<HoverCardPrimitive.Portal
|
|
88
|
-
container={
|
|
103
|
+
container={
|
|
104
|
+
document.querySelectorAll(".turtle-widget-root")[0] ?? undefined
|
|
105
|
+
}
|
|
89
106
|
data-slot="hover-card-portal"
|
|
90
107
|
>
|
|
91
108
|
{hasGradientBorder ? (
|
|
@@ -96,7 +113,10 @@ function HoverCardContent({
|
|
|
96
113
|
className={cn(gradientClasses, roundedClass, "p-[1px]")}
|
|
97
114
|
{...props}
|
|
98
115
|
>
|
|
99
|
-
<div
|
|
116
|
+
<div
|
|
117
|
+
data-slot="hover-card-content-inner"
|
|
118
|
+
className={hoverCardClasses}
|
|
119
|
+
/>
|
|
100
120
|
</HoverCardPrimitive.Content>
|
|
101
121
|
) : (
|
|
102
122
|
<HoverCardPrimitive.Content
|
|
@@ -111,4 +131,9 @@ function HoverCardContent({
|
|
|
111
131
|
);
|
|
112
132
|
}
|
|
113
133
|
|
|
114
|
-
export {
|
|
134
|
+
export {
|
|
135
|
+
HoverCard,
|
|
136
|
+
HoverCardTrigger,
|
|
137
|
+
HoverCardContent,
|
|
138
|
+
hoverCardContentVariants,
|
|
139
|
+
};
|
|
@@ -8,10 +8,10 @@ const iconAnimationVariants = cva(
|
|
|
8
8
|
{
|
|
9
9
|
variants: {
|
|
10
10
|
size: {
|
|
11
|
-
default: "
|
|
12
|
-
sm: "
|
|
13
|
-
lg: "
|
|
14
|
-
xl: "
|
|
11
|
+
default: "h-12 w-12",
|
|
12
|
+
sm: "h-8 w-8",
|
|
13
|
+
lg: "h-16 w-16",
|
|
14
|
+
xl: "h-20 w-20",
|
|
15
15
|
},
|
|
16
16
|
variant: {
|
|
17
17
|
default: "bg-background",
|
|
@@ -22,7 +22,7 @@ const iconAnimationVariants = cva(
|
|
|
22
22
|
size: "default",
|
|
23
23
|
variant: "default",
|
|
24
24
|
},
|
|
25
|
-
}
|
|
25
|
+
},
|
|
26
26
|
);
|
|
27
27
|
|
|
28
28
|
export interface IconAnimationProps
|
|
@@ -44,12 +44,12 @@ const IconAnimation = React.forwardRef<HTMLDivElement, IconAnimationProps>(
|
|
|
44
44
|
<div
|
|
45
45
|
className={cn(
|
|
46
46
|
"absolute inset-0 rounded-full",
|
|
47
|
-
"bg-gradient-to-r from-transparent
|
|
47
|
+
"via-primary bg-gradient-to-r from-transparent to-transparent",
|
|
48
48
|
"animate-spin",
|
|
49
49
|
{
|
|
50
50
|
"animate-spin": spinning,
|
|
51
51
|
"animate-none": !spinning,
|
|
52
|
-
}
|
|
52
|
+
},
|
|
53
53
|
)}
|
|
54
54
|
style={{
|
|
55
55
|
background: spinning
|
|
@@ -62,21 +62,21 @@ const IconAnimation = React.forwardRef<HTMLDivElement, IconAnimationProps>(
|
|
|
62
62
|
{/* Inner circle to create the border effect */}
|
|
63
63
|
<div
|
|
64
64
|
className={cn(
|
|
65
|
-
"
|
|
66
|
-
variant === "transparent" ? "bg-transparent" : "bg-background"
|
|
65
|
+
"h-full w-full rounded-full",
|
|
66
|
+
variant === "transparent" ? "bg-transparent" : "bg-background",
|
|
67
67
|
)}
|
|
68
68
|
/>
|
|
69
69
|
</div>
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
{/* Icon container - stays fixed */}
|
|
72
72
|
<div className="relative z-10 flex items-center justify-center">
|
|
73
73
|
{children}
|
|
74
74
|
</div>
|
|
75
75
|
</div>
|
|
76
76
|
);
|
|
77
|
-
}
|
|
77
|
+
},
|
|
78
78
|
);
|
|
79
79
|
|
|
80
80
|
IconAnimation.displayName = "IconAnimation";
|
|
81
81
|
|
|
82
|
-
export { IconAnimation, iconAnimationVariants };
|
|
82
|
+
export { IconAnimation, iconAnimationVariants };
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { cn } from "@/lib/utils";
|
|
3
3
|
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
Tooltip,
|
|
6
|
+
TooltipContent,
|
|
7
|
+
TooltipProvider,
|
|
8
|
+
TooltipTrigger,
|
|
9
|
+
} from "@/components/ui/tooltip";
|
|
5
10
|
import { useMemo } from "react";
|
|
6
11
|
|
|
7
12
|
interface IconListItem {
|
|
@@ -27,22 +32,34 @@ const sizeClasses = {
|
|
|
27
32
|
|
|
28
33
|
const IconList = React.forwardRef<HTMLDivElement, IconListProps>(
|
|
29
34
|
(
|
|
30
|
-
{
|
|
31
|
-
|
|
35
|
+
{
|
|
36
|
+
className,
|
|
37
|
+
items,
|
|
38
|
+
label,
|
|
39
|
+
size = "sm",
|
|
40
|
+
maxVisible = 6,
|
|
41
|
+
showTooltip = false,
|
|
42
|
+
...props
|
|
43
|
+
},
|
|
44
|
+
ref,
|
|
32
45
|
) => {
|
|
33
|
-
const [loadedImages, setLoadedImages] = React.useState<Set<string>>(
|
|
46
|
+
const [loadedImages, setLoadedImages] = React.useState<Set<string>>(
|
|
47
|
+
new Set(),
|
|
48
|
+
);
|
|
34
49
|
|
|
35
50
|
if (!items || items.length === 0) return null;
|
|
36
51
|
|
|
37
52
|
const uniqueItems = useMemo(() => {
|
|
38
|
-
const normalized: IconListItem[] = items.map(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
53
|
+
const normalized: IconListItem[] = items.map(
|
|
54
|
+
(item: IconListItem | string, index: number) =>
|
|
55
|
+
typeof item === "string"
|
|
56
|
+
? { icon: item, name: "", id: `item-${index}` }
|
|
57
|
+
: { ...item, id: item.id || `item-${index}` },
|
|
42
58
|
);
|
|
43
59
|
|
|
44
60
|
const unique = normalized.filter(
|
|
45
|
-
(item, index, self) =>
|
|
61
|
+
(item, index, self) =>
|
|
62
|
+
index === self.findIndex((t) => t.icon === item.icon),
|
|
46
63
|
);
|
|
47
64
|
|
|
48
65
|
return unique;
|
|
@@ -61,8 +78,8 @@ const IconList = React.forwardRef<HTMLDivElement, IconListProps>(
|
|
|
61
78
|
key={item.id || index}
|
|
62
79
|
className={cn(
|
|
63
80
|
sizeClasses[size],
|
|
64
|
-
"border
|
|
65
|
-
!loadedImages.has(item.icon) && "animate-pulse"
|
|
81
|
+
"border-background border transition-all hover:z-10 hover:scale-110",
|
|
82
|
+
!loadedImages.has(item.icon) && "animate-pulse",
|
|
66
83
|
)}
|
|
67
84
|
>
|
|
68
85
|
<AvatarImage
|
|
@@ -70,13 +87,18 @@ const IconList = React.forwardRef<HTMLDivElement, IconListProps>(
|
|
|
70
87
|
alt={item.name || "Icon"}
|
|
71
88
|
onLoad={() => handleImageLoad(item.icon)}
|
|
72
89
|
/>
|
|
73
|
-
<AvatarFallback
|
|
90
|
+
<AvatarFallback
|
|
91
|
+
className={cn("font-medium", sizeClasses[size].split(" ").pop())}
|
|
92
|
+
>
|
|
74
93
|
{item.name ? item.name.slice(0, 2).toUpperCase() : "?"}
|
|
75
94
|
</AvatarFallback>
|
|
76
95
|
</Avatar>
|
|
77
96
|
);
|
|
78
97
|
|
|
79
|
-
const renderWithTooltip = (
|
|
98
|
+
const renderWithTooltip = (
|
|
99
|
+
content: React.ReactNode,
|
|
100
|
+
tooltipText: string,
|
|
101
|
+
) => {
|
|
80
102
|
if (!showTooltip || !tooltipText) return content;
|
|
81
103
|
|
|
82
104
|
return (
|
|
@@ -98,7 +120,9 @@ const IconList = React.forwardRef<HTMLDivElement, IconListProps>(
|
|
|
98
120
|
aria-label={label || "Icon list"}
|
|
99
121
|
{...props}
|
|
100
122
|
>
|
|
101
|
-
{label &&
|
|
123
|
+
{label && (
|
|
124
|
+
<span className="text-muted-foreground mr-1 text-xs">{label}:</span>
|
|
125
|
+
)}
|
|
102
126
|
<div className="flex -space-x-1">
|
|
103
127
|
{visibleItems.map((item, index) => (
|
|
104
128
|
<div key={item.id || index} role="listitem">
|
|
@@ -111,12 +135,15 @@ const IconList = React.forwardRef<HTMLDivElement, IconListProps>(
|
|
|
111
135
|
<Avatar
|
|
112
136
|
className={cn(
|
|
113
137
|
sizeClasses[size],
|
|
114
|
-
"border
|
|
138
|
+
"border-background bg-muted hover:bg-muted/80 border transition-all",
|
|
115
139
|
)}
|
|
116
140
|
aria-label={`${remainingCount} more items`}
|
|
117
141
|
>
|
|
118
142
|
<AvatarFallback
|
|
119
|
-
className={cn(
|
|
143
|
+
className={cn(
|
|
144
|
+
"font-semibold",
|
|
145
|
+
sizeClasses[size].split(" ").pop(),
|
|
146
|
+
)}
|
|
120
147
|
>
|
|
121
148
|
+{remainingCount}
|
|
122
149
|
</AvatarFallback>
|
|
@@ -124,7 +151,7 @@ const IconList = React.forwardRef<HTMLDivElement, IconListProps>(
|
|
|
124
151
|
hiddenItems
|
|
125
152
|
.map((item) => item.name)
|
|
126
153
|
.filter(Boolean)
|
|
127
|
-
.join(", ") || `${remainingCount} more items
|
|
154
|
+
.join(", ") || `${remainingCount} more items`,
|
|
128
155
|
)}
|
|
129
156
|
</div>
|
|
130
157
|
)}
|
|
@@ -132,7 +159,7 @@ const IconList = React.forwardRef<HTMLDivElement, IconListProps>(
|
|
|
132
159
|
</div>
|
|
133
160
|
</TooltipProvider>
|
|
134
161
|
);
|
|
135
|
-
}
|
|
162
|
+
},
|
|
136
163
|
);
|
|
137
164
|
|
|
138
165
|
IconList.displayName = "IconList";
|
|
@@ -33,7 +33,7 @@ const valueVariants = cva("font-bold", {
|
|
|
33
33
|
},
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
const titleVariants = cva("
|
|
36
|
+
const titleVariants = cva("text-muted-foreground font-medium", {
|
|
37
37
|
variants: {
|
|
38
38
|
size: {
|
|
39
39
|
sm: "text-xs",
|
|
@@ -71,7 +71,7 @@ const InfoCard = React.forwardRef<HTMLDivElement, InfoCardProps>(
|
|
|
71
71
|
className,
|
|
72
72
|
...props
|
|
73
73
|
},
|
|
74
|
-
ref
|
|
74
|
+
ref,
|
|
75
75
|
) => {
|
|
76
76
|
return (
|
|
77
77
|
<Card
|
|
@@ -83,7 +83,13 @@ const InfoCard = React.forwardRef<HTMLDivElement, InfoCardProps>(
|
|
|
83
83
|
>
|
|
84
84
|
{/* Icon & Title */}
|
|
85
85
|
<div className="flex gap-2">
|
|
86
|
-
{iconUrl &&
|
|
86
|
+
{iconUrl && (
|
|
87
|
+
<img
|
|
88
|
+
src={iconUrl}
|
|
89
|
+
alt={`${title}-icon`}
|
|
90
|
+
className="h-5 w-5 rounded-full"
|
|
91
|
+
/>
|
|
92
|
+
)}
|
|
87
93
|
<p className={titleVariants({ size: titleSize })}>{title}</p>
|
|
88
94
|
</div>
|
|
89
95
|
|
|
@@ -91,10 +97,12 @@ const InfoCard = React.forwardRef<HTMLDivElement, InfoCardProps>(
|
|
|
91
97
|
<p className={cn("text-foreground")}>{value}</p>
|
|
92
98
|
|
|
93
99
|
{/* Subtitle */}
|
|
94
|
-
{subtitle &&
|
|
100
|
+
{subtitle && (
|
|
101
|
+
<p className="text-muted-foreground/70 text-xs">{subtitle}</p>
|
|
102
|
+
)}
|
|
95
103
|
</Card>
|
|
96
104
|
);
|
|
97
|
-
}
|
|
105
|
+
},
|
|
98
106
|
);
|
|
99
107
|
|
|
100
108
|
InfoCard.displayName = "InfoCard";
|
|
@@ -29,7 +29,7 @@ function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
29
29
|
// Error state.
|
|
30
30
|
"has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40",
|
|
31
31
|
|
|
32
|
-
className
|
|
32
|
+
className,
|
|
33
33
|
)}
|
|
34
34
|
{...props}
|
|
35
35
|
/>
|
|
@@ -41,8 +41,10 @@ const inputGroupAddonVariants = cva(
|
|
|
41
41
|
{
|
|
42
42
|
variants: {
|
|
43
43
|
align: {
|
|
44
|
-
"inline-start":
|
|
45
|
-
|
|
44
|
+
"inline-start":
|
|
45
|
+
"order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",
|
|
46
|
+
"inline-end":
|
|
47
|
+
"order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]",
|
|
46
48
|
"block-start":
|
|
47
49
|
"order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5 [.border-b]:pb-3",
|
|
48
50
|
"block-end":
|
|
@@ -52,7 +54,7 @@ const inputGroupAddonVariants = cva(
|
|
|
52
54
|
defaultVariants: {
|
|
53
55
|
align: "inline-start",
|
|
54
56
|
},
|
|
55
|
-
}
|
|
57
|
+
},
|
|
56
58
|
);
|
|
57
59
|
|
|
58
60
|
function InputGroupAddon({
|
|
@@ -77,19 +79,23 @@ function InputGroupAddon({
|
|
|
77
79
|
);
|
|
78
80
|
}
|
|
79
81
|
|
|
80
|
-
const inputGroupButtonVariants = cva(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
const inputGroupButtonVariants = cva(
|
|
83
|
+
"flex items-center gap-2 text-sm shadow-none",
|
|
84
|
+
{
|
|
85
|
+
variants: {
|
|
86
|
+
size: {
|
|
87
|
+
xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
|
|
88
|
+
sm: "h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5",
|
|
89
|
+
"icon-xs":
|
|
90
|
+
"size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",
|
|
91
|
+
"icon-sm": "size-8 p-0 has-[>svg]:p-0",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
defaultVariants: {
|
|
95
|
+
size: "xs",
|
|
87
96
|
},
|
|
88
97
|
},
|
|
89
|
-
|
|
90
|
-
size: "xs",
|
|
91
|
-
},
|
|
92
|
-
});
|
|
98
|
+
);
|
|
93
99
|
|
|
94
100
|
function InputGroupButton({
|
|
95
101
|
className,
|
|
@@ -115,33 +121,39 @@ function InputGroupText({ className, ...props }: React.ComponentProps<"span">) {
|
|
|
115
121
|
<span
|
|
116
122
|
className={cn(
|
|
117
123
|
"text-muted-foreground flex items-center gap-2 text-sm [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
|
|
118
|
-
className
|
|
124
|
+
className,
|
|
119
125
|
)}
|
|
120
126
|
{...props}
|
|
121
127
|
/>
|
|
122
128
|
);
|
|
123
129
|
}
|
|
124
130
|
|
|
125
|
-
function InputGroupInput({
|
|
131
|
+
function InputGroupInput({
|
|
132
|
+
className,
|
|
133
|
+
...props
|
|
134
|
+
}: React.ComponentProps<"input">) {
|
|
126
135
|
return (
|
|
127
136
|
<Input
|
|
128
137
|
data-slot="input-group-control"
|
|
129
138
|
className={cn(
|
|
130
139
|
"flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent",
|
|
131
|
-
className
|
|
140
|
+
className,
|
|
132
141
|
)}
|
|
133
142
|
{...props}
|
|
134
143
|
/>
|
|
135
144
|
);
|
|
136
145
|
}
|
|
137
146
|
|
|
138
|
-
function InputGroupTextarea({
|
|
147
|
+
function InputGroupTextarea({
|
|
148
|
+
className,
|
|
149
|
+
...props
|
|
150
|
+
}: React.ComponentProps<"textarea">) {
|
|
139
151
|
return (
|
|
140
152
|
<Textarea
|
|
141
153
|
data-slot="input-group-control"
|
|
142
154
|
className={cn(
|
|
143
155
|
"flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent",
|
|
144
|
-
className
|
|
156
|
+
className,
|
|
145
157
|
)}
|
|
146
158
|
{...props}
|
|
147
159
|
/>
|