@turtleclub/ui 0.7.0-beta.32 → 0.7.0-beta.34
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/dist/index.cjs +10331 -110
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7652 -47844
- package/dist/index.js.map +1 -1
- package/dist/types/components/features/sidebar-layout.d.ts +2 -0
- package/dist/types/components/features/sidebar-layout.d.ts.map +1 -1
- package/dist/types/components/ui/chart.d.ts +1 -1
- package/dist/types/components/ui/chart.d.ts.map +1 -1
- package/package.json +26 -22
- package/.prettierrc.json +0 -4
- package/.turbo/turbo-build.log +0 -182
- package/CHANGELOG.md +0 -795
- package/components.json +0 -21
- package/src/components/charts/QUICK_REFERENCE.md +0 -323
- package/src/components/charts/README.md +0 -658
- package/src/components/charts/RECHARTS_FEATURES.md +0 -458
- package/src/components/charts/area-chart.tsx +0 -248
- package/src/components/charts/bar-chart.tsx +0 -362
- package/src/components/charts/index.ts +0 -4
- package/src/components/charts/pie-chart.tsx +0 -277
- package/src/components/charts/radial-chart.tsx +0 -312
- package/src/components/features/api-status/index.tsx +0 -23
- package/src/components/features/data-table/data-table.tsx +0 -538
- package/src/components/features/data-table/expand-toggle.tsx +0 -17
- package/src/components/features/data-table/fuzzy-filter.tsx +0 -34
- package/src/components/features/data-table/index.ts +0 -3
- package/src/components/features/data-table/item-info.tsx +0 -19
- package/src/components/features/data-table/skeleton.tsx +0 -23
- package/src/components/features/data-table/sort-dropdown.tsx +0 -118
- package/src/components/features/data-table/sortable-header.tsx +0 -37
- package/src/components/features/index.ts +0 -6
- package/src/components/features/page-heading.tsx +0 -27
- package/src/components/features/search-bar.tsx +0 -55
- package/src/components/features/segmented-navigation.tsx +0 -18
- package/src/components/features/sidebar-layout.tsx +0 -193
- package/src/components/features/turtle-tooltip.tsx +0 -67
- package/src/components/icons/arrow.tsx +0 -23
- package/src/components/icons/beta.tsx +0 -95
- package/src/components/icons/dot.tsx +0 -102
- package/src/components/icons/index.ts +0 -7
- package/src/components/icons/issue.tsx +0 -106
- package/src/components/icons/turtle.tsx +0 -156
- package/src/components/icons/update.tsx +0 -113
- package/src/components/icons/warning.tsx +0 -95
- package/src/components/molecules/index.ts +0 -9
- package/src/components/molecules/opportunity/index.ts +0 -10
- package/src/components/molecules/opportunity/opportunity-apr.tsx +0 -129
- package/src/components/molecules/opportunity/opportunity-disclaimer.tsx +0 -46
- package/src/components/molecules/opportunity/opportunity-rate-estimator.tsx +0 -62
- package/src/components/molecules/opportunity/opportunity-section.tsx +0 -113
- package/src/components/molecules/opportunity/opportunity-selector.tsx +0 -30
- package/src/components/molecules/opportunity/opportunity-type.tsx +0 -16
- package/src/components/molecules/route-details.tsx +0 -112
- package/src/components/molecules/slippage-selector.tsx +0 -200
- package/src/components/molecules/swap-details.tsx +0 -55
- package/src/components/molecules/swap-input.tsx +0 -186
- package/src/components/molecules/tabs.tsx +0 -79
- package/src/components/molecules/token-selector.tsx +0 -180
- package/src/components/molecules/tx-status.tsx +0 -312
- package/src/components/molecules/widget/asset-list/asset-filters.tsx +0 -113
- package/src/components/molecules/widget/asset-list/asset-list.tsx +0 -178
- package/src/components/molecules/widget/asset-list/asset-row.tsx +0 -45
- package/src/components/molecules/widget/asset-list/hooks/index.ts +0 -2
- package/src/components/molecules/widget/asset-list/hooks/use-asset-filtering.ts +0 -44
- package/src/components/molecules/widget/asset-list/hooks/use-asset-grouping.ts +0 -87
- package/src/components/molecules/widget/asset-list/index.ts +0 -3
- package/src/components/molecules/widget/base-selector.tsx +0 -121
- package/src/components/molecules/widget/campaign-item.tsx +0 -82
- package/src/components/molecules/widget/deal-item.tsx +0 -92
- package/src/components/molecules/widget/index.ts +0 -36
- package/src/components/molecules/widget/opportunity-item.tsx +0 -105
- package/src/components/molecules/widget/widget-item-stats.tsx +0 -50
- package/src/components/molecules/widget/widget-item.tsx +0 -139
- package/src/components/molecules/widget/widget-list-items.tsx +0 -86
- package/src/components/ui/alert-dialog.tsx +0 -163
- package/src/components/ui/animated-background/animated-background.tsx +0 -182
- package/src/components/ui/animated-background/index.ts +0 -1
- package/src/components/ui/avatar.tsx +0 -73
- package/src/components/ui/badge.tsx +0 -59
- package/src/components/ui/banner.tsx +0 -84
- package/src/components/ui/button.tsx +0 -100
- package/src/components/ui/card.tsx +0 -119
- package/src/components/ui/chart.tsx +0 -346
- package/src/components/ui/checkbox.tsx +0 -32
- package/src/components/ui/chip.tsx +0 -52
- package/src/components/ui/collapsible.tsx +0 -34
- package/src/components/ui/combobox.tsx +0 -730
- package/src/components/ui/command.tsx +0 -184
- package/src/components/ui/dialog.tsx +0 -129
- package/src/components/ui/dropdown.tsx +0 -316
- package/src/components/ui/field.tsx +0 -244
- package/src/components/ui/heading.tsx +0 -74
- package/src/components/ui/hover-card.tsx +0 -139
- package/src/components/ui/icon-animation.tsx +0 -82
- package/src/components/ui/icon-list.tsx +0 -168
- package/src/components/ui/index.ts +0 -48
- package/src/components/ui/info-card.tsx +0 -110
- package/src/components/ui/input-group.tsx +0 -170
- package/src/components/ui/input.tsx +0 -72
- package/src/components/ui/label-with-icon.tsx +0 -122
- package/src/components/ui/label.tsx +0 -24
- package/src/components/ui/multi-select.tsx +0 -1090
- package/src/components/ui/navigation-bar.tsx +0 -153
- package/src/components/ui/navigation-menu.tsx +0 -188
- package/src/components/ui/opportunity-details-v1.tsx +0 -104
- package/src/components/ui/pagination.tsx +0 -127
- package/src/components/ui/popover.tsx +0 -48
- package/src/components/ui/scroll-area.tsx +0 -64
- package/src/components/ui/segment-control.tsx +0 -146
- package/src/components/ui/select.tsx +0 -199
- package/src/components/ui/separator.tsx +0 -26
- package/src/components/ui/sheet.tsx +0 -139
- package/src/components/ui/sidebar.tsx +0 -728
- package/src/components/ui/skeleton.tsx +0 -14
- package/src/components/ui/slider.tsx +0 -58
- package/src/components/ui/sonner.tsx +0 -24
- package/src/components/ui/switch.tsx +0 -29
- package/src/components/ui/table-shadcn.tsx +0 -110
- package/src/components/ui/table.tsx +0 -117
- package/src/components/ui/textarea.tsx +0 -22
- package/src/components/ui/toggle-group.tsx +0 -71
- package/src/components/ui/toggle.tsx +0 -47
- package/src/components/ui/tooltip.tsx +0 -66
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useIsMobile.ts +0 -77
- package/src/index.ts +0 -16
- package/src/lib/utils.ts +0 -6
- package/src/styles/globals.css +0 -181
- package/src/styles/themes/index.css +0 -9
- package/src/styles/themes/semantic.css +0 -117
- package/src/styles/tokens/colors.css +0 -124
- package/src/styles/tokens/index.css +0 -15
- package/src/styles/tokens/radius.css +0 -18
- package/src/styles/tokens/spacing.css +0 -58
- package/src/styles/tokens/typography.css +0 -87
- package/src/tokens/index.ts +0 -108
- package/tsconfig.json +0 -20
- package/vite.config.js +0 -49
- /package/{src/images/enso.png → dist/enso-22FJ4GNK.png} +0 -0
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import React, { useMemo } from "react";
|
|
4
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
5
|
-
|
|
6
|
-
import { cn } from "@/lib/utils";
|
|
7
|
-
import { Label } from "@/components/ui/label";
|
|
8
|
-
import { Separator } from "@/components/ui/separator";
|
|
9
|
-
|
|
10
|
-
function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
|
|
11
|
-
return (
|
|
12
|
-
<fieldset
|
|
13
|
-
data-slot="field-set"
|
|
14
|
-
className={cn(
|
|
15
|
-
"flex flex-col gap-6",
|
|
16
|
-
"has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3",
|
|
17
|
-
className,
|
|
18
|
-
)}
|
|
19
|
-
{...props}
|
|
20
|
-
/>
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function FieldLegend({
|
|
25
|
-
className,
|
|
26
|
-
variant = "legend",
|
|
27
|
-
...props
|
|
28
|
-
}: React.ComponentProps<"legend"> & { variant?: "legend" | "label" }) {
|
|
29
|
-
return (
|
|
30
|
-
<legend
|
|
31
|
-
data-slot="field-legend"
|
|
32
|
-
data-variant={variant}
|
|
33
|
-
className={cn(
|
|
34
|
-
"mb-3 font-medium",
|
|
35
|
-
"data-[variant=legend]:text-base",
|
|
36
|
-
"data-[variant=label]:text-sm",
|
|
37
|
-
className,
|
|
38
|
-
)}
|
|
39
|
-
{...props}
|
|
40
|
-
/>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
45
|
-
return (
|
|
46
|
-
<div
|
|
47
|
-
data-slot="field-group"
|
|
48
|
-
className={cn(
|
|
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,
|
|
51
|
-
)}
|
|
52
|
-
{...props}
|
|
53
|
-
/>
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
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",
|
|
77
|
-
},
|
|
78
|
-
},
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
function Field({
|
|
82
|
-
className,
|
|
83
|
-
orientation = "vertical",
|
|
84
|
-
...props
|
|
85
|
-
}: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>) {
|
|
86
|
-
return (
|
|
87
|
-
<div
|
|
88
|
-
role="group"
|
|
89
|
-
data-slot="field"
|
|
90
|
-
data-orientation={orientation}
|
|
91
|
-
className={cn(fieldVariants({ orientation }), className)}
|
|
92
|
-
{...props}
|
|
93
|
-
/>
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
98
|
-
return (
|
|
99
|
-
<div
|
|
100
|
-
data-slot="field-content"
|
|
101
|
-
className={cn(
|
|
102
|
-
"group/field-content flex flex-1 flex-col gap-1.5 leading-snug",
|
|
103
|
-
className,
|
|
104
|
-
)}
|
|
105
|
-
{...props}
|
|
106
|
-
/>
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function FieldLabel({
|
|
111
|
-
className,
|
|
112
|
-
...props
|
|
113
|
-
}: React.ComponentProps<typeof Label>) {
|
|
114
|
-
return (
|
|
115
|
-
<Label
|
|
116
|
-
data-slot="field-label"
|
|
117
|
-
className={cn(
|
|
118
|
-
"group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50",
|
|
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",
|
|
120
|
-
"has-data-[state=checked]:bg-primary/5 has-data-[state=checked]:border-primary",
|
|
121
|
-
className,
|
|
122
|
-
)}
|
|
123
|
-
{...props}
|
|
124
|
-
/>
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
129
|
-
return (
|
|
130
|
-
<div
|
|
131
|
-
data-slot="field-label"
|
|
132
|
-
className={cn(
|
|
133
|
-
"flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50",
|
|
134
|
-
className,
|
|
135
|
-
)}
|
|
136
|
-
{...props}
|
|
137
|
-
/>
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
|
|
142
|
-
return (
|
|
143
|
-
<p
|
|
144
|
-
data-slot="field-description"
|
|
145
|
-
className={cn(
|
|
146
|
-
"text-muted-foreground text-sm leading-normal font-normal group-has-[[data-orientation=horizontal]]/field:text-balance",
|
|
147
|
-
"last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5",
|
|
148
|
-
"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
|
|
149
|
-
className,
|
|
150
|
-
)}
|
|
151
|
-
{...props}
|
|
152
|
-
/>
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function FieldSeparator({
|
|
157
|
-
children,
|
|
158
|
-
className,
|
|
159
|
-
...props
|
|
160
|
-
}: React.ComponentProps<"div"> & {
|
|
161
|
-
children?: React.ReactNode;
|
|
162
|
-
}) {
|
|
163
|
-
return (
|
|
164
|
-
<div
|
|
165
|
-
data-slot="field-separator"
|
|
166
|
-
data-content={!!children}
|
|
167
|
-
className={cn(
|
|
168
|
-
"relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2",
|
|
169
|
-
className,
|
|
170
|
-
)}
|
|
171
|
-
{...props}
|
|
172
|
-
>
|
|
173
|
-
<Separator className="absolute inset-0 top-1/2" />
|
|
174
|
-
{children && (
|
|
175
|
-
<span
|
|
176
|
-
className="bg-background text-muted-foreground relative mx-auto block w-fit px-2"
|
|
177
|
-
data-slot="field-separator-content"
|
|
178
|
-
>
|
|
179
|
-
{children}
|
|
180
|
-
</span>
|
|
181
|
-
)}
|
|
182
|
-
</div>
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function FieldError({
|
|
187
|
-
className,
|
|
188
|
-
children,
|
|
189
|
-
errors,
|
|
190
|
-
...props
|
|
191
|
-
}: React.ComponentProps<"div"> & {
|
|
192
|
-
errors?: Array<{ message?: string } | undefined>;
|
|
193
|
-
}) {
|
|
194
|
-
const content = useMemo(() => {
|
|
195
|
-
if (children) {
|
|
196
|
-
return children;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (!errors) {
|
|
200
|
-
return null;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (errors?.length === 1 && errors[0]?.message) {
|
|
204
|
-
return errors[0].message;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return (
|
|
208
|
-
<ul className="ml-4 flex list-disc flex-col gap-1">
|
|
209
|
-
{errors.map(
|
|
210
|
-
(error, index) =>
|
|
211
|
-
error?.message && <li key={index}>{error.message}</li>,
|
|
212
|
-
)}
|
|
213
|
-
</ul>
|
|
214
|
-
);
|
|
215
|
-
}, [children, errors]);
|
|
216
|
-
|
|
217
|
-
if (!content) {
|
|
218
|
-
return null;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return (
|
|
222
|
-
<div
|
|
223
|
-
role="alert"
|
|
224
|
-
data-slot="field-error"
|
|
225
|
-
className={cn("text-destructive text-sm font-normal", className)}
|
|
226
|
-
{...props}
|
|
227
|
-
>
|
|
228
|
-
{content}
|
|
229
|
-
</div>
|
|
230
|
-
);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
export {
|
|
234
|
-
Field,
|
|
235
|
-
FieldLabel,
|
|
236
|
-
FieldDescription,
|
|
237
|
-
FieldError,
|
|
238
|
-
FieldGroup,
|
|
239
|
-
FieldLegend,
|
|
240
|
-
FieldSeparator,
|
|
241
|
-
FieldSet,
|
|
242
|
-
FieldContent,
|
|
243
|
-
FieldTitle,
|
|
244
|
-
};
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { cn } from "@/lib/utils";
|
|
2
|
-
import React from "react";
|
|
3
|
-
|
|
4
|
-
export type TypographyProps = { children: React.ReactNode; className?: string };
|
|
5
|
-
|
|
6
|
-
export function HeadingH1({ children, className }: TypographyProps) {
|
|
7
|
-
return (
|
|
8
|
-
<h1
|
|
9
|
-
className={cn(
|
|
10
|
-
"scroll-m-20 text-4xl font-semibold tracking-tight text-balance",
|
|
11
|
-
className,
|
|
12
|
-
)}
|
|
13
|
-
>
|
|
14
|
-
{children}
|
|
15
|
-
</h1>
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function HeadingH2({ children, className }: TypographyProps) {
|
|
20
|
-
return (
|
|
21
|
-
<h2
|
|
22
|
-
className={cn(
|
|
23
|
-
"scroll-m-20 text-3xl font-normal tracking-tight first:mt-0",
|
|
24
|
-
className,
|
|
25
|
-
)}
|
|
26
|
-
>
|
|
27
|
-
{children}
|
|
28
|
-
</h2>
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function HeadingH3({ children, className }: TypographyProps) {
|
|
33
|
-
return (
|
|
34
|
-
<h3
|
|
35
|
-
className={cn(
|
|
36
|
-
"scroll-m-20 text-xl font-normal tracking-tight",
|
|
37
|
-
className,
|
|
38
|
-
)}
|
|
39
|
-
>
|
|
40
|
-
{children}
|
|
41
|
-
</h3>
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function HeadingH4({ children, className }: TypographyProps) {
|
|
46
|
-
return (
|
|
47
|
-
<h4
|
|
48
|
-
className={cn("scroll-m-20 text-lg font-light tracking-tight", className)}
|
|
49
|
-
>
|
|
50
|
-
{children}
|
|
51
|
-
</h4>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function HeadingH5({ children, className }: TypographyProps) {
|
|
56
|
-
return (
|
|
57
|
-
<h5 className={cn("scroll-m-20 font-light tracking-tight", className)}>
|
|
58
|
-
{children}
|
|
59
|
-
</h5>
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function HeadingH6({ children, className }: TypographyProps) {
|
|
64
|
-
return (
|
|
65
|
-
<h6
|
|
66
|
-
className={cn(
|
|
67
|
-
"text-muted-foreground scroll-m-20 text-sm font-light tracking-tight",
|
|
68
|
-
className,
|
|
69
|
-
)}
|
|
70
|
-
>
|
|
71
|
-
{children}
|
|
72
|
-
</h6>
|
|
73
|
-
);
|
|
74
|
-
}
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
|
|
3
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
|
-
|
|
5
|
-
import { cn } from "@/lib/utils";
|
|
6
|
-
|
|
7
|
-
const hoverCardContentVariants = cva(
|
|
8
|
-
"text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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 z-50 w-64 origin-(--radix-hover-card-content-transform-origin) shadow-md outline-hidden transition-all",
|
|
9
|
-
{
|
|
10
|
-
variants: {
|
|
11
|
-
variant: {
|
|
12
|
-
container: "bg-background relative drop-shadow-lg",
|
|
13
|
-
simple: "bg-muted",
|
|
14
|
-
item: "bg-muted drop-shadow-lg",
|
|
15
|
-
},
|
|
16
|
-
gradientBorder: {
|
|
17
|
-
none: "",
|
|
18
|
-
white:
|
|
19
|
-
"relative before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:bg-gradient-to-br before:from-white/40 before:via-transparent before:to-white/10 before:[mask-composite:exclude] before:p-px before:content-[''] before:[mask:linear-gradient(#fff_0_0)_content-box,linear-gradient(#fff_0_0)]",
|
|
20
|
-
green:
|
|
21
|
-
"relative before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:bg-gradient-to-br before:from-[#73F36C]/60 before:via-transparent before:to-[#73F36C]/20 before:[mask-composite:exclude] before:p-px before:content-[''] before:[mask:linear-gradient(#fff_0_0)_content-box,linear-gradient(#fff_0_0)]",
|
|
22
|
-
auto: "light:before:from-black/20 light:before:to-black/5 relative before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:bg-gradient-to-br before:from-white/40 before:via-transparent before:to-white/10 before:[mask-composite:exclude] before:p-px before:content-[''] before:[mask:linear-gradient(#fff_0_0)_content-box,linear-gradient(#fff_0_0)]",
|
|
23
|
-
},
|
|
24
|
-
padding: {
|
|
25
|
-
none: "p-0",
|
|
26
|
-
sm: "px-3.5 py-3.5",
|
|
27
|
-
default: "px-4.5 py-4.5",
|
|
28
|
-
md: "px-6 py-6.5",
|
|
29
|
-
lg: "px-8 py-8.5",
|
|
30
|
-
},
|
|
31
|
-
rounded: {
|
|
32
|
-
default: "rounded-lg",
|
|
33
|
-
infoCard: "rounded-info-card",
|
|
34
|
-
none: "rounded-none",
|
|
35
|
-
sm: "rounded-sm",
|
|
36
|
-
md: "rounded-md",
|
|
37
|
-
lg: "rounded-lg",
|
|
38
|
-
xl: "rounded-lg",
|
|
39
|
-
full: "rounded-full",
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
defaultVariants: {
|
|
43
|
-
variant: "container",
|
|
44
|
-
padding: "default",
|
|
45
|
-
rounded: "default",
|
|
46
|
-
gradientBorder: "none",
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
function HoverCard({
|
|
52
|
-
...props
|
|
53
|
-
}: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
|
|
54
|
-
return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function HoverCardTrigger({
|
|
58
|
-
...props
|
|
59
|
-
}: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
|
|
60
|
-
return (
|
|
61
|
-
<HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function HoverCardContent({
|
|
66
|
-
className,
|
|
67
|
-
align = "center",
|
|
68
|
-
sideOffset = 4,
|
|
69
|
-
variant,
|
|
70
|
-
padding,
|
|
71
|
-
rounded,
|
|
72
|
-
gradientBorder,
|
|
73
|
-
...props
|
|
74
|
-
}: React.ComponentProps<typeof HoverCardPrimitive.Content> &
|
|
75
|
-
VariantProps<typeof hoverCardContentVariants>) {
|
|
76
|
-
// Auto-apply gradient border for container variant if not specified
|
|
77
|
-
const finalGradientBorder =
|
|
78
|
-
gradientBorder ?? (variant === "container" ? "white" : "none");
|
|
79
|
-
|
|
80
|
-
const hasGradientBorder = finalGradientBorder !== "none";
|
|
81
|
-
|
|
82
|
-
// Get the gradient border classes
|
|
83
|
-
const gradientClasses = hoverCardContentVariants({
|
|
84
|
-
gradientBorder: finalGradientBorder,
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Get the main hover card classes without gradient
|
|
88
|
-
const hoverCardClasses = cn(
|
|
89
|
-
hoverCardContentVariants({
|
|
90
|
-
variant,
|
|
91
|
-
padding,
|
|
92
|
-
rounded,
|
|
93
|
-
gradientBorder: "none",
|
|
94
|
-
className,
|
|
95
|
-
}),
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
// Get the rounded class for the wrapper
|
|
99
|
-
const roundedClass = hoverCardContentVariants({ rounded });
|
|
100
|
-
|
|
101
|
-
return (
|
|
102
|
-
<HoverCardPrimitive.Portal
|
|
103
|
-
container={
|
|
104
|
-
document.querySelectorAll(".turtle-widget-root")[0] ?? undefined
|
|
105
|
-
}
|
|
106
|
-
data-slot="hover-card-portal"
|
|
107
|
-
>
|
|
108
|
-
{hasGradientBorder ? (
|
|
109
|
-
<HoverCardPrimitive.Content
|
|
110
|
-
data-slot="hover-card-content-wrapper"
|
|
111
|
-
align={align}
|
|
112
|
-
sideOffset={sideOffset}
|
|
113
|
-
className={cn(gradientClasses, roundedClass, "p-[1px]")}
|
|
114
|
-
{...props}
|
|
115
|
-
>
|
|
116
|
-
<div
|
|
117
|
-
data-slot="hover-card-content-inner"
|
|
118
|
-
className={hoverCardClasses}
|
|
119
|
-
/>
|
|
120
|
-
</HoverCardPrimitive.Content>
|
|
121
|
-
) : (
|
|
122
|
-
<HoverCardPrimitive.Content
|
|
123
|
-
data-slot="hover-card-content"
|
|
124
|
-
align={align}
|
|
125
|
-
sideOffset={sideOffset}
|
|
126
|
-
className={hoverCardClasses}
|
|
127
|
-
{...props}
|
|
128
|
-
/>
|
|
129
|
-
)}
|
|
130
|
-
</HoverCardPrimitive.Portal>
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export {
|
|
135
|
-
HoverCard,
|
|
136
|
-
HoverCardTrigger,
|
|
137
|
-
HoverCardContent,
|
|
138
|
-
hoverCardContentVariants,
|
|
139
|
-
};
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
-
|
|
4
|
-
import { cn } from "@/lib/utils";
|
|
5
|
-
|
|
6
|
-
const iconAnimationVariants = cva(
|
|
7
|
-
"relative inline-flex items-center justify-center rounded-full",
|
|
8
|
-
{
|
|
9
|
-
variants: {
|
|
10
|
-
size: {
|
|
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
|
-
},
|
|
16
|
-
variant: {
|
|
17
|
-
default: "bg-background",
|
|
18
|
-
transparent: "bg-transparent",
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
defaultVariants: {
|
|
22
|
-
size: "default",
|
|
23
|
-
variant: "default",
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
export interface IconAnimationProps
|
|
29
|
-
extends React.ComponentProps<"div">,
|
|
30
|
-
VariantProps<typeof iconAnimationVariants> {
|
|
31
|
-
children: React.ReactNode;
|
|
32
|
-
spinning?: boolean;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const IconAnimation = React.forwardRef<HTMLDivElement, IconAnimationProps>(
|
|
36
|
-
({ className, size, variant, children, spinning = true, ...props }, ref) => {
|
|
37
|
-
return (
|
|
38
|
-
<div
|
|
39
|
-
ref={ref}
|
|
40
|
-
className={cn(iconAnimationVariants({ size, variant }), className)}
|
|
41
|
-
{...props}
|
|
42
|
-
>
|
|
43
|
-
{/* Animated border */}
|
|
44
|
-
<div
|
|
45
|
-
className={cn(
|
|
46
|
-
"absolute inset-0 rounded-full",
|
|
47
|
-
"via-primary bg-gradient-to-r from-transparent to-transparent",
|
|
48
|
-
"animate-spin",
|
|
49
|
-
{
|
|
50
|
-
"animate-spin": spinning,
|
|
51
|
-
"animate-none": !spinning,
|
|
52
|
-
},
|
|
53
|
-
)}
|
|
54
|
-
style={{
|
|
55
|
-
background: spinning
|
|
56
|
-
? "conic-gradient(from 0deg, transparent 0deg, var(--primary) 180deg, transparent 360deg)"
|
|
57
|
-
: "conic-gradient(from 0deg, var(--primary) 0deg, var(--primary) 360deg)",
|
|
58
|
-
padding: "1px",
|
|
59
|
-
borderRadius: "9999px",
|
|
60
|
-
}}
|
|
61
|
-
>
|
|
62
|
-
{/* Inner circle to create the border effect */}
|
|
63
|
-
<div
|
|
64
|
-
className={cn(
|
|
65
|
-
"h-full w-full rounded-full",
|
|
66
|
-
variant === "transparent" ? "bg-transparent" : "bg-background",
|
|
67
|
-
)}
|
|
68
|
-
/>
|
|
69
|
-
</div>
|
|
70
|
-
|
|
71
|
-
{/* Icon container - stays fixed */}
|
|
72
|
-
<div className="relative z-10 flex items-center justify-center">
|
|
73
|
-
{children}
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
);
|
|
77
|
-
},
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
IconAnimation.displayName = "IconAnimation";
|
|
81
|
-
|
|
82
|
-
export { IconAnimation, iconAnimationVariants };
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { cn } from "@/lib/utils";
|
|
3
|
-
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
|
|
4
|
-
import {
|
|
5
|
-
Tooltip,
|
|
6
|
-
TooltipContent,
|
|
7
|
-
TooltipProvider,
|
|
8
|
-
TooltipTrigger,
|
|
9
|
-
} from "@/components/ui/tooltip";
|
|
10
|
-
import { useMemo } from "react";
|
|
11
|
-
|
|
12
|
-
interface IconListItem {
|
|
13
|
-
icon: string;
|
|
14
|
-
name: string;
|
|
15
|
-
id?: string; // Optional unique identifier
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface IconListProps extends React.ComponentProps<"div"> {
|
|
19
|
-
items: IconListItem[] | string[];
|
|
20
|
-
label?: string;
|
|
21
|
-
size?: "xs" | "sm" | "md" | "lg";
|
|
22
|
-
maxVisible?: number;
|
|
23
|
-
showTooltip?: boolean;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const sizeClasses = {
|
|
27
|
-
xs: "w-3 h-3 text-[8px]",
|
|
28
|
-
sm: "w-4 h-4 text-[10px]",
|
|
29
|
-
md: "w-5 h-5 text-xs",
|
|
30
|
-
lg: "w-6 h-6 text-sm",
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const IconList = React.forwardRef<HTMLDivElement, IconListProps>(
|
|
34
|
-
(
|
|
35
|
-
{
|
|
36
|
-
className,
|
|
37
|
-
items,
|
|
38
|
-
label,
|
|
39
|
-
size = "sm",
|
|
40
|
-
maxVisible = 6,
|
|
41
|
-
showTooltip = false,
|
|
42
|
-
...props
|
|
43
|
-
},
|
|
44
|
-
ref,
|
|
45
|
-
) => {
|
|
46
|
-
const [loadedImages, setLoadedImages] = React.useState<Set<string>>(
|
|
47
|
-
new Set(),
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
if (!items || items.length === 0) return null;
|
|
51
|
-
|
|
52
|
-
const uniqueItems = useMemo(() => {
|
|
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}` },
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
const unique = normalized.filter(
|
|
61
|
-
(item, index, self) =>
|
|
62
|
-
index === self.findIndex((t) => t.icon === item.icon),
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
return unique;
|
|
66
|
-
}, [items]);
|
|
67
|
-
|
|
68
|
-
const visibleItems = uniqueItems.slice(0, maxVisible);
|
|
69
|
-
const remainingCount = uniqueItems.length - maxVisible;
|
|
70
|
-
const hiddenItems = uniqueItems.slice(maxVisible);
|
|
71
|
-
|
|
72
|
-
const handleImageLoad = (icon: string) => {
|
|
73
|
-
setLoadedImages((prev) => new Set(prev).add(icon));
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const renderAvatar = (item: IconListItem, index: number) => (
|
|
77
|
-
<Avatar
|
|
78
|
-
key={item.id || index}
|
|
79
|
-
className={cn(
|
|
80
|
-
sizeClasses[size],
|
|
81
|
-
"border-background border transition-all hover:z-10 hover:scale-110",
|
|
82
|
-
!loadedImages.has(item.icon) && "animate-pulse",
|
|
83
|
-
)}
|
|
84
|
-
>
|
|
85
|
-
<AvatarImage
|
|
86
|
-
src={item.icon}
|
|
87
|
-
alt={item.name || "Icon"}
|
|
88
|
-
onLoad={() => handleImageLoad(item.icon)}
|
|
89
|
-
/>
|
|
90
|
-
<AvatarFallback
|
|
91
|
-
className={cn("font-medium", sizeClasses[size].split(" ").pop())}
|
|
92
|
-
>
|
|
93
|
-
{item.name ? item.name.slice(0, 2).toUpperCase() : "?"}
|
|
94
|
-
</AvatarFallback>
|
|
95
|
-
</Avatar>
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
const renderWithTooltip = (
|
|
99
|
-
content: React.ReactNode,
|
|
100
|
-
tooltipText: string,
|
|
101
|
-
) => {
|
|
102
|
-
if (!showTooltip || !tooltipText) return content;
|
|
103
|
-
|
|
104
|
-
return (
|
|
105
|
-
<Tooltip>
|
|
106
|
-
<TooltipTrigger asChild>{content}</TooltipTrigger>
|
|
107
|
-
<TooltipContent side="top" className="text-xs">
|
|
108
|
-
{tooltipText}
|
|
109
|
-
</TooltipContent>
|
|
110
|
-
</Tooltip>
|
|
111
|
-
);
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
return (
|
|
115
|
-
<TooltipProvider>
|
|
116
|
-
<div
|
|
117
|
-
ref={ref}
|
|
118
|
-
className={cn("flex items-center gap-1", className)}
|
|
119
|
-
role="list"
|
|
120
|
-
aria-label={label || "Icon list"}
|
|
121
|
-
{...props}
|
|
122
|
-
>
|
|
123
|
-
{label && (
|
|
124
|
-
<span className="text-muted-foreground mr-1 text-xs">{label}:</span>
|
|
125
|
-
)}
|
|
126
|
-
<div className="flex -space-x-1">
|
|
127
|
-
{visibleItems.map((item, index) => (
|
|
128
|
-
<div key={item.id || index} role="listitem">
|
|
129
|
-
{renderWithTooltip(renderAvatar(item, index), item.name)}
|
|
130
|
-
</div>
|
|
131
|
-
))}
|
|
132
|
-
{remainingCount > 0 && (
|
|
133
|
-
<div role="listitem">
|
|
134
|
-
{renderWithTooltip(
|
|
135
|
-
<Avatar
|
|
136
|
-
className={cn(
|
|
137
|
-
sizeClasses[size],
|
|
138
|
-
"border-background bg-muted hover:bg-muted/80 border transition-all",
|
|
139
|
-
)}
|
|
140
|
-
aria-label={`${remainingCount} more items`}
|
|
141
|
-
>
|
|
142
|
-
<AvatarFallback
|
|
143
|
-
className={cn(
|
|
144
|
-
"font-semibold",
|
|
145
|
-
sizeClasses[size].split(" ").pop(),
|
|
146
|
-
)}
|
|
147
|
-
>
|
|
148
|
-
+{remainingCount}
|
|
149
|
-
</AvatarFallback>
|
|
150
|
-
</Avatar>,
|
|
151
|
-
hiddenItems
|
|
152
|
-
.map((item) => item.name)
|
|
153
|
-
.filter(Boolean)
|
|
154
|
-
.join(", ") || `${remainingCount} more items`,
|
|
155
|
-
)}
|
|
156
|
-
</div>
|
|
157
|
-
)}
|
|
158
|
-
</div>
|
|
159
|
-
</div>
|
|
160
|
-
</TooltipProvider>
|
|
161
|
-
);
|
|
162
|
-
},
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
IconList.displayName = "IconList";
|
|
166
|
-
|
|
167
|
-
export { IconList };
|
|
168
|
-
export type { IconListProps, IconListItem };
|