@m3000/market 0.0.1
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/LICENSE +21 -0
- package/dist/components/blocks/auction/Auction.d.ts +49 -0
- package/dist/components/blocks/auction/Auction.js +44 -0
- package/dist/components/blocks/auction/AuctionBidForm.d.ts +11 -0
- package/dist/components/blocks/auction/AuctionBidForm.js +88 -0
- package/dist/components/blocks/auction/AuctionBidInput.d.ts +9 -0
- package/dist/components/blocks/auction/AuctionBidInput.js +99 -0
- package/dist/components/blocks/auction/AuctionContext.d.ts +71 -0
- package/dist/components/blocks/auction/AuctionContext.js +228 -0
- package/dist/components/blocks/auction/AuctionInfo.d.ts +9 -0
- package/dist/components/blocks/auction/AuctionInfo.js +37 -0
- package/dist/components/blocks/auction/AuctionLayout.d.ts +63 -0
- package/dist/components/blocks/auction/AuctionLayout.js +80 -0
- package/dist/components/blocks/auction/AuctionRankings.d.ts +16 -0
- package/dist/components/blocks/auction/AuctionRankings.js +334 -0
- package/dist/components/blocks/auction/AuctionStatusTag.d.ts +15 -0
- package/dist/components/blocks/auction/AuctionStatusTag.js +60 -0
- package/dist/components/blocks/auction/AuctionSuggestedBids.d.ts +38 -0
- package/dist/components/blocks/auction/AuctionSuggestedBids.js +116 -0
- package/dist/components/blocks/auction/AuctionYourBidCard.d.ts +27 -0
- package/dist/components/blocks/auction/AuctionYourBidCard.js +94 -0
- package/dist/components/blocks/auction/AuctionYourBids.d.ts +9 -0
- package/dist/components/blocks/auction/AuctionYourBids.js +49 -0
- package/dist/components/blocks/auction/index.d.ts +12 -0
- package/dist/components/blocks/index.d.ts +12 -0
- package/dist/components/index.d.ts +28 -0
- package/dist/components/primitives/Button.d.ts +31 -0
- package/dist/components/primitives/Button.js +117 -0
- package/dist/components/primitives/Drawer.d.ts +43 -0
- package/dist/components/primitives/Drawer.js +51 -0
- package/dist/components/primitives/Feedback.d.ts +28 -0
- package/dist/components/primitives/Feedback.js +147 -0
- package/dist/components/primitives/MorphDialog.d.ts +39 -0
- package/dist/components/primitives/MorphDialog.js +87 -0
- package/dist/components/primitives/Price.d.ts +84 -0
- package/dist/components/primitives/Price.js +255 -0
- package/dist/components/primitives/PriceInput.d.ts +33 -0
- package/dist/components/primitives/PriceInput.js +25 -0
- package/dist/components/primitives/Receipt.d.ts +164 -0
- package/dist/components/primitives/Receipt.js +344 -0
- package/dist/components/primitives/Scale.d.ts +67 -0
- package/dist/components/primitives/Scale.js +132 -0
- package/dist/components/primitives/Separator.d.ts +22 -0
- package/dist/components/primitives/Separator.js +62 -0
- package/dist/components/primitives/Skeleton.d.ts +14 -0
- package/dist/components/primitives/Skeleton.js +20 -0
- package/dist/components/primitives/SteppedInput.d.ts +94 -0
- package/dist/components/primitives/SteppedInput.js +154 -0
- package/dist/components/primitives/Tabs.d.ts +37 -0
- package/dist/components/primitives/Tabs.js +99 -0
- package/dist/components/primitives/Tag.d.ts +24 -0
- package/dist/components/primitives/Tag.js +22 -0
- package/dist/components/primitives/Text.d.ts +32 -0
- package/dist/components/primitives/Text.js +65 -0
- package/dist/components/primitives/countdown/Countdown.d.ts +24 -0
- package/dist/components/primitives/countdown/Countdown.js +22 -0
- package/dist/components/primitives/framed-image/FramedImage.d.ts +13 -0
- package/dist/components/primitives/framed-image/FramedImage.js +37 -0
- package/dist/components/primitives/index.d.ts +17 -0
- package/dist/components/primitives/ranked-list/Ranking.d.ts +117 -0
- package/dist/components/primitives/ranked-list/Ranking.js +219 -0
- package/dist/components/primitives/ranked-list/index.d.ts +1 -0
- package/dist/hooks/useCountdown.d.ts +20 -0
- package/dist/hooks/useCountdown.js +75 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +36 -0
- package/dist/lib/cn.d.ts +6 -0
- package/dist/lib/cn.js +75 -0
- package/dist/lib/motion.d.ts +19 -0
- package/dist/lib/motion.js +43 -0
- package/dist/types/index.d.ts +120 -0
- package/dist/utils/format.d.ts +38 -0
- package/dist/utils/format.js +103 -0
- package/dist/utils/rank-utils.d.ts +34 -0
- package/dist/utils/rank-utils.js +80 -0
- package/dist/utils/tick-validation.d.ts +22 -0
- package/dist/utils/tick-validation.js +40 -0
- package/package.json +92 -0
- package/src/components/blocks/auction/Auction.tsx +74 -0
- package/src/components/blocks/auction/AuctionArtwork.tsx +4 -0
- package/src/components/blocks/auction/AuctionBidForm.tsx +138 -0
- package/src/components/blocks/auction/AuctionBidInput.tsx +166 -0
- package/src/components/blocks/auction/AuctionContext.tsx +401 -0
- package/src/components/blocks/auction/AuctionInfo.tsx +36 -0
- package/src/components/blocks/auction/AuctionLayout.tsx +200 -0
- package/src/components/blocks/auction/AuctionRankings.tsx +435 -0
- package/src/components/blocks/auction/AuctionStatusTag.tsx +98 -0
- package/src/components/blocks/auction/AuctionSuggestedBids.tsx +203 -0
- package/src/components/blocks/auction/AuctionYourBidCard.tsx +125 -0
- package/src/components/blocks/auction/AuctionYourBids.tsx +61 -0
- package/src/components/blocks/auction/index.ts +42 -0
- package/src/components/blocks/index.ts +1 -0
- package/src/components/index.ts +2 -0
- package/src/components/primitives/Button.tsx +183 -0
- package/src/components/primitives/Drawer.tsx +125 -0
- package/src/components/primitives/Feedback.tsx +185 -0
- package/src/components/primitives/MorphDialog.tsx +160 -0
- package/src/components/primitives/Price.tsx +394 -0
- package/src/components/primitives/PriceInput.tsx +48 -0
- package/src/components/primitives/Receipt.tsx +711 -0
- package/src/components/primitives/Scale.tsx +287 -0
- package/src/components/primitives/Separator.tsx +87 -0
- package/src/components/primitives/Skeleton.tsx +33 -0
- package/src/components/primitives/SteppedInput.tsx +313 -0
- package/src/components/primitives/Tabs.tsx +161 -0
- package/src/components/primitives/Tag.tsx +48 -0
- package/src/components/primitives/Text.tsx +102 -0
- package/src/components/primitives/countdown/Countdown.tsx +43 -0
- package/src/components/primitives/countdown/index.ts +2 -0
- package/src/components/primitives/framed-image/FramedImage.tsx +51 -0
- package/src/components/primitives/framed-image/index.ts +1 -0
- package/src/components/primitives/index.ts +42 -0
- package/src/components/primitives/ranked-list/RankedList.tsx +9 -0
- package/src/components/primitives/ranked-list/Ranking.tsx +454 -0
- package/src/components/primitives/ranked-list/index.ts +8 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useCountdown.ts +91 -0
- package/src/index.ts +130 -0
- package/src/lib/cn.ts +81 -0
- package/src/lib/index.ts +2 -0
- package/src/lib/motion.ts +55 -0
- package/src/public/lea-83-time-walk.png +0 -0
- package/src/public/lea-83-time-walk.webp +0 -0
- package/src/stories/Auction.stories.tsx +658 -0
- package/src/stories/AuctionLayout.stories.tsx +313 -0
- package/src/stories/AuctionStatusTag.stories.tsx +166 -0
- package/src/stories/AuctionYourBidCard.stories.tsx +257 -0
- package/src/stories/Button.stories.tsx +306 -0
- package/src/stories/Countdown.stories.tsx +158 -0
- package/src/stories/Feedback.stories.tsx +80 -0
- package/src/stories/FramedImage.stories.tsx +46 -0
- package/src/stories/MorphDialog.stories.tsx +88 -0
- package/src/stories/Price.stories.tsx +292 -0
- package/src/stories/RankedList.stories.tsx +190 -0
- package/src/stories/Receipt.stories.tsx +221 -0
- package/src/stories/Scale.stories.tsx +578 -0
- package/src/stories/Separator.stories.tsx +188 -0
- package/src/stories/Skeleton.stories.tsx +138 -0
- package/src/stories/SteppedInput.stories.tsx +321 -0
- package/src/stories/Tabs.stories.tsx +215 -0
- package/src/stories/Tag.stories.tsx +138 -0
- package/src/stories/Text.stories.tsx +245 -0
- package/src/styles/globals.css +39 -0
- package/src/styles/index.css +4 -0
- package/src/styles/theme/animation.css +11 -0
- package/src/styles/theme/color.css +185 -0
- package/src/styles/theme/index.css +3 -0
- package/src/styles/theme/typography.css +3 -0
- package/src/styles/utility.css +8 -0
- package/src/types/index.ts +149 -0
- package/src/utils/format.ts +130 -0
- package/src/utils/index.ts +16 -0
- package/src/utils/rank-utils.ts +131 -0
- package/src/utils/tick-validation.ts +65 -0
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Button } from "@/components/primitives/Button";
|
|
4
|
+
import { Scale } from "@/components/primitives/Scale";
|
|
5
|
+
import { Text } from "@/components/primitives/Text";
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Scale.Linear> = {
|
|
8
|
+
title: "Primitives/Scale",
|
|
9
|
+
component: Scale.Linear,
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: "centered",
|
|
12
|
+
},
|
|
13
|
+
decorators: [
|
|
14
|
+
(Story) => (
|
|
15
|
+
<div className="flex flex-col items-center gap-4 rounded-lg border border-border bg-background p-8">
|
|
16
|
+
<Story />
|
|
17
|
+
</div>
|
|
18
|
+
),
|
|
19
|
+
],
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default meta;
|
|
23
|
+
|
|
24
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
const formatDollars = (cents: bigint) => {
|
|
27
|
+
const dollars = Number(cents) / 100;
|
|
28
|
+
return dollars.toLocaleString("en-US", {
|
|
29
|
+
style: "currency",
|
|
30
|
+
currency: "USD",
|
|
31
|
+
minimumFractionDigits: 0,
|
|
32
|
+
maximumFractionDigits: 0,
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const formatValue = (value: bigint) => {
|
|
37
|
+
const val = Number(value) / 1e18;
|
|
38
|
+
return `${val.toFixed(4)}`;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const formatPercent = (value: number) => `${value.toFixed(0)}%`;
|
|
42
|
+
|
|
43
|
+
// ─── Stories ────────────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
export const BasicBigInt: StoryObj<typeof Scale.Linear> = {
|
|
46
|
+
render: () => {
|
|
47
|
+
const [selected, setSelected] = React.useState<bigint | null>(null);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div className="w-80">
|
|
51
|
+
<Text size="2" color="secondary" className="mb-4">
|
|
52
|
+
BigInt scale: $100 - $500, tick size: $10
|
|
53
|
+
</Text>
|
|
54
|
+
<Scale.Linear
|
|
55
|
+
domain={[10000n, 50000n]} // $100 - $500 in cents
|
|
56
|
+
getTickSize={() => 1000n} // $10 in cents
|
|
57
|
+
className="flex gap-2"
|
|
58
|
+
>
|
|
59
|
+
<Scale.Tick position={0}>
|
|
60
|
+
{({ value }) => {
|
|
61
|
+
const v = value as bigint;
|
|
62
|
+
return (
|
|
63
|
+
<Button
|
|
64
|
+
color={selected === v ? "primary" : "tertiary"}
|
|
65
|
+
onClick={() => setSelected(v)}
|
|
66
|
+
className="flex-1"
|
|
67
|
+
>
|
|
68
|
+
{formatDollars(v)}
|
|
69
|
+
</Button>
|
|
70
|
+
);
|
|
71
|
+
}}
|
|
72
|
+
</Scale.Tick>
|
|
73
|
+
<Scale.Tick position={0.5}>
|
|
74
|
+
{({ value }) => {
|
|
75
|
+
const v = value as bigint;
|
|
76
|
+
return (
|
|
77
|
+
<Button
|
|
78
|
+
color={selected === v ? "primary" : "tertiary"}
|
|
79
|
+
onClick={() => setSelected(v)}
|
|
80
|
+
className="flex-1"
|
|
81
|
+
>
|
|
82
|
+
{formatDollars(v)}
|
|
83
|
+
</Button>
|
|
84
|
+
);
|
|
85
|
+
}}
|
|
86
|
+
</Scale.Tick>
|
|
87
|
+
<Scale.Tick position={1}>
|
|
88
|
+
{({ value }) => {
|
|
89
|
+
const v = value as bigint;
|
|
90
|
+
return (
|
|
91
|
+
<Button
|
|
92
|
+
color={selected === v ? "primary" : "tertiary"}
|
|
93
|
+
onClick={() => setSelected(v)}
|
|
94
|
+
className="flex-1"
|
|
95
|
+
>
|
|
96
|
+
{formatDollars(v)}
|
|
97
|
+
</Button>
|
|
98
|
+
);
|
|
99
|
+
}}
|
|
100
|
+
</Scale.Tick>
|
|
101
|
+
</Scale.Linear>
|
|
102
|
+
{selected && (
|
|
103
|
+
<Text size="1" color="tertiary" className="mt-2">
|
|
104
|
+
Selected: {formatDollars(selected)}
|
|
105
|
+
</Text>
|
|
106
|
+
)}
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const BasicNumber: StoryObj<typeof Scale.Linear> = {
|
|
113
|
+
render: () => {
|
|
114
|
+
const [selected, setSelected] = React.useState<number | null>(null);
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<div className="w-80">
|
|
118
|
+
<Text size="2" color="secondary" className="mb-4">
|
|
119
|
+
Number scale: 0% - 100%, tick size: 10%
|
|
120
|
+
</Text>
|
|
121
|
+
<Scale.Linear
|
|
122
|
+
domain={[0, 100]}
|
|
123
|
+
getTickSize={() => 10}
|
|
124
|
+
className="flex gap-2"
|
|
125
|
+
>
|
|
126
|
+
<Scale.Tick position={0}>
|
|
127
|
+
{({ value }) => {
|
|
128
|
+
const v = value as number;
|
|
129
|
+
return (
|
|
130
|
+
<Button
|
|
131
|
+
color={selected === v ? "primary" : "tertiary"}
|
|
132
|
+
onClick={() => setSelected(v)}
|
|
133
|
+
className="flex-1"
|
|
134
|
+
>
|
|
135
|
+
{formatPercent(v)}
|
|
136
|
+
</Button>
|
|
137
|
+
);
|
|
138
|
+
}}
|
|
139
|
+
</Scale.Tick>
|
|
140
|
+
<Scale.Tick position={0.5}>
|
|
141
|
+
{({ value }) => {
|
|
142
|
+
const v = value as number;
|
|
143
|
+
return (
|
|
144
|
+
<Button
|
|
145
|
+
color={selected === v ? "primary" : "tertiary"}
|
|
146
|
+
onClick={() => setSelected(v)}
|
|
147
|
+
className="flex-1"
|
|
148
|
+
>
|
|
149
|
+
{formatPercent(v)}
|
|
150
|
+
</Button>
|
|
151
|
+
);
|
|
152
|
+
}}
|
|
153
|
+
</Scale.Tick>
|
|
154
|
+
<Scale.Tick position={1}>
|
|
155
|
+
{({ value }) => {
|
|
156
|
+
const v = value as number;
|
|
157
|
+
return (
|
|
158
|
+
<Button
|
|
159
|
+
color={selected === v ? "primary" : "tertiary"}
|
|
160
|
+
onClick={() => setSelected(v)}
|
|
161
|
+
className="flex-1"
|
|
162
|
+
>
|
|
163
|
+
{formatPercent(v)}
|
|
164
|
+
</Button>
|
|
165
|
+
);
|
|
166
|
+
}}
|
|
167
|
+
</Scale.Tick>
|
|
168
|
+
</Scale.Linear>
|
|
169
|
+
{selected !== null && (
|
|
170
|
+
<Text size="1" color="tertiary" className="mt-2">
|
|
171
|
+
Selected: {formatPercent(selected)}
|
|
172
|
+
</Text>
|
|
173
|
+
)}
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export const UsingTicksHelper: StoryObj<typeof Scale.Linear> = {
|
|
180
|
+
render: () => {
|
|
181
|
+
const [selected, setSelected] = React.useState<bigint | null>(null);
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<div className="w-80">
|
|
185
|
+
<Text size="2" color="secondary" className="mb-4">
|
|
186
|
+
Using Scale.Ticks to generate 4 evenly-spaced options
|
|
187
|
+
</Text>
|
|
188
|
+
<Scale.Linear
|
|
189
|
+
domain={[10000n, 50000n]}
|
|
190
|
+
getTickSize={() => 1000n}
|
|
191
|
+
className="flex gap-2"
|
|
192
|
+
>
|
|
193
|
+
<Scale.Ticks count={4}>
|
|
194
|
+
{({ value }) => {
|
|
195
|
+
const v = value as bigint;
|
|
196
|
+
return (
|
|
197
|
+
<Button
|
|
198
|
+
color={selected === v ? "primary" : "tertiary"}
|
|
199
|
+
onClick={() => setSelected(v)}
|
|
200
|
+
className="flex-1"
|
|
201
|
+
>
|
|
202
|
+
{formatDollars(v)}
|
|
203
|
+
</Button>
|
|
204
|
+
);
|
|
205
|
+
}}
|
|
206
|
+
</Scale.Ticks>
|
|
207
|
+
</Scale.Linear>
|
|
208
|
+
{selected && (
|
|
209
|
+
<Text size="1" color="tertiary" className="mt-2">
|
|
210
|
+
Selected: {formatDollars(selected)}
|
|
211
|
+
</Text>
|
|
212
|
+
)}
|
|
213
|
+
</div>
|
|
214
|
+
);
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
export const DynamicTickSize: StoryObj<typeof Scale.Linear> = {
|
|
219
|
+
render: () => {
|
|
220
|
+
const [selected, setSelected] = React.useState<bigint | null>(null);
|
|
221
|
+
|
|
222
|
+
// Tick size changes at $1000: $10 below, $100 above
|
|
223
|
+
const getTickSize = (value: bigint) => {
|
|
224
|
+
return value > 100000n ? 10000n : 1000n; // $100 vs $10 in cents
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
return (
|
|
228
|
+
<div className="w-96">
|
|
229
|
+
<Text size="2" color="secondary" className="mb-2">
|
|
230
|
+
Dynamic tick size: $10 below $1,000, $100 above
|
|
231
|
+
</Text>
|
|
232
|
+
<Text size="1" color="tertiary" className="mb-4">
|
|
233
|
+
Scale: $100 - $2,000
|
|
234
|
+
</Text>
|
|
235
|
+
<Scale.Linear
|
|
236
|
+
domain={[10000n, 200000n]} // $100 - $2000
|
|
237
|
+
getTickSize={getTickSize}
|
|
238
|
+
className="flex flex-wrap gap-2"
|
|
239
|
+
>
|
|
240
|
+
<Scale.Ticks count={5}>
|
|
241
|
+
{({ value, position }) => {
|
|
242
|
+
const v = value as bigint;
|
|
243
|
+
return (
|
|
244
|
+
<Button
|
|
245
|
+
color={selected === v ? "primary" : "tertiary"}
|
|
246
|
+
onClick={() => setSelected(v)}
|
|
247
|
+
size="sm"
|
|
248
|
+
>
|
|
249
|
+
<div className="flex flex-col items-center">
|
|
250
|
+
<span>{formatDollars(v)}</span>
|
|
251
|
+
<span className="text-xs opacity-60">
|
|
252
|
+
{(position * 100).toFixed(0)}%
|
|
253
|
+
</span>
|
|
254
|
+
</div>
|
|
255
|
+
</Button>
|
|
256
|
+
);
|
|
257
|
+
}}
|
|
258
|
+
</Scale.Ticks>
|
|
259
|
+
</Scale.Linear>
|
|
260
|
+
{selected && (
|
|
261
|
+
<Text size="1" color="tertiary" className="mt-2">
|
|
262
|
+
Selected: {formatDollars(selected)}
|
|
263
|
+
</Text>
|
|
264
|
+
)}
|
|
265
|
+
</div>
|
|
266
|
+
);
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
export const SnapModes: StoryObj<typeof Scale.Linear> = {
|
|
271
|
+
render: () => {
|
|
272
|
+
// Show how different snap modes affect the values
|
|
273
|
+
// With min=100, max=195, tick=10, position=0.5 → raw value = 147.5
|
|
274
|
+
// - nearest: 150
|
|
275
|
+
// - up: 150
|
|
276
|
+
// - down: 140
|
|
277
|
+
|
|
278
|
+
return (
|
|
279
|
+
<div className="w-96 space-y-6">
|
|
280
|
+
<Text size="2" color="secondary">
|
|
281
|
+
Scale: $100 - $195 (odd range), tick: $10, position: 0.5
|
|
282
|
+
</Text>
|
|
283
|
+
<Text size="1" color="tertiary">
|
|
284
|
+
Raw interpolated value would be $147.50
|
|
285
|
+
</Text>
|
|
286
|
+
|
|
287
|
+
<div>
|
|
288
|
+
<Text size="1" weight="medium" className="mb-2">
|
|
289
|
+
snapMode="nearest" (default) → rounds to $150
|
|
290
|
+
</Text>
|
|
291
|
+
<Scale.Linear
|
|
292
|
+
domain={[10000n, 19500n]}
|
|
293
|
+
getTickSize={() => 1000n}
|
|
294
|
+
snapMode="nearest"
|
|
295
|
+
className="flex gap-2"
|
|
296
|
+
>
|
|
297
|
+
<Scale.Tick position={0.5}>
|
|
298
|
+
{({ value }) => (
|
|
299
|
+
<Button color="tertiary">
|
|
300
|
+
{formatDollars(value as bigint)}
|
|
301
|
+
</Button>
|
|
302
|
+
)}
|
|
303
|
+
</Scale.Tick>
|
|
304
|
+
</Scale.Linear>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
<div>
|
|
308
|
+
<Text size="1" weight="medium" className="mb-2">
|
|
309
|
+
snapMode="up" → rounds up to $150
|
|
310
|
+
</Text>
|
|
311
|
+
<Scale.Linear
|
|
312
|
+
domain={[10000n, 19500n]}
|
|
313
|
+
getTickSize={() => 1000n}
|
|
314
|
+
snapMode="up"
|
|
315
|
+
className="flex gap-2"
|
|
316
|
+
>
|
|
317
|
+
<Scale.Tick position={0.5}>
|
|
318
|
+
{({ value }) => (
|
|
319
|
+
<Button color="tertiary">
|
|
320
|
+
{formatDollars(value as bigint)}
|
|
321
|
+
</Button>
|
|
322
|
+
)}
|
|
323
|
+
</Scale.Tick>
|
|
324
|
+
</Scale.Linear>
|
|
325
|
+
</div>
|
|
326
|
+
|
|
327
|
+
<div>
|
|
328
|
+
<Text size="1" weight="medium" className="mb-2">
|
|
329
|
+
snapMode="down" → rounds down to $140
|
|
330
|
+
</Text>
|
|
331
|
+
<Scale.Linear
|
|
332
|
+
domain={[10000n, 19500n]}
|
|
333
|
+
getTickSize={() => 1000n}
|
|
334
|
+
snapMode="down"
|
|
335
|
+
className="flex gap-2"
|
|
336
|
+
>
|
|
337
|
+
<Scale.Tick position={0.5}>
|
|
338
|
+
{({ value }) => (
|
|
339
|
+
<Button color="tertiary">
|
|
340
|
+
{formatDollars(value as bigint)}
|
|
341
|
+
</Button>
|
|
342
|
+
)}
|
|
343
|
+
</Scale.Tick>
|
|
344
|
+
</Scale.Linear>
|
|
345
|
+
</div>
|
|
346
|
+
|
|
347
|
+
<div>
|
|
348
|
+
<Text size="1" weight="medium" className="mb-2">
|
|
349
|
+
snapMode=false → no snapping, $147
|
|
350
|
+
</Text>
|
|
351
|
+
<Scale.Linear
|
|
352
|
+
domain={[10000n, 19500n]}
|
|
353
|
+
getTickSize={() => 1000n}
|
|
354
|
+
snapMode={false}
|
|
355
|
+
className="flex gap-2"
|
|
356
|
+
>
|
|
357
|
+
<Scale.Tick position={0.5}>
|
|
358
|
+
{({ value }) => (
|
|
359
|
+
<Button color="tertiary">
|
|
360
|
+
{formatDollars(value as bigint)}
|
|
361
|
+
</Button>
|
|
362
|
+
)}
|
|
363
|
+
</Scale.Tick>
|
|
364
|
+
</Scale.Linear>
|
|
365
|
+
</div>
|
|
366
|
+
</div>
|
|
367
|
+
);
|
|
368
|
+
},
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
export const BidSuggestions: StoryObj<typeof Scale.Linear> = {
|
|
372
|
+
render: () => {
|
|
373
|
+
const [selected, setSelected] = React.useState<bigint | null>(null);
|
|
374
|
+
const UNIT = BigInt(10 ** 18);
|
|
375
|
+
|
|
376
|
+
// Min: 0.01, Max: 1
|
|
377
|
+
const min = UNIT / 100n;
|
|
378
|
+
const max = UNIT;
|
|
379
|
+
|
|
380
|
+
// Tick: 0.01 below 0.1, 0.1 above
|
|
381
|
+
const getTickSize = (value: bigint) => {
|
|
382
|
+
return value > UNIT / 10n
|
|
383
|
+
? UNIT / 10n // 0.1
|
|
384
|
+
: UNIT / 100n; // 0.01
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
return (
|
|
388
|
+
<div className="w-96">
|
|
389
|
+
<Text size="3" weight="medium" className="mb-2">
|
|
390
|
+
Bid Suggestions
|
|
391
|
+
</Text>
|
|
392
|
+
<Text size="2" color="secondary" className="mb-4">
|
|
393
|
+
Reserve: 0.01, Max suggestion: 1
|
|
394
|
+
</Text>
|
|
395
|
+
<Scale.Linear
|
|
396
|
+
domain={[min, max]}
|
|
397
|
+
getTickSize={getTickSize}
|
|
398
|
+
snapMode="up"
|
|
399
|
+
className="flex flex-col gap-2"
|
|
400
|
+
>
|
|
401
|
+
<Scale.Ticks count={4}>
|
|
402
|
+
{({ value, position }) => {
|
|
403
|
+
const v = value as bigint;
|
|
404
|
+
return (
|
|
405
|
+
<Button
|
|
406
|
+
color={selected === v ? "primary" : "secondary"}
|
|
407
|
+
onClick={() => setSelected(v)}
|
|
408
|
+
className="w-full justify-between"
|
|
409
|
+
>
|
|
410
|
+
<span className="font-mono">{formatValue(v)}</span>
|
|
411
|
+
<span className="text-xs opacity-60">
|
|
412
|
+
{(position * 100).toFixed(0)}% of range
|
|
413
|
+
</span>
|
|
414
|
+
</Button>
|
|
415
|
+
);
|
|
416
|
+
}}
|
|
417
|
+
</Scale.Ticks>
|
|
418
|
+
</Scale.Linear>
|
|
419
|
+
{selected && (
|
|
420
|
+
<div className="mt-4 rounded-md border border-border p-3">
|
|
421
|
+
<Text size="1" color="tertiary">
|
|
422
|
+
Selected bid:
|
|
423
|
+
</Text>
|
|
424
|
+
<Text size="3" weight="medium" className="font-mono">
|
|
425
|
+
{formatValue(selected)}
|
|
426
|
+
</Text>
|
|
427
|
+
</div>
|
|
428
|
+
)}
|
|
429
|
+
</div>
|
|
430
|
+
);
|
|
431
|
+
},
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
export const WithExternalRankCalculation: StoryObj<typeof Scale.Linear> = {
|
|
435
|
+
render: () => {
|
|
436
|
+
const [selected, setSelected] = React.useState<bigint | null>(null);
|
|
437
|
+
|
|
438
|
+
// Mock rank calculation - higher bid = better rank
|
|
439
|
+
// This shows how to combine Scale with external rank logic
|
|
440
|
+
const getRank = (value: bigint) => {
|
|
441
|
+
const cents = Number(value);
|
|
442
|
+
// Simulate: $500 = rank 1, $100 = rank 20
|
|
443
|
+
const rank = Math.max(1, Math.round(21 - (cents / 10000) * 4));
|
|
444
|
+
return {
|
|
445
|
+
rank,
|
|
446
|
+
isWinning: rank <= 10, // Top 10 are winners
|
|
447
|
+
};
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
return (
|
|
451
|
+
<div className="w-96">
|
|
452
|
+
<Text size="2" color="secondary" className="mb-4">
|
|
453
|
+
Scale + external rank calculation (10 winning spots)
|
|
454
|
+
</Text>
|
|
455
|
+
<Scale.Linear
|
|
456
|
+
domain={[10000n, 50000n]}
|
|
457
|
+
getTickSize={() => 1000n}
|
|
458
|
+
className="flex flex-col gap-2"
|
|
459
|
+
>
|
|
460
|
+
<Scale.Ticks count={4}>
|
|
461
|
+
{({ value }) => {
|
|
462
|
+
const v = value as bigint;
|
|
463
|
+
const { rank, isWinning } = getRank(v);
|
|
464
|
+
return (
|
|
465
|
+
<Button
|
|
466
|
+
color={selected === v ? "primary" : "tertiary"}
|
|
467
|
+
onClick={() => setSelected(v)}
|
|
468
|
+
className="w-full justify-between"
|
|
469
|
+
>
|
|
470
|
+
<span>{formatDollars(v)}</span>
|
|
471
|
+
<span
|
|
472
|
+
className={isWinning ? "text-success" : "text-destructive"}
|
|
473
|
+
>
|
|
474
|
+
Rank #{rank} {isWinning ? "(winning)" : "(outbid)"}
|
|
475
|
+
</span>
|
|
476
|
+
</Button>
|
|
477
|
+
);
|
|
478
|
+
}}
|
|
479
|
+
</Scale.Ticks>
|
|
480
|
+
</Scale.Linear>
|
|
481
|
+
</div>
|
|
482
|
+
);
|
|
483
|
+
},
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
export const CustomCardStyling: StoryObj<typeof Scale.Linear> = {
|
|
487
|
+
render: () => {
|
|
488
|
+
const [selected, setSelected] = React.useState<bigint | null>(null);
|
|
489
|
+
|
|
490
|
+
return (
|
|
491
|
+
<div className="w-80">
|
|
492
|
+
<Text size="2" color="secondary" className="mb-4">
|
|
493
|
+
Custom card-style rendering
|
|
494
|
+
</Text>
|
|
495
|
+
<Scale.Linear
|
|
496
|
+
domain={[10000n, 50000n]}
|
|
497
|
+
getTickSize={() => 5000n}
|
|
498
|
+
className="grid grid-cols-3 gap-3"
|
|
499
|
+
>
|
|
500
|
+
<Scale.Ticks count={3}>
|
|
501
|
+
{({ value, position }) => {
|
|
502
|
+
const v = value as bigint;
|
|
503
|
+
return (
|
|
504
|
+
<button
|
|
505
|
+
type="button"
|
|
506
|
+
onClick={() => setSelected(v)}
|
|
507
|
+
className={`rounded-lg border-2 p-3 text-center transition-colors ${
|
|
508
|
+
selected === v
|
|
509
|
+
? "border-foreground bg-foreground text-background"
|
|
510
|
+
: "border-border bg-muted hover:border-foreground/50"
|
|
511
|
+
}`}
|
|
512
|
+
>
|
|
513
|
+
<div className="text-lg font-semibold">
|
|
514
|
+
{formatDollars(v)}
|
|
515
|
+
</div>
|
|
516
|
+
<div
|
|
517
|
+
className={`mt-1 text-xs ${
|
|
518
|
+
selected === v ? "opacity-80" : "text-muted-foreground"
|
|
519
|
+
}`}
|
|
520
|
+
>
|
|
521
|
+
{(position * 100).toFixed(0)}%
|
|
522
|
+
</div>
|
|
523
|
+
</button>
|
|
524
|
+
);
|
|
525
|
+
}}
|
|
526
|
+
</Scale.Ticks>
|
|
527
|
+
</Scale.Linear>
|
|
528
|
+
</div>
|
|
529
|
+
);
|
|
530
|
+
},
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
export const TemperatureScale: StoryObj<typeof Scale.Linear> = {
|
|
534
|
+
render: () => {
|
|
535
|
+
const [selected, setSelected] = React.useState<number | null>(null);
|
|
536
|
+
|
|
537
|
+
return (
|
|
538
|
+
<div className="w-80">
|
|
539
|
+
<Text size="2" color="secondary" className="mb-4">
|
|
540
|
+
Number scale: Temperature 0°C - 40°C
|
|
541
|
+
</Text>
|
|
542
|
+
<Scale.Linear
|
|
543
|
+
domain={[0, 40]}
|
|
544
|
+
getTickSize={() => 5}
|
|
545
|
+
className="flex gap-2"
|
|
546
|
+
>
|
|
547
|
+
<Scale.Ticks count={5}>
|
|
548
|
+
{({ value }) => {
|
|
549
|
+
const v = value as number;
|
|
550
|
+
const isCold = v < 15;
|
|
551
|
+
const isHot = v > 30;
|
|
552
|
+
return (
|
|
553
|
+
<Button
|
|
554
|
+
color={selected === v ? "primary" : "tertiary"}
|
|
555
|
+
onClick={() => setSelected(v)}
|
|
556
|
+
className="flex-1"
|
|
557
|
+
>
|
|
558
|
+
<span
|
|
559
|
+
className={
|
|
560
|
+
isCold ? "text-blue-400" : isHot ? "text-red-400" : ""
|
|
561
|
+
}
|
|
562
|
+
>
|
|
563
|
+
{v}°C
|
|
564
|
+
</span>
|
|
565
|
+
</Button>
|
|
566
|
+
);
|
|
567
|
+
}}
|
|
568
|
+
</Scale.Ticks>
|
|
569
|
+
</Scale.Linear>
|
|
570
|
+
{selected !== null && (
|
|
571
|
+
<Text size="1" color="tertiary" className="mt-2">
|
|
572
|
+
Selected: {selected}°C
|
|
573
|
+
</Text>
|
|
574
|
+
)}
|
|
575
|
+
</div>
|
|
576
|
+
);
|
|
577
|
+
},
|
|
578
|
+
};
|