@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,87 +0,0 @@
|
|
|
1
|
-
import { useMemo } from "react";
|
|
2
|
-
import { Asset } from "../asset-list";
|
|
3
|
-
import { WidgetListGroup } from "../../widget-list-items";
|
|
4
|
-
|
|
5
|
-
interface UseAssetGroupingProps {
|
|
6
|
-
assets: Asset[];
|
|
7
|
-
groupByChain: boolean;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const CHAIN_ICONS: Record<number, string> = {
|
|
11
|
-
1: "https://storage.googleapis.com/turtle-assets/tokens/eth.png",
|
|
12
|
-
747474:
|
|
13
|
-
"https://storage.googleapis.com/turtle-assets/partners/polygon/katana.svg",
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export function useAssetGrouping({
|
|
17
|
-
assets,
|
|
18
|
-
groupByChain,
|
|
19
|
-
}: UseAssetGroupingProps): WidgetListGroup<Asset>[] {
|
|
20
|
-
return useMemo(() => {
|
|
21
|
-
// First, sort all assets by balance (USD value) in descending order
|
|
22
|
-
const sortedAssets = [...assets].sort((a, b) => {
|
|
23
|
-
// Parse balance USD values, removing $ and commas
|
|
24
|
-
const balanceA = parseFloat(a.balanceUSD.replace(/[$,]/g, "") || "0");
|
|
25
|
-
const balanceB = parseFloat(b.balanceUSD.replace(/[$,]/g, "") || "0");
|
|
26
|
-
return balanceB - balanceA;
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
if (!groupByChain) {
|
|
30
|
-
return [
|
|
31
|
-
{
|
|
32
|
-
id: "all-assets",
|
|
33
|
-
items: sortedAssets,
|
|
34
|
-
},
|
|
35
|
-
];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Group by chain
|
|
39
|
-
const chainGroups = sortedAssets.reduce(
|
|
40
|
-
(acc, asset) => {
|
|
41
|
-
if (!acc[asset.chainId]) {
|
|
42
|
-
acc[asset.chainId] = {
|
|
43
|
-
id: asset.chainId,
|
|
44
|
-
title: asset.chainName,
|
|
45
|
-
// Improve this adding chain icon to balances data
|
|
46
|
-
icon: CHAIN_ICONS[Number(asset.chainId)],
|
|
47
|
-
items: [],
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
acc[asset.chainId].items.push(asset);
|
|
51
|
-
return acc;
|
|
52
|
-
},
|
|
53
|
-
{} as Record<string, WidgetListGroup<Asset>>,
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
console.log("chainGroups", chainGroups);
|
|
57
|
-
|
|
58
|
-
// Sort groups by: 1) highest balance in group, 2) number of tokens with balance
|
|
59
|
-
const groupsArray = Object.values(chainGroups);
|
|
60
|
-
groupsArray.sort((a, b) => {
|
|
61
|
-
// Get the highest balance in each group (items are already sorted)
|
|
62
|
-
const maxBalanceA =
|
|
63
|
-
a.items.length > 0
|
|
64
|
-
? parseFloat(a.items[0].balanceUSD.replace(/[$,]/g, "") || "0")
|
|
65
|
-
: 0;
|
|
66
|
-
const maxBalanceB =
|
|
67
|
-
b.items.length > 0
|
|
68
|
-
? parseFloat(b.items[0].balanceUSD.replace(/[$,]/g, "") || "0")
|
|
69
|
-
: 0;
|
|
70
|
-
|
|
71
|
-
// If highest balances are equal, sort by number of tokens with non-zero balance
|
|
72
|
-
if (maxBalanceA === maxBalanceB) {
|
|
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;
|
|
79
|
-
return nonZeroCountB - nonZeroCountA;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return maxBalanceB - maxBalanceA;
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
return groupsArray;
|
|
86
|
-
}, [assets, groupByChain]);
|
|
87
|
-
}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
import { cn } from "@/lib/utils";
|
|
4
|
-
import type { ReactNode } from "react";
|
|
5
|
-
|
|
6
|
-
// Minimal Token type - only the fields we need
|
|
7
|
-
interface TokenLike {
|
|
8
|
-
symbol: string;
|
|
9
|
-
logoUrl?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface BaseSelectorProps {
|
|
13
|
-
icon?: React.ReactNode;
|
|
14
|
-
text: string;
|
|
15
|
-
onClick?: () => void;
|
|
16
|
-
className?: string;
|
|
17
|
-
variant?: "default" | "bordered";
|
|
18
|
-
size?: "xs" | "sm" | "default";
|
|
19
|
-
placeholder?: string;
|
|
20
|
-
showIcon?: boolean;
|
|
21
|
-
// New: Accept token directly
|
|
22
|
-
token?: TokenLike;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Utility convert icon url to img element
|
|
26
|
-
const iconUrlToImg = (iconUrl?: string, alt: string = ""): ReactNode => {
|
|
27
|
-
return iconUrl ? (
|
|
28
|
-
<img src={iconUrl} alt={alt} className="h-4 w-4 rounded-full" />
|
|
29
|
-
) : (
|
|
30
|
-
<div className="bg-muted flex h-4 w-4 items-center justify-center rounded-full text-xs">
|
|
31
|
-
{alt.charAt(0)}
|
|
32
|
-
</div>
|
|
33
|
-
);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
// Generate icon from token
|
|
37
|
-
const getTokenIcon = (token: TokenLike): ReactNode => {
|
|
38
|
-
return iconUrlToImg(token.logoUrl, token.symbol);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const BaseSelector = ({
|
|
42
|
-
icon,
|
|
43
|
-
text,
|
|
44
|
-
onClick,
|
|
45
|
-
className,
|
|
46
|
-
variant = "bordered",
|
|
47
|
-
size = "default",
|
|
48
|
-
placeholder = "Select",
|
|
49
|
-
showIcon = true,
|
|
50
|
-
token,
|
|
51
|
-
}: BaseSelectorProps) => {
|
|
52
|
-
// Determine the actual icon to display
|
|
53
|
-
const displayIcon = token ? getTokenIcon(token) : icon;
|
|
54
|
-
const displayText = token?.symbol || text;
|
|
55
|
-
const hasContent = displayText || displayIcon;
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<div
|
|
59
|
-
onClick={onClick}
|
|
60
|
-
className={cn(
|
|
61
|
-
"bg-muted hover:bg-accent/70 text-foreground inline-flex w-auto min-w-[80px] cursor-pointer items-center justify-between rounded-full font-medium",
|
|
62
|
-
"focus:ring-primary/20 transition-colors focus:ring-2 focus:outline-none",
|
|
63
|
-
variant === "bordered" && "border-border border",
|
|
64
|
-
size === "xs" && "h-7 min-w-[80px] gap-2 px-2.5 py-1",
|
|
65
|
-
size === "sm" && "h-8 min-w-[75px] gap-1.5 px-3 py-1.5",
|
|
66
|
-
size === "default" && "h-10 min-w-[80px] gap-1.5 px-3 py-2",
|
|
67
|
-
className,
|
|
68
|
-
)}
|
|
69
|
-
role="button"
|
|
70
|
-
tabIndex={0}
|
|
71
|
-
>
|
|
72
|
-
{hasContent ? (
|
|
73
|
-
<div
|
|
74
|
-
className={cn(
|
|
75
|
-
"flex items-center",
|
|
76
|
-
size === "xs" && "gap-2",
|
|
77
|
-
size === "sm" && "gap-1.5",
|
|
78
|
-
size === "default" && "gap-1.5",
|
|
79
|
-
)}
|
|
80
|
-
>
|
|
81
|
-
{showIcon && displayIcon && (
|
|
82
|
-
<span
|
|
83
|
-
className={cn(
|
|
84
|
-
"flex items-center justify-center",
|
|
85
|
-
size === "xs" && "h-3 w-3.5",
|
|
86
|
-
size === "sm" && "h-3.5 w-4",
|
|
87
|
-
size === "default" && "h-4 w-5",
|
|
88
|
-
)}
|
|
89
|
-
>
|
|
90
|
-
{displayIcon}
|
|
91
|
-
</span>
|
|
92
|
-
)}
|
|
93
|
-
<span
|
|
94
|
-
className={cn(
|
|
95
|
-
"font-medium",
|
|
96
|
-
size === "xs" && "text-xs",
|
|
97
|
-
size === "sm" && "text-sm",
|
|
98
|
-
size === "default" && "text-sm",
|
|
99
|
-
)}
|
|
100
|
-
>
|
|
101
|
-
{displayText}
|
|
102
|
-
</span>
|
|
103
|
-
</div>
|
|
104
|
-
) : (
|
|
105
|
-
<span
|
|
106
|
-
className={cn(
|
|
107
|
-
"text-muted-foreground",
|
|
108
|
-
size === "xs" && "text-xs",
|
|
109
|
-
size === "sm" && "text-sm",
|
|
110
|
-
size === "default" && "text-sm",
|
|
111
|
-
)}
|
|
112
|
-
>
|
|
113
|
-
{placeholder}
|
|
114
|
-
</span>
|
|
115
|
-
)}
|
|
116
|
-
</div>
|
|
117
|
-
);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
export { BaseSelector, iconUrlToImg, getTokenIcon };
|
|
121
|
-
export type { BaseSelectorProps, TokenLike };
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { LabelWithIcon } from "@/components/ui/label-with-icon";
|
|
3
|
-
import {
|
|
4
|
-
WidgetItem,
|
|
5
|
-
WidgetItemTop,
|
|
6
|
-
WidgetItemBottom,
|
|
7
|
-
WidgetItemLeft,
|
|
8
|
-
WidgetItemRight,
|
|
9
|
-
} from "./widget-item";
|
|
10
|
-
import { IconList, IconListItem } from "@/components/ui/icon-list";
|
|
11
|
-
import { WidgetItemStats } from "./widget-item-stats";
|
|
12
|
-
|
|
13
|
-
interface CampaignItemValue {
|
|
14
|
-
icon: string; // icon url
|
|
15
|
-
name: string;
|
|
16
|
-
aprRange: string;
|
|
17
|
-
tvl: string;
|
|
18
|
-
participants?: string;
|
|
19
|
-
rewards?: IconListItem[];
|
|
20
|
-
chains?: IconListItem[];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface CampaignItemProps extends React.ComponentProps<"div"> {
|
|
24
|
-
value: CampaignItemValue;
|
|
25
|
-
onSelect?: () => void;
|
|
26
|
-
selected?: boolean;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const CampaignItem = React.forwardRef<HTMLDivElement, CampaignItemProps>(
|
|
30
|
-
({ value, onSelect, selected = false, ...props }, ref) => {
|
|
31
|
-
const { icon, name, tvl, participants, aprRange, rewards, chains } = value;
|
|
32
|
-
|
|
33
|
-
// TODO: Refactor and add default icon here, maybe turtle icon?
|
|
34
|
-
const defaultIcon = (
|
|
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
|
-
<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
|
-
</svg>
|
|
39
|
-
</div>
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
const stats = [
|
|
43
|
-
{ label: "TVL", value: tvl },
|
|
44
|
-
{ label: "Participants", value: participants || "" },
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<WidgetItem ref={ref} onSelect={onSelect} selected={selected} {...props}>
|
|
49
|
-
<WidgetItemTop>
|
|
50
|
-
<WidgetItemLeft>
|
|
51
|
-
<LabelWithIcon
|
|
52
|
-
icon={icon || defaultIcon}
|
|
53
|
-
textSize="base"
|
|
54
|
-
iconSize="lg"
|
|
55
|
-
>
|
|
56
|
-
{name}
|
|
57
|
-
</LabelWithIcon>
|
|
58
|
-
</WidgetItemLeft>
|
|
59
|
-
<WidgetItemRight>
|
|
60
|
-
<span className="text-md text-foreground font-semibold">
|
|
61
|
-
{aprRange || "N/A"}
|
|
62
|
-
</span>
|
|
63
|
-
</WidgetItemRight>
|
|
64
|
-
</WidgetItemTop>
|
|
65
|
-
<WidgetItemBottom>
|
|
66
|
-
<WidgetItemLeft>
|
|
67
|
-
{chains && <IconList items={chains} label="Chains" size="sm" />}
|
|
68
|
-
<WidgetItemStats stats={stats} />
|
|
69
|
-
</WidgetItemLeft>
|
|
70
|
-
<WidgetItemRight className="flex flex-col items-end gap-1">
|
|
71
|
-
{rewards && <IconList items={rewards} label="Rewards" size="sm" />}
|
|
72
|
-
</WidgetItemRight>
|
|
73
|
-
</WidgetItemBottom>
|
|
74
|
-
</WidgetItem>
|
|
75
|
-
);
|
|
76
|
-
},
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
CampaignItem.displayName = "CampaignItem";
|
|
80
|
-
|
|
81
|
-
export { CampaignItem };
|
|
82
|
-
export type { CampaignItemProps, CampaignItemValue };
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { LabelWithIcon } from "@/components/ui/label-with-icon";
|
|
3
|
-
import {
|
|
4
|
-
WidgetItem,
|
|
5
|
-
WidgetItemTop,
|
|
6
|
-
WidgetItemBottom,
|
|
7
|
-
WidgetItemLeft,
|
|
8
|
-
WidgetItemRight,
|
|
9
|
-
} from "./widget-item";
|
|
10
|
-
import { IconList, IconListItem } from "@/components/ui/icon-list";
|
|
11
|
-
import { WidgetItemStats } from "./widget-item-stats";
|
|
12
|
-
import { OpportunityType } from "../opportunity";
|
|
13
|
-
import { SparkleIcon, SparklesIcon } from "lucide-react";
|
|
14
|
-
|
|
15
|
-
interface DealItemValue {
|
|
16
|
-
icon: string;
|
|
17
|
-
name: string;
|
|
18
|
-
apr: string;
|
|
19
|
-
tvl: string;
|
|
20
|
-
turtleBoost: string;
|
|
21
|
-
chains?: IconListItem[];
|
|
22
|
-
category: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface DealItemProps extends React.ComponentProps<"div"> {
|
|
26
|
-
value: DealItemValue;
|
|
27
|
-
onSelect?: () => void;
|
|
28
|
-
selected?: boolean;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const DealItem = React.forwardRef<HTMLDivElement, DealItemProps>(
|
|
32
|
-
({ value, onSelect, selected = false, ...props }, ref) => {
|
|
33
|
-
const { icon, name, chains, tvl, turtleBoost, category } = value;
|
|
34
|
-
|
|
35
|
-
const defaultIcon = (
|
|
36
|
-
<div className="bg-primary/20 flex h-6 w-6 items-center justify-center rounded-full">
|
|
37
|
-
<svg className="h-4 w-4" viewBox="0 0 24 24" fill="currentColor">
|
|
38
|
-
<path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58s1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41s-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z" />
|
|
39
|
-
</svg>
|
|
40
|
-
</div>
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
const stats = React.useMemo(
|
|
44
|
-
() => [
|
|
45
|
-
{ label: "TVL", value: tvl },
|
|
46
|
-
{
|
|
47
|
-
label: "Turtle Boost",
|
|
48
|
-
value: turtleBoost,
|
|
49
|
-
icon: <SparklesIcon size={12} />,
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
[tvl, turtleBoost],
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
return (
|
|
56
|
-
<WidgetItem ref={ref} onSelect={onSelect} selected={selected} {...props}>
|
|
57
|
-
<WidgetItemTop>
|
|
58
|
-
<WidgetItemLeft>
|
|
59
|
-
<LabelWithIcon
|
|
60
|
-
icon={icon || defaultIcon}
|
|
61
|
-
textSize="base"
|
|
62
|
-
iconSize="lg"
|
|
63
|
-
>
|
|
64
|
-
{name}
|
|
65
|
-
</LabelWithIcon>
|
|
66
|
-
</WidgetItemLeft>
|
|
67
|
-
<WidgetItemRight>
|
|
68
|
-
<span className="text-md text-foreground font-semibold">
|
|
69
|
-
{turtleBoost}
|
|
70
|
-
</span>
|
|
71
|
-
</WidgetItemRight>
|
|
72
|
-
</WidgetItemTop>
|
|
73
|
-
<WidgetItemBottom>
|
|
74
|
-
<WidgetItemLeft>
|
|
75
|
-
<WidgetItemStats stats={stats} />
|
|
76
|
-
{/* <OpportunityType type={"Boosted Deal"} /> */}
|
|
77
|
-
</WidgetItemLeft>
|
|
78
|
-
<WidgetItemRight>
|
|
79
|
-
{chains && (
|
|
80
|
-
<IconList items={chains} label="Available on" size="sm" />
|
|
81
|
-
)}
|
|
82
|
-
</WidgetItemRight>
|
|
83
|
-
</WidgetItemBottom>
|
|
84
|
-
</WidgetItem>
|
|
85
|
-
);
|
|
86
|
-
},
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
DealItem.displayName = "DealItem";
|
|
90
|
-
|
|
91
|
-
export { DealItem };
|
|
92
|
-
export type { DealItemProps };
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
export * from "./base-selector";
|
|
2
|
-
export * from "./widget-list-items";
|
|
3
|
-
export * from "./asset-list";
|
|
4
|
-
|
|
5
|
-
// Base components
|
|
6
|
-
export {
|
|
7
|
-
WidgetItem,
|
|
8
|
-
WidgetItemTop,
|
|
9
|
-
WidgetItemBottom,
|
|
10
|
-
WidgetItemLeft,
|
|
11
|
-
WidgetItemRight,
|
|
12
|
-
} from "./widget-item";
|
|
13
|
-
export type {
|
|
14
|
-
WidgetItemProps,
|
|
15
|
-
WidgetItemTopProps,
|
|
16
|
-
WidgetItemBottomProps,
|
|
17
|
-
WidgetItemLeftProps,
|
|
18
|
-
WidgetItemRightProps,
|
|
19
|
-
} from "./widget-item";
|
|
20
|
-
|
|
21
|
-
// Helper components
|
|
22
|
-
export { WidgetItemStats } from "./widget-item-stats";
|
|
23
|
-
export type { WidgetItemStatsProps, Stat } from "./widget-item-stats";
|
|
24
|
-
|
|
25
|
-
// Item components
|
|
26
|
-
export { OpportunityItem } from "./opportunity-item";
|
|
27
|
-
export type {
|
|
28
|
-
OpportunityItemProps,
|
|
29
|
-
OpportunityItemValue,
|
|
30
|
-
} from "./opportunity-item";
|
|
31
|
-
|
|
32
|
-
export { CampaignItem } from "./campaign-item";
|
|
33
|
-
export type { CampaignItemProps, CampaignItemValue } from "./campaign-item";
|
|
34
|
-
|
|
35
|
-
export { DealItem } from "./deal-item";
|
|
36
|
-
export type { DealItemProps } from "./deal-item";
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { LabelWithIcon } from "@/components/ui/label-with-icon";
|
|
3
|
-
import {
|
|
4
|
-
WidgetItem,
|
|
5
|
-
WidgetItemTop,
|
|
6
|
-
WidgetItemBottom,
|
|
7
|
-
WidgetItemLeft,
|
|
8
|
-
WidgetItemRight,
|
|
9
|
-
} from "./widget-item";
|
|
10
|
-
import { IconList, IconListItem } from "@/components/ui/icon-list";
|
|
11
|
-
import { WidgetItemStats } from "./widget-item-stats";
|
|
12
|
-
import { SparklesIcon } from "lucide-react";
|
|
13
|
-
|
|
14
|
-
interface OpportunityItemValue {
|
|
15
|
-
icon: string;
|
|
16
|
-
name: string;
|
|
17
|
-
tvl: string;
|
|
18
|
-
apr: string;
|
|
19
|
-
incentives: string[] | IconListItem[];
|
|
20
|
-
aprBreakdown: {
|
|
21
|
-
name: string;
|
|
22
|
-
apr: number;
|
|
23
|
-
description: string;
|
|
24
|
-
iconUrl: string;
|
|
25
|
-
boost: boolean;
|
|
26
|
-
}[];
|
|
27
|
-
chain: IconListItem;
|
|
28
|
-
turtleBoost: string | null;
|
|
29
|
-
partner: { icon: string; name: string } | null;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface OpportunityItemProps extends React.ComponentProps<"div"> {
|
|
33
|
-
value: OpportunityItemValue;
|
|
34
|
-
incentives?: string[] | IconListItem[];
|
|
35
|
-
chains?: IconListItem[];
|
|
36
|
-
onSelect?: () => void;
|
|
37
|
-
selected?: boolean;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const OpportunityItem = React.forwardRef<HTMLDivElement, OpportunityItemProps>(
|
|
41
|
-
({ value, onSelect, selected = false, ...props }, ref) => {
|
|
42
|
-
const { icon, name, tvl, apr, incentives, chain, turtleBoost } = value;
|
|
43
|
-
|
|
44
|
-
const defaultIcon = (
|
|
45
|
-
<div className="bg-primary/20 flex h-6 w-6 items-center justify-center rounded-full">
|
|
46
|
-
<svg className="h-4 w-4" viewBox="0 0 24 24" fill="currentColor">
|
|
47
|
-
<path d="M12 2L13.09 8.26L20 7L18.74 13.09L22 14L16.74 19.26L17 21L10.91 19.74L10 22L8.09 15.74L2 17L3.26 10.91L0 10L5.26 4.74L5 3L11.09 4.26L12 2Z" />
|
|
48
|
-
</svg>
|
|
49
|
-
</div>
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
const stats = React.useMemo(() => {
|
|
53
|
-
if (!turtleBoost) return [{ label: "TVL", value: tvl || "" }];
|
|
54
|
-
return [
|
|
55
|
-
{ label: "TVL", value: tvl || "" },
|
|
56
|
-
{
|
|
57
|
-
label: "Turtle Boost",
|
|
58
|
-
value: turtleBoost,
|
|
59
|
-
icon: <SparklesIcon size={12} />,
|
|
60
|
-
},
|
|
61
|
-
];
|
|
62
|
-
}, []);
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<WidgetItem ref={ref} onSelect={onSelect} selected={selected} {...props}>
|
|
66
|
-
<WidgetItemTop>
|
|
67
|
-
<WidgetItemLeft>
|
|
68
|
-
<LabelWithIcon
|
|
69
|
-
icon={icon || defaultIcon}
|
|
70
|
-
textSize="base"
|
|
71
|
-
iconSize="lg"
|
|
72
|
-
>
|
|
73
|
-
{name}
|
|
74
|
-
</LabelWithIcon>
|
|
75
|
-
</WidgetItemLeft>
|
|
76
|
-
<WidgetItemRight>
|
|
77
|
-
{apr && (
|
|
78
|
-
<span className="text-md text-foreground font-semibold">
|
|
79
|
-
{apr}
|
|
80
|
-
</span>
|
|
81
|
-
)}
|
|
82
|
-
</WidgetItemRight>
|
|
83
|
-
</WidgetItemTop>
|
|
84
|
-
<WidgetItemBottom>
|
|
85
|
-
<WidgetItemLeft>
|
|
86
|
-
{chain && <IconList items={[chain]} label="Chains" size="sm" />}
|
|
87
|
-
<WidgetItemStats stats={stats} />
|
|
88
|
-
</WidgetItemLeft>
|
|
89
|
-
<WidgetItemRight>
|
|
90
|
-
<div className="flex flex-col items-end gap-1">
|
|
91
|
-
{incentives && (
|
|
92
|
-
<IconList items={incentives} label="Rewards" size="sm" />
|
|
93
|
-
)}
|
|
94
|
-
</div>
|
|
95
|
-
</WidgetItemRight>
|
|
96
|
-
</WidgetItemBottom>
|
|
97
|
-
</WidgetItem>
|
|
98
|
-
);
|
|
99
|
-
},
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
OpportunityItem.displayName = "OpportunityItem";
|
|
103
|
-
|
|
104
|
-
export { OpportunityItem };
|
|
105
|
-
export type { OpportunityItemProps, OpportunityItemValue };
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { cn } from "@/lib/utils";
|
|
3
|
-
|
|
4
|
-
interface Stat {
|
|
5
|
-
label: string;
|
|
6
|
-
value: string;
|
|
7
|
-
icon?: React.ReactNode;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface WidgetItemStatsProps extends React.ComponentProps<"div"> {
|
|
11
|
-
stats: Stat[];
|
|
12
|
-
separator?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const WidgetItemStats = React.forwardRef<HTMLDivElement, WidgetItemStatsProps>(
|
|
16
|
-
({ className, stats, separator = " | ", ...props }, ref) => {
|
|
17
|
-
const validStats = stats.filter((stat) => stat.value);
|
|
18
|
-
|
|
19
|
-
if (validStats.length === 0) return null;
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<div
|
|
23
|
-
ref={ref}
|
|
24
|
-
className={cn("text-muted-foreground flex gap-2 text-xs", className)}
|
|
25
|
-
{...props}
|
|
26
|
-
>
|
|
27
|
-
{validStats.map((stat, index) => (
|
|
28
|
-
<React.Fragment key={stat.label}>
|
|
29
|
-
{index > 0 && <span>{separator}</span>}
|
|
30
|
-
<span className="flex items-center justify-center gap-1">
|
|
31
|
-
<span>{stat.label}: </span>
|
|
32
|
-
{stat.icon ? (
|
|
33
|
-
<span className="flex gap-1">
|
|
34
|
-
{stat.icon} {stat.value}
|
|
35
|
-
</span>
|
|
36
|
-
) : (
|
|
37
|
-
<span>{stat.value}</span>
|
|
38
|
-
)}
|
|
39
|
-
</span>
|
|
40
|
-
</React.Fragment>
|
|
41
|
-
))}
|
|
42
|
-
</div>
|
|
43
|
-
);
|
|
44
|
-
},
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
WidgetItemStats.displayName = "WidgetItemStats";
|
|
48
|
-
|
|
49
|
-
export { WidgetItemStats };
|
|
50
|
-
export type { WidgetItemStatsProps, Stat };
|