@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
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { cn } from "@/lib/utils";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
Select,
|
|
6
|
+
SelectContent,
|
|
7
|
+
SelectItem,
|
|
8
|
+
SelectTrigger,
|
|
9
|
+
} from "@/components/ui/select";
|
|
5
10
|
import { useEffect } from "react";
|
|
6
11
|
|
|
7
12
|
interface Token {
|
|
@@ -35,10 +40,13 @@ const TokenSelector = ({
|
|
|
35
40
|
showBalance = true,
|
|
36
41
|
}: TokenSelectorProps) => {
|
|
37
42
|
// Auto-select first token if no value is provided and tokens exist
|
|
38
|
-
const effectiveValue =
|
|
43
|
+
const effectiveValue =
|
|
44
|
+
value || (tokens.length > 0 ? tokens[0].address : undefined);
|
|
39
45
|
|
|
40
46
|
// Find the selected token to display in the trigger
|
|
41
|
-
const selectedToken = tokens.find(
|
|
47
|
+
const selectedToken = tokens.find(
|
|
48
|
+
(token) => token.address === effectiveValue,
|
|
49
|
+
);
|
|
42
50
|
|
|
43
51
|
// Handle value change and auto-select first token on mount
|
|
44
52
|
useEffect(() => {
|
|
@@ -48,17 +56,21 @@ const TokenSelector = ({
|
|
|
48
56
|
}, [value, tokens, onValueChange]);
|
|
49
57
|
|
|
50
58
|
return (
|
|
51
|
-
<Select
|
|
59
|
+
<Select
|
|
60
|
+
value={effectiveValue}
|
|
61
|
+
onValueChange={onValueChange}
|
|
62
|
+
disabled={disabled}
|
|
63
|
+
>
|
|
52
64
|
<SelectTrigger
|
|
53
65
|
// variant={variant}
|
|
54
66
|
// size={size}
|
|
55
67
|
className={cn(
|
|
56
|
-
"w-auto min-w-[80px]
|
|
57
|
-
"focus:ring-
|
|
68
|
+
"bg-muted hover:bg-muted/80 w-auto min-w-[80px] rounded-md font-medium",
|
|
69
|
+
"focus:ring-primary/20 focus:ring-2 focus:outline-none",
|
|
58
70
|
size === "xs" && "min-w-[80px] gap-2",
|
|
59
71
|
size === "sm" && "min-w-[75px] gap-1.5",
|
|
60
72
|
size === "default" && "min-w-[80px] gap-1.5",
|
|
61
|
-
className
|
|
73
|
+
className,
|
|
62
74
|
)}
|
|
63
75
|
>
|
|
64
76
|
{selectedToken ? (
|
|
@@ -67,15 +79,15 @@ const TokenSelector = ({
|
|
|
67
79
|
"flex items-center",
|
|
68
80
|
size === "xs" && "gap-2",
|
|
69
81
|
size === "sm" && "gap-1.5",
|
|
70
|
-
size === "default" && "gap-1.5"
|
|
82
|
+
size === "default" && "gap-1.5",
|
|
71
83
|
)}
|
|
72
84
|
>
|
|
73
85
|
<span
|
|
74
86
|
className={cn(
|
|
75
87
|
"flex items-center justify-center",
|
|
76
|
-
size === "xs" && "w-3.5
|
|
77
|
-
size === "sm" && "
|
|
78
|
-
size === "default" && "w-5
|
|
88
|
+
size === "xs" && "h-3 w-3.5",
|
|
89
|
+
size === "sm" && "h-3.5 w-4",
|
|
90
|
+
size === "default" && "h-4 w-5",
|
|
79
91
|
)}
|
|
80
92
|
>
|
|
81
93
|
{selectedToken.icon}
|
|
@@ -85,7 +97,7 @@ const TokenSelector = ({
|
|
|
85
97
|
"font-medium",
|
|
86
98
|
size === "xs" && "text-xs",
|
|
87
99
|
size === "sm" && "text-sm",
|
|
88
|
-
size === "default" && "text-sm"
|
|
100
|
+
size === "default" && "text-sm",
|
|
89
101
|
)}
|
|
90
102
|
>
|
|
91
103
|
{selectedToken.symbol}
|
|
@@ -97,24 +109,28 @@ const TokenSelector = ({
|
|
|
97
109
|
"text-muted-foreground",
|
|
98
110
|
size === "xs" && "text-xs",
|
|
99
111
|
size === "sm" && "text-sm",
|
|
100
|
-
size === "default" && "text-sm"
|
|
112
|
+
size === "default" && "text-sm",
|
|
101
113
|
)}
|
|
102
114
|
>
|
|
103
115
|
{placeholder}
|
|
104
116
|
</span>
|
|
105
117
|
)}
|
|
106
118
|
</SelectTrigger>
|
|
107
|
-
<SelectContent className="border
|
|
119
|
+
<SelectContent className="border-muted gap-2 border">
|
|
108
120
|
{tokens.map((token) => (
|
|
109
|
-
<SelectItem
|
|
121
|
+
<SelectItem
|
|
122
|
+
key={token.address}
|
|
123
|
+
value={token.address}
|
|
124
|
+
className="cursor-pointer py-2"
|
|
125
|
+
>
|
|
110
126
|
<div className="flex flex-col gap-2">
|
|
111
127
|
<div className="flex items-center gap-2">
|
|
112
128
|
<span
|
|
113
129
|
className={cn(
|
|
114
130
|
"flex items-center justify-center",
|
|
115
|
-
size === "xs" && "
|
|
116
|
-
size === "sm" && "
|
|
117
|
-
size === "default" && "w-5
|
|
131
|
+
size === "xs" && "h-3.5 w-3.5",
|
|
132
|
+
size === "sm" && "h-4 w-4",
|
|
133
|
+
size === "default" && "h-4 w-5",
|
|
118
134
|
)}
|
|
119
135
|
>
|
|
120
136
|
{token.icon}
|
|
@@ -124,13 +140,15 @@ const TokenSelector = ({
|
|
|
124
140
|
"font-medium",
|
|
125
141
|
size === "xs" && "text-xs",
|
|
126
142
|
size === "sm" && "text-sm",
|
|
127
|
-
size === "default" && "text-sm"
|
|
143
|
+
size === "default" && "text-sm",
|
|
128
144
|
)}
|
|
129
145
|
>
|
|
130
146
|
{token.symbol}
|
|
131
147
|
</span>
|
|
132
148
|
</div>
|
|
133
|
-
{showBalance &&
|
|
149
|
+
{showBalance && (
|
|
150
|
+
<span className="text-xs text-white/80">≈ {token.balance}</span>
|
|
151
|
+
)}
|
|
134
152
|
</div>
|
|
135
153
|
</SelectItem>
|
|
136
154
|
))}
|
|
@@ -49,7 +49,7 @@ const TxStatus = React.forwardRef<HTMLDivElement, TxStatusProps>(
|
|
|
49
49
|
showActions = true,
|
|
50
50
|
...props
|
|
51
51
|
},
|
|
52
|
-
ref
|
|
52
|
+
ref,
|
|
53
53
|
) => {
|
|
54
54
|
const defaultTitle = cancelled
|
|
55
55
|
? "Transaction Cancelled"
|
|
@@ -63,7 +63,12 @@ const TxStatus = React.forwardRef<HTMLDivElement, TxStatusProps>(
|
|
|
63
63
|
: "Please wait while your transaction is being processed...";
|
|
64
64
|
|
|
65
65
|
const ExternalLinkIcon = ({ size = "w-4 h-4" }) => (
|
|
66
|
-
<svg
|
|
66
|
+
<svg
|
|
67
|
+
className={size}
|
|
68
|
+
fill="none"
|
|
69
|
+
stroke="currentColor"
|
|
70
|
+
viewBox="0 0 24 24"
|
|
71
|
+
>
|
|
67
72
|
<path
|
|
68
73
|
strokeLinecap="round"
|
|
69
74
|
strokeLinejoin="round"
|
|
@@ -74,8 +79,18 @@ const TxStatus = React.forwardRef<HTMLDivElement, TxStatusProps>(
|
|
|
74
79
|
);
|
|
75
80
|
|
|
76
81
|
const StepCheckIcon = () => (
|
|
77
|
-
<svg
|
|
78
|
-
|
|
82
|
+
<svg
|
|
83
|
+
className="h-4 w-4"
|
|
84
|
+
fill="none"
|
|
85
|
+
stroke="currentColor"
|
|
86
|
+
viewBox="0 0 24 24"
|
|
87
|
+
>
|
|
88
|
+
<path
|
|
89
|
+
strokeLinecap="round"
|
|
90
|
+
strokeLinejoin="round"
|
|
91
|
+
strokeWidth={2}
|
|
92
|
+
d="M5 13l4 4L19 7"
|
|
93
|
+
/>
|
|
79
94
|
</svg>
|
|
80
95
|
);
|
|
81
96
|
|
|
@@ -88,9 +103,9 @@ const TxStatus = React.forwardRef<HTMLDivElement, TxStatusProps>(
|
|
|
88
103
|
<Card
|
|
89
104
|
ref={ref}
|
|
90
105
|
className={cn(
|
|
91
|
-
"p-4 text-center
|
|
92
|
-
variant === "compact" && "
|
|
93
|
-
className
|
|
106
|
+
"space-y-3 p-4 text-center",
|
|
107
|
+
variant === "compact" && "space-y-2 p-3",
|
|
108
|
+
className,
|
|
94
109
|
)}
|
|
95
110
|
{...props}
|
|
96
111
|
>
|
|
@@ -102,15 +117,24 @@ const TxStatus = React.forwardRef<HTMLDivElement, TxStatusProps>(
|
|
|
102
117
|
>
|
|
103
118
|
{cancelled ? (
|
|
104
119
|
<XIcon
|
|
105
|
-
className={cn(
|
|
120
|
+
className={cn(
|
|
121
|
+
variant === "compact" ? "h-5 w-5" : "h-6 w-6",
|
|
122
|
+
"text-destructive",
|
|
123
|
+
)}
|
|
106
124
|
/>
|
|
107
125
|
) : completed ? (
|
|
108
126
|
<CheckIcon
|
|
109
|
-
className={cn(
|
|
127
|
+
className={cn(
|
|
128
|
+
variant === "compact" ? "h-5 w-5" : "h-6 w-6",
|
|
129
|
+
"text-primary",
|
|
130
|
+
)}
|
|
110
131
|
/>
|
|
111
132
|
) : (
|
|
112
133
|
<TurtleIcon
|
|
113
|
-
className={cn(
|
|
134
|
+
className={cn(
|
|
135
|
+
variant === "compact" ? "h-5 w-5" : "h-6 w-6",
|
|
136
|
+
"text-primary",
|
|
137
|
+
)}
|
|
114
138
|
/>
|
|
115
139
|
)}
|
|
116
140
|
</IconAnimation>
|
|
@@ -120,88 +144,110 @@ const TxStatus = React.forwardRef<HTMLDivElement, TxStatusProps>(
|
|
|
120
144
|
<div className="space-y-1">
|
|
121
145
|
<h3
|
|
122
146
|
className={cn(
|
|
123
|
-
"font-medium
|
|
124
|
-
variant === "compact" ? "text-xs" : "text-sm"
|
|
147
|
+
"text-foreground font-medium",
|
|
148
|
+
variant === "compact" ? "text-xs" : "text-sm",
|
|
125
149
|
)}
|
|
126
150
|
>
|
|
127
151
|
{title || defaultTitle}
|
|
128
152
|
</h3>
|
|
129
|
-
<p
|
|
153
|
+
<p
|
|
154
|
+
className={cn(
|
|
155
|
+
"text-muted-foreground",
|
|
156
|
+
variant === "compact" ? "text-xs" : "text-xs",
|
|
157
|
+
)}
|
|
158
|
+
>
|
|
130
159
|
{description || defaultDescription}
|
|
131
160
|
</p>
|
|
132
161
|
</div>
|
|
133
162
|
|
|
134
163
|
{/* Transaction summary (completed state) */}
|
|
135
164
|
{completed && !cancelled && (amount || token || protocol) && (
|
|
136
|
-
<div className="
|
|
165
|
+
<div className="bg-muted/50 space-y-1 rounded-lg p-2">
|
|
137
166
|
{amount && token && (
|
|
138
167
|
<div className="text-xs font-medium">
|
|
139
168
|
{amount} {token}
|
|
140
169
|
</div>
|
|
141
170
|
)}
|
|
142
|
-
{protocol &&
|
|
171
|
+
{protocol && (
|
|
172
|
+
<div className="text-muted-foreground text-xs">
|
|
173
|
+
via {protocol}
|
|
174
|
+
</div>
|
|
175
|
+
)}
|
|
143
176
|
</div>
|
|
144
177
|
)}
|
|
145
178
|
|
|
146
179
|
{/* Transaction hash link */}
|
|
147
180
|
{txHash && !cancelled && (
|
|
148
181
|
<div className="space-y-1">
|
|
149
|
-
<div className="text-
|
|
182
|
+
<div className="text-muted-foreground text-xs">
|
|
183
|
+
Transaction Hash
|
|
184
|
+
</div>
|
|
150
185
|
{explorerUrl ? (
|
|
151
186
|
<a
|
|
152
187
|
href={`${explorerUrl}/tx/${txHash}`}
|
|
153
188
|
target="_blank"
|
|
154
189
|
rel="noopener noreferrer"
|
|
155
|
-
className="inline-flex items-center gap-2 text-xs
|
|
190
|
+
className="text-primary hover:text-primary/80 inline-flex items-center gap-2 text-xs transition-colors"
|
|
156
191
|
>
|
|
157
192
|
{formatTxHash(txHash)}
|
|
158
193
|
<ExternalLinkIcon />
|
|
159
194
|
</a>
|
|
160
195
|
) : (
|
|
161
|
-
<div className="text-
|
|
196
|
+
<div className="text-foreground font-mono text-xs">
|
|
197
|
+
{formatTxHash(txHash)}
|
|
198
|
+
</div>
|
|
162
199
|
)}
|
|
163
200
|
</div>
|
|
164
201
|
)}
|
|
165
202
|
|
|
166
203
|
{/* Estimated time (pending state) */}
|
|
167
204
|
{!completed && !cancelled && estimatedTime && (
|
|
168
|
-
<div className="text-
|
|
205
|
+
<div className="text-muted-foreground text-xs">
|
|
206
|
+
Estimated time: {estimatedTime}
|
|
207
|
+
</div>
|
|
169
208
|
)}
|
|
170
209
|
|
|
171
210
|
{/* Progress steps (pending state) */}
|
|
172
211
|
{!completed && !cancelled && steps.length > 0 && (
|
|
173
|
-
<div className="space-y-2
|
|
174
|
-
<div className="text-
|
|
212
|
+
<div className="border-border space-y-2 border-t pt-2">
|
|
213
|
+
<div className="text-muted-foreground text-left text-xs font-medium">
|
|
214
|
+
Progress
|
|
215
|
+
</div>
|
|
175
216
|
<div className="space-y-2">
|
|
176
217
|
{steps.map((step, index) => (
|
|
177
218
|
<div key={index} className="flex items-center gap-3 text-left">
|
|
178
219
|
<div
|
|
179
220
|
className={cn(
|
|
180
|
-
"flex items-center justify-center
|
|
181
|
-
step.completed &&
|
|
221
|
+
"flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full border-2",
|
|
222
|
+
step.completed &&
|
|
223
|
+
"bg-primary border-primary text-primary-foreground",
|
|
182
224
|
step.current &&
|
|
183
225
|
!step.completed &&
|
|
184
226
|
"border-primary text-primary animate-pulse",
|
|
185
227
|
!step.completed &&
|
|
186
228
|
!step.current &&
|
|
187
|
-
"border-muted-foreground/30 text-muted-foreground"
|
|
229
|
+
"border-muted-foreground/30 text-muted-foreground",
|
|
188
230
|
)}
|
|
189
231
|
>
|
|
190
232
|
{step.completed ? (
|
|
191
233
|
<StepCheckIcon />
|
|
192
234
|
) : step.current ? (
|
|
193
|
-
<div className="
|
|
235
|
+
<div className="bg-primary h-2 w-2 animate-pulse rounded-full" />
|
|
194
236
|
) : (
|
|
195
|
-
<div className="
|
|
237
|
+
<div className="bg-muted-foreground/30 h-2 w-2 rounded-full" />
|
|
196
238
|
)}
|
|
197
239
|
</div>
|
|
198
|
-
<div className="flex-1
|
|
240
|
+
<div className="flex flex-1 items-center justify-between">
|
|
199
241
|
<span
|
|
200
242
|
className={cn(
|
|
201
243
|
"text-xs",
|
|
202
244
|
step.completed && "text-foreground",
|
|
203
|
-
step.current &&
|
|
204
|
-
|
|
245
|
+
step.current &&
|
|
246
|
+
!step.completed &&
|
|
247
|
+
"text-foreground font-medium",
|
|
248
|
+
!step.completed &&
|
|
249
|
+
!step.current &&
|
|
250
|
+
"text-muted-foreground",
|
|
205
251
|
)}
|
|
206
252
|
>
|
|
207
253
|
{step.label}
|
|
@@ -211,7 +257,7 @@ const TxStatus = React.forwardRef<HTMLDivElement, TxStatusProps>(
|
|
|
211
257
|
href={`${explorerUrl}/tx/${step.txHash}`}
|
|
212
258
|
target="_blank"
|
|
213
259
|
rel="noopener noreferrer"
|
|
214
|
-
className="inline-flex items-center gap-1 text-xs
|
|
260
|
+
className="text-primary hover:text-primary/80 ml-2 inline-flex items-center gap-1 text-xs transition-colors"
|
|
215
261
|
title={`View transaction: ${step.txHash}`}
|
|
216
262
|
>
|
|
217
263
|
<span className="font-mono">
|
|
@@ -228,32 +274,37 @@ const TxStatus = React.forwardRef<HTMLDivElement, TxStatusProps>(
|
|
|
228
274
|
)}
|
|
229
275
|
|
|
230
276
|
{/* Action buttons (completed or cancelled state) */}
|
|
231
|
-
{(completed || cancelled) &&
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
277
|
+
{(completed || cancelled) &&
|
|
278
|
+
showActions &&
|
|
279
|
+
(onViewDetails || onClose) && (
|
|
280
|
+
<div
|
|
281
|
+
className={cn(
|
|
282
|
+
"flex gap-2 pt-2",
|
|
283
|
+
variant === "compact" ? "flex-col" : "flex-row justify-center",
|
|
284
|
+
)}
|
|
285
|
+
>
|
|
286
|
+
{!cancelled && onViewDetails && (
|
|
287
|
+
<Button
|
|
288
|
+
size={variant === "compact" ? "sm" : "default"}
|
|
289
|
+
onClick={onViewDetails}
|
|
290
|
+
>
|
|
291
|
+
View Details
|
|
292
|
+
</Button>
|
|
293
|
+
)}
|
|
294
|
+
{onClose && (
|
|
295
|
+
<Button
|
|
296
|
+
variant="default"
|
|
297
|
+
size={variant === "compact" ? "sm" : "default"}
|
|
298
|
+
onClick={onClose}
|
|
299
|
+
>
|
|
300
|
+
{cancelled ? "Try Again" : "Done"}
|
|
301
|
+
</Button>
|
|
302
|
+
)}
|
|
303
|
+
</div>
|
|
304
|
+
)}
|
|
254
305
|
</Card>
|
|
255
306
|
);
|
|
256
|
-
}
|
|
307
|
+
},
|
|
257
308
|
);
|
|
258
309
|
|
|
259
310
|
TxStatus.displayName = "TxStatus";
|
|
@@ -60,7 +60,7 @@ export const AssetFilters: React.FC<AssetFiltersProps> = ({
|
|
|
60
60
|
onFiltersChange(newFilters);
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
|
-
[activeFilters, onFiltersChange, variant, multipleFilters]
|
|
63
|
+
[activeFilters, onFiltersChange, variant, multipleFilters],
|
|
64
64
|
);
|
|
65
65
|
|
|
66
66
|
return (
|
|
@@ -83,7 +83,9 @@ export const AssetFilters: React.FC<AssetFiltersProps> = ({
|
|
|
83
83
|
{filters.map((filter) => (
|
|
84
84
|
<Badge
|
|
85
85
|
key={filter.id}
|
|
86
|
-
variant={
|
|
86
|
+
variant={
|
|
87
|
+
activeFilters.includes(filter.id) ? "default" : "muted"
|
|
88
|
+
}
|
|
87
89
|
className="bg-muted cursor-pointer rounded-full"
|
|
88
90
|
onClick={() => handleFilterToggle(filter.id)}
|
|
89
91
|
>
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
import React, { useState } from "react";
|
|
3
3
|
import { WidgetListItems } from "../widget-list-items";
|
|
4
4
|
import { AssetRow } from "./asset-row";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
AssetFilters,
|
|
7
|
+
AssetFilterItem as BaseAssetFilter,
|
|
8
|
+
} from "./asset-filters";
|
|
6
9
|
import { useAssetFiltering, useAssetGrouping } from "./hooks";
|
|
7
10
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
8
11
|
import { cn } from "@/lib/utils";
|
|
@@ -68,13 +71,15 @@ const defaultFilters: AssetFilterProp[] = [
|
|
|
68
71
|
id: "eth",
|
|
69
72
|
label: "ETH",
|
|
70
73
|
filterFn: (asset) =>
|
|
71
|
-
["ETH"].includes(asset.symbol.toUpperCase()) ||
|
|
74
|
+
["ETH"].includes(asset.symbol.toUpperCase()) ||
|
|
75
|
+
["ETH"].includes(asset.name.toUpperCase()),
|
|
72
76
|
},
|
|
73
77
|
{
|
|
74
78
|
id: "btc",
|
|
75
79
|
label: "BTC",
|
|
76
80
|
filterFn: (asset) =>
|
|
77
|
-
["BTC"].includes(asset.symbol.toUpperCase()) ||
|
|
81
|
+
["BTC"].includes(asset.symbol.toUpperCase()) ||
|
|
82
|
+
["BTC"].includes(asset.name.toUpperCase()),
|
|
78
83
|
},
|
|
79
84
|
];
|
|
80
85
|
|
|
@@ -26,7 +26,7 @@ export const AssetRow: React.FC<AssetRowProps> = ({
|
|
|
26
26
|
className={cn(
|
|
27
27
|
"flex cursor-pointer items-center justify-between rounded-lg px-3.5 py-2.5 transition-colors",
|
|
28
28
|
"hover:bg-secondary",
|
|
29
|
-
className
|
|
29
|
+
className,
|
|
30
30
|
)}
|
|
31
31
|
>
|
|
32
32
|
<div className="flex items-center gap-3">
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from "./use-asset-filtering";
|
|
2
|
-
export * from "./use-asset-grouping";
|
|
2
|
+
export * from "./use-asset-grouping";
|
|
@@ -24,7 +24,7 @@ export function useAssetFiltering({
|
|
|
24
24
|
(asset) =>
|
|
25
25
|
asset.symbol.toLowerCase().includes(query) ||
|
|
26
26
|
asset.name.toLowerCase().includes(query) ||
|
|
27
|
-
asset.address?.toLowerCase().includes(query)
|
|
27
|
+
asset.address?.toLowerCase().includes(query),
|
|
28
28
|
);
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -34,7 +34,9 @@ export function useAssetFiltering({
|
|
|
34
34
|
.filter((f) => activeFilterIds.includes(f.id))
|
|
35
35
|
.map((f) => f.filterFn);
|
|
36
36
|
|
|
37
|
-
result = result.filter((asset) =>
|
|
37
|
+
result = result.filter((asset) =>
|
|
38
|
+
activeFilterFns.every((filterFn) => filterFn(asset)),
|
|
39
|
+
);
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
return result;
|
|
@@ -9,7 +9,8 @@ interface UseAssetGroupingProps {
|
|
|
9
9
|
|
|
10
10
|
const CHAIN_ICONS: Record<number, string> = {
|
|
11
11
|
1: "https://storage.googleapis.com/turtle-assets/tokens/eth.png",
|
|
12
|
-
747474:
|
|
12
|
+
747474:
|
|
13
|
+
"https://storage.googleapis.com/turtle-assets/partners/polygon/katana.svg",
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
export function useAssetGrouping({
|
|
@@ -49,7 +50,7 @@ export function useAssetGrouping({
|
|
|
49
50
|
acc[asset.chainId].items.push(asset);
|
|
50
51
|
return acc;
|
|
51
52
|
},
|
|
52
|
-
{} as Record<string, WidgetListGroup<Asset
|
|
53
|
+
{} as Record<string, WidgetListGroup<Asset>>,
|
|
53
54
|
);
|
|
54
55
|
|
|
55
56
|
console.log("chainGroups", chainGroups);
|
|
@@ -59,14 +60,22 @@ export function useAssetGrouping({
|
|
|
59
60
|
groupsArray.sort((a, b) => {
|
|
60
61
|
// Get the highest balance in each group (items are already sorted)
|
|
61
62
|
const maxBalanceA =
|
|
62
|
-
a.items.length > 0
|
|
63
|
+
a.items.length > 0
|
|
64
|
+
? parseFloat(a.items[0].balanceUSD.replace(/[$,]/g, "") || "0")
|
|
65
|
+
: 0;
|
|
63
66
|
const maxBalanceB =
|
|
64
|
-
b.items.length > 0
|
|
67
|
+
b.items.length > 0
|
|
68
|
+
? parseFloat(b.items[0].balanceUSD.replace(/[$,]/g, "") || "0")
|
|
69
|
+
: 0;
|
|
65
70
|
|
|
66
71
|
// If highest balances are equal, sort by number of tokens with non-zero balance
|
|
67
72
|
if (maxBalanceA === maxBalanceB) {
|
|
68
|
-
const nonZeroCountA = a.items.filter(
|
|
69
|
-
|
|
73
|
+
const nonZeroCountA = a.items.filter(
|
|
74
|
+
(asset) => parseFloat(asset.balance) > 0,
|
|
75
|
+
).length;
|
|
76
|
+
const nonZeroCountB = b.items.filter(
|
|
77
|
+
(asset) => parseFloat(asset.balance) > 0,
|
|
78
|
+
).length;
|
|
70
79
|
return nonZeroCountB - nonZeroCountA;
|
|
71
80
|
}
|
|
72
81
|
|
|
@@ -47,7 +47,7 @@ const BaseSelector = ({
|
|
|
47
47
|
size === "xs" && "h-7 min-w-[80px] gap-2 px-2.5 py-1",
|
|
48
48
|
size === "sm" && "h-8 min-w-[75px] gap-1.5 px-3 py-1.5",
|
|
49
49
|
size === "default" && "h-10 min-w-[80px] gap-1.5 px-3 py-2",
|
|
50
|
-
className
|
|
50
|
+
className,
|
|
51
51
|
)}
|
|
52
52
|
role="button"
|
|
53
53
|
tabIndex={0}
|
|
@@ -58,7 +58,7 @@ const BaseSelector = ({
|
|
|
58
58
|
"flex items-center",
|
|
59
59
|
size === "xs" && "gap-2",
|
|
60
60
|
size === "sm" && "gap-1.5",
|
|
61
|
-
size === "default" && "gap-1.5"
|
|
61
|
+
size === "default" && "gap-1.5",
|
|
62
62
|
)}
|
|
63
63
|
>
|
|
64
64
|
{showIcon && icon && (
|
|
@@ -67,7 +67,7 @@ const BaseSelector = ({
|
|
|
67
67
|
"flex items-center justify-center",
|
|
68
68
|
size === "xs" && "h-3 w-3.5",
|
|
69
69
|
size === "sm" && "h-3.5 w-4",
|
|
70
|
-
size === "default" && "h-4 w-5"
|
|
70
|
+
size === "default" && "h-4 w-5",
|
|
71
71
|
)}
|
|
72
72
|
>
|
|
73
73
|
{icon}
|
|
@@ -78,7 +78,7 @@ const BaseSelector = ({
|
|
|
78
78
|
"font-medium",
|
|
79
79
|
size === "xs" && "text-xs",
|
|
80
80
|
size === "sm" && "text-sm",
|
|
81
|
-
size === "default" && "text-sm"
|
|
81
|
+
size === "default" && "text-sm",
|
|
82
82
|
)}
|
|
83
83
|
>
|
|
84
84
|
{text}
|
|
@@ -90,7 +90,7 @@ const BaseSelector = ({
|
|
|
90
90
|
"text-muted-foreground",
|
|
91
91
|
size === "xs" && "text-xs",
|
|
92
92
|
size === "sm" && "text-sm",
|
|
93
|
-
size === "default" && "text-sm"
|
|
93
|
+
size === "default" && "text-sm",
|
|
94
94
|
)}
|
|
95
95
|
>
|
|
96
96
|
{placeholder}
|
|
@@ -32,8 +32,8 @@ const CampaignItem = React.forwardRef<HTMLDivElement, CampaignItemProps>(
|
|
|
32
32
|
|
|
33
33
|
// TODO: Refactor and add default icon here, maybe turtle icon?
|
|
34
34
|
const defaultIcon = (
|
|
35
|
-
<div className="
|
|
36
|
-
<svg className="
|
|
35
|
+
<div className="bg-primary/20 flex h-6 w-6 items-center justify-center rounded-full">
|
|
36
|
+
<svg className="h-4 w-4" viewBox="0 0 24 24" fill="currentColor">
|
|
37
37
|
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm4.59-12.42L10 14.17l-2.59-2.58L6 13l4 4 8-8z" />
|
|
38
38
|
</svg>
|
|
39
39
|
</div>
|
|
@@ -48,12 +48,18 @@ const CampaignItem = React.forwardRef<HTMLDivElement, CampaignItemProps>(
|
|
|
48
48
|
<WidgetItem ref={ref} onSelect={onSelect} selected={selected} {...props}>
|
|
49
49
|
<WidgetItemTop>
|
|
50
50
|
<WidgetItemLeft>
|
|
51
|
-
<LabelWithIcon
|
|
51
|
+
<LabelWithIcon
|
|
52
|
+
icon={icon || defaultIcon}
|
|
53
|
+
textSize="base"
|
|
54
|
+
iconSize="lg"
|
|
55
|
+
>
|
|
52
56
|
{name}
|
|
53
57
|
</LabelWithIcon>
|
|
54
58
|
</WidgetItemLeft>
|
|
55
59
|
<WidgetItemRight>
|
|
56
|
-
<span className="text-md
|
|
60
|
+
<span className="text-md text-foreground font-semibold">
|
|
61
|
+
{aprRange || "N/A"}
|
|
62
|
+
</span>
|
|
57
63
|
</WidgetItemRight>
|
|
58
64
|
</WidgetItemTop>
|
|
59
65
|
<WidgetItemBottom>
|
|
@@ -61,13 +67,13 @@ const CampaignItem = React.forwardRef<HTMLDivElement, CampaignItemProps>(
|
|
|
61
67
|
{chains && <IconList items={chains} label="Chains" size="sm" />}
|
|
62
68
|
<WidgetItemStats stats={stats} />
|
|
63
69
|
</WidgetItemLeft>
|
|
64
|
-
<WidgetItemRight className="flex flex-col gap-1
|
|
70
|
+
<WidgetItemRight className="flex flex-col items-end gap-1">
|
|
65
71
|
{rewards && <IconList items={rewards} label="Rewards" size="sm" />}
|
|
66
72
|
</WidgetItemRight>
|
|
67
73
|
</WidgetItemBottom>
|
|
68
74
|
</WidgetItem>
|
|
69
75
|
);
|
|
70
|
-
}
|
|
76
|
+
},
|
|
71
77
|
);
|
|
72
78
|
|
|
73
79
|
CampaignItem.displayName = "CampaignItem";
|