@sudobility/consumables_pages 0.0.41 → 0.0.43
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/CreditBalanceBadge.d.ts +1 -6
- package/dist/CreditStorePage.d.ts +1 -6
- package/dist/PurchaseHistoryPage.d.ts +1 -5
- package/dist/UsageHistoryPage.d.ts +1 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +638 -4
- package/dist/types.d.ts +3 -9
- package/package.json +5 -4
- package/dist/CreditBalanceBadge.js +0 -23
- package/dist/CreditStorePage.js +0 -18
- package/dist/LoadingSpinner.js +0 -14
- package/dist/PurchaseHistoryPage.js +0 -18
- package/dist/UsageHistoryPage.js +0 -23
- package/dist/types.js +0 -7
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* @fileoverview Inline credit balance badge component for topbar integration.
|
|
3
|
-
* Displays a pill-shaped badge with a coin icon and the current balance.
|
|
4
|
-
* Renders as a button when onClick is provided, otherwise as a span.
|
|
5
|
-
*/
|
|
6
|
-
import type { CreditBalanceBadgeProps } from './types.js';
|
|
1
|
+
import { CreditBalanceBadgeProps } from './types';
|
|
7
2
|
/**
|
|
8
3
|
* Renders a small inline badge showing the user's credit balance.
|
|
9
4
|
* Blue when balance > 0, red when balance is 0. Returns null when balance is null.
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* @fileoverview Credit store page component displaying the user's balance and
|
|
3
|
-
* a responsive grid of purchasable credit packages. Purely presentational --
|
|
4
|
-
* all data and callbacks are passed via props.
|
|
5
|
-
*/
|
|
6
|
-
import type { CreditStorePageProps } from './types.js';
|
|
1
|
+
import { CreditStorePageProps } from './types';
|
|
7
2
|
/**
|
|
8
3
|
* Renders a credit store with balance display, purchase packages grid,
|
|
9
4
|
* loading/error states, and a login prompt for unauthenticated users.
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* @fileoverview Purchase history page component with responsive table (desktop)
|
|
3
|
-
* and card (mobile) layouts. Supports load-more pagination.
|
|
4
|
-
*/
|
|
5
|
-
import type { PurchaseHistoryPageProps } from './types.js';
|
|
1
|
+
import { PurchaseHistoryPageProps } from './types';
|
|
6
2
|
/**
|
|
7
3
|
* Renders a paginated list of purchase records.
|
|
8
4
|
* Desktop: table with date, credits, source, and amount columns.
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* @fileoverview Usage history page component with responsive table (desktop)
|
|
3
|
-
* and card (mobile) layouts. Supports load-more pagination.
|
|
4
|
-
*/
|
|
5
|
-
import type { UsageHistoryPageProps } from './types.js';
|
|
1
|
+
import { UsageHistoryPageProps } from './types';
|
|
6
2
|
/**
|
|
7
3
|
* Renders a paginated list of usage records.
|
|
8
4
|
* Desktop: table with date, description and (optionally) credits columns.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { CreditStorePage } from './CreditStorePage
|
|
2
|
-
export { PurchaseHistoryPage } from './PurchaseHistoryPage
|
|
3
|
-
export { UsageHistoryPage } from './UsageHistoryPage
|
|
4
|
-
export { CreditBalanceBadge } from './CreditBalanceBadge
|
|
5
|
-
export type { CreditStorePageProps, CreditStorePageLabels, CreditStorePageFormatters, PurchaseHistoryPageProps, PurchaseHistoryPageLabels, PurchaseHistoryPageFormatters, UsageHistoryPageProps, UsageHistoryPageLabels, UsageHistoryPageFormatters, CreditBalanceBadgeProps, } from './types
|
|
1
|
+
export { CreditStorePage } from './CreditStorePage';
|
|
2
|
+
export { PurchaseHistoryPage } from './PurchaseHistoryPage';
|
|
3
|
+
export { UsageHistoryPage } from './UsageHistoryPage';
|
|
4
|
+
export { CreditBalanceBadge } from './CreditBalanceBadge';
|
|
5
|
+
export type { CreditStorePageProps, CreditStorePageLabels, CreditStorePageFormatters, PurchaseHistoryPageProps, PurchaseHistoryPageLabels, PurchaseHistoryPageFormatters, UsageHistoryPageProps, UsageHistoryPageLabels, UsageHistoryPageFormatters, CreditBalanceBadgeProps, } from './types';
|
|
6
6
|
export type { ConsumableSource } from '@sudobility/types';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,638 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { jsx as e, jsxs as d, Fragment as p } from "react/jsx-runtime";
|
|
2
|
+
const k = {
|
|
3
|
+
button: {
|
|
4
|
+
// Primary button - main brand actions
|
|
5
|
+
primary: {
|
|
6
|
+
base: "bg-blue-600 hover:bg-blue-700 active:bg-blue-800 text-white border-transparent",
|
|
7
|
+
dark: "dark:bg-blue-600 dark:hover:bg-blue-700 dark:active:bg-blue-800 dark:text-white",
|
|
8
|
+
focus: "focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 dark:focus-visible:ring-blue-400",
|
|
9
|
+
disabled: "disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-blue-600"
|
|
10
|
+
},
|
|
11
|
+
// Secondary button - alternative actions
|
|
12
|
+
secondary: {
|
|
13
|
+
base: "bg-gray-100 hover:bg-gray-200 active:bg-gray-300 text-gray-900 border-transparent",
|
|
14
|
+
dark: "dark:bg-gray-800 dark:hover:bg-gray-700 dark:active:bg-gray-600 dark:text-gray-50",
|
|
15
|
+
focus: "focus-visible:ring-2 focus-visible:ring-gray-500 focus-visible:ring-offset-2",
|
|
16
|
+
disabled: "disabled:opacity-50 disabled:cursor-not-allowed"
|
|
17
|
+
},
|
|
18
|
+
// Outline button - secondary emphasis
|
|
19
|
+
outline: {
|
|
20
|
+
base: "bg-transparent hover:bg-gray-50 active:bg-gray-100 text-gray-900 border-gray-300",
|
|
21
|
+
dark: "dark:bg-transparent dark:hover:bg-gray-800 dark:active:bg-gray-700 dark:text-gray-50 dark:border-gray-600",
|
|
22
|
+
focus: "focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2",
|
|
23
|
+
disabled: "disabled:opacity-50 disabled:cursor-not-allowed"
|
|
24
|
+
},
|
|
25
|
+
// Ghost button - minimal emphasis
|
|
26
|
+
ghost: {
|
|
27
|
+
base: "bg-transparent hover:bg-gray-100 active:bg-gray-200 text-gray-700 border-transparent",
|
|
28
|
+
dark: "dark:bg-transparent dark:hover:bg-gray-800 dark:active:bg-gray-700 dark:text-gray-300",
|
|
29
|
+
focus: "focus-visible:ring-2 focus-visible:ring-gray-500 focus-visible:ring-offset-2",
|
|
30
|
+
disabled: "disabled:opacity-50 disabled:cursor-not-allowed"
|
|
31
|
+
},
|
|
32
|
+
// Destructive button - dangerous actions
|
|
33
|
+
destructive: {
|
|
34
|
+
base: "bg-red-600 hover:bg-red-700 active:bg-red-800 text-white border-transparent",
|
|
35
|
+
dark: "dark:bg-red-600 dark:hover:bg-red-700 dark:active:bg-red-800 dark:text-white",
|
|
36
|
+
focus: "focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-2",
|
|
37
|
+
disabled: "disabled:opacity-50 disabled:cursor-not-allowed"
|
|
38
|
+
},
|
|
39
|
+
// Success button - positive actions
|
|
40
|
+
success: {
|
|
41
|
+
base: "bg-green-600 hover:bg-green-700 active:bg-green-800 text-white border-transparent",
|
|
42
|
+
dark: "dark:bg-green-600 dark:hover:bg-green-700 dark:active:bg-green-800 dark:text-white",
|
|
43
|
+
focus: "focus-visible:ring-2 focus-visible:ring-green-500 focus-visible:ring-offset-2",
|
|
44
|
+
disabled: "disabled:opacity-50 disabled:cursor-not-allowed"
|
|
45
|
+
},
|
|
46
|
+
// Link button - text-like appearance
|
|
47
|
+
link: {
|
|
48
|
+
base: "bg-transparent hover:bg-transparent active:bg-transparent text-blue-600 border-transparent underline-offset-4 hover:underline",
|
|
49
|
+
dark: "dark:text-blue-400",
|
|
50
|
+
focus: "focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2",
|
|
51
|
+
disabled: "disabled:opacity-50 disabled:cursor-not-allowed disabled:no-underline"
|
|
52
|
+
},
|
|
53
|
+
// Gradient variants for special emphasis
|
|
54
|
+
gradient: {
|
|
55
|
+
primary: "bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white border-transparent shadow-lg hover:shadow-xl",
|
|
56
|
+
secondary: "bg-gradient-to-r from-gray-100 to-gray-200 hover:from-gray-200 hover:to-gray-300 text-gray-900 border-transparent",
|
|
57
|
+
success: "bg-gradient-to-r from-green-500 to-emerald-600 hover:from-green-600 hover:to-emerald-700 text-white border-transparent"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
card: {
|
|
61
|
+
// Default card styling
|
|
62
|
+
default: {
|
|
63
|
+
base: "bg-white border-gray-200",
|
|
64
|
+
dark: "dark:bg-gray-800 dark:border-gray-700",
|
|
65
|
+
hover: "hover:shadow-md transition-shadow duration-200"
|
|
66
|
+
},
|
|
67
|
+
// Elevated card with shadow
|
|
68
|
+
elevated: {
|
|
69
|
+
base: "bg-white shadow-sm border-gray-200",
|
|
70
|
+
dark: "dark:bg-gray-800 dark:border-gray-700",
|
|
71
|
+
hover: "hover:shadow-lg transition-shadow duration-200"
|
|
72
|
+
},
|
|
73
|
+
// Interactive card that can be clicked
|
|
74
|
+
interactive: {
|
|
75
|
+
base: "bg-white border-gray-200 cursor-pointer",
|
|
76
|
+
dark: "dark:bg-gray-800 dark:border-gray-700",
|
|
77
|
+
hover: "hover:bg-gray-50 hover:shadow-md dark:hover:bg-gray-700 transition-all duration-200",
|
|
78
|
+
focus: "focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
|
79
|
+
},
|
|
80
|
+
// Success state card
|
|
81
|
+
success: {
|
|
82
|
+
base: "bg-green-50 border-green-200",
|
|
83
|
+
dark: "dark:bg-green-900/20 dark:border-green-800",
|
|
84
|
+
text: "text-green-800 dark:text-green-200"
|
|
85
|
+
},
|
|
86
|
+
// Warning state card
|
|
87
|
+
warning: {
|
|
88
|
+
base: "bg-orange-50 border-orange-200",
|
|
89
|
+
dark: "dark:bg-orange-900/20 dark:border-orange-800",
|
|
90
|
+
text: "text-orange-800 dark:text-orange-200"
|
|
91
|
+
},
|
|
92
|
+
// Attention state card
|
|
93
|
+
attention: {
|
|
94
|
+
base: "bg-amber-50 border-amber-200",
|
|
95
|
+
dark: "dark:bg-amber-900/20 dark:border-amber-800",
|
|
96
|
+
text: "text-amber-800 dark:text-amber-200"
|
|
97
|
+
},
|
|
98
|
+
// Error state card
|
|
99
|
+
error: {
|
|
100
|
+
base: "bg-red-50 border-red-200",
|
|
101
|
+
dark: "dark:bg-red-900/20 dark:border-red-800",
|
|
102
|
+
text: "text-red-800 dark:text-red-200"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
badge: {
|
|
106
|
+
// Default badge
|
|
107
|
+
default: {
|
|
108
|
+
base: "bg-gray-100 text-gray-800",
|
|
109
|
+
dark: "dark:bg-gray-800 dark:text-gray-300"
|
|
110
|
+
},
|
|
111
|
+
// Primary badge
|
|
112
|
+
primary: {
|
|
113
|
+
base: "bg-blue-100 text-blue-800",
|
|
114
|
+
dark: "dark:bg-blue-900/30 dark:text-blue-300"
|
|
115
|
+
},
|
|
116
|
+
// Success badge
|
|
117
|
+
success: {
|
|
118
|
+
base: "bg-green-100 text-green-800",
|
|
119
|
+
dark: "dark:bg-green-900/30 dark:text-green-300"
|
|
120
|
+
},
|
|
121
|
+
// Warning badge
|
|
122
|
+
warning: {
|
|
123
|
+
base: "bg-orange-100 text-orange-800",
|
|
124
|
+
dark: "dark:bg-orange-900/30 dark:text-orange-300"
|
|
125
|
+
},
|
|
126
|
+
// Attention badge
|
|
127
|
+
attention: {
|
|
128
|
+
base: "bg-amber-100 text-amber-800",
|
|
129
|
+
dark: "dark:bg-amber-900/30 dark:text-amber-300"
|
|
130
|
+
},
|
|
131
|
+
// Error badge
|
|
132
|
+
error: {
|
|
133
|
+
base: "bg-red-100 text-red-800",
|
|
134
|
+
dark: "dark:bg-red-900/30 dark:text-red-300"
|
|
135
|
+
},
|
|
136
|
+
// Web3 specific badges
|
|
137
|
+
ethereum: {
|
|
138
|
+
base: "bg-blue-100 text-blue-800",
|
|
139
|
+
dark: "dark:bg-blue-900/30 dark:text-blue-300"
|
|
140
|
+
},
|
|
141
|
+
solana: {
|
|
142
|
+
base: "bg-purple-100 text-purple-800",
|
|
143
|
+
dark: "dark:bg-purple-900/30 dark:text-purple-300"
|
|
144
|
+
},
|
|
145
|
+
polygon: {
|
|
146
|
+
base: "bg-purple-50 text-purple-800",
|
|
147
|
+
dark: "dark:bg-purple-900/20 dark:text-purple-300"
|
|
148
|
+
},
|
|
149
|
+
bitcoin: {
|
|
150
|
+
base: "bg-orange-100 text-orange-800",
|
|
151
|
+
dark: "dark:bg-orange-900/30 dark:text-orange-300"
|
|
152
|
+
},
|
|
153
|
+
binance: {
|
|
154
|
+
base: "bg-amber-100 text-amber-800",
|
|
155
|
+
dark: "dark:bg-amber-900/30 dark:text-amber-300"
|
|
156
|
+
},
|
|
157
|
+
cardano: {
|
|
158
|
+
base: "bg-blue-50 text-blue-900",
|
|
159
|
+
dark: "dark:bg-blue-900/20 dark:text-blue-200"
|
|
160
|
+
},
|
|
161
|
+
avalanche: {
|
|
162
|
+
base: "bg-red-100 text-red-800",
|
|
163
|
+
dark: "dark:bg-red-900/30 dark:text-red-300"
|
|
164
|
+
},
|
|
165
|
+
arbitrum: {
|
|
166
|
+
base: "bg-gray-100 text-gray-800",
|
|
167
|
+
dark: "dark:bg-gray-800/50 dark:text-gray-300"
|
|
168
|
+
},
|
|
169
|
+
optimism: {
|
|
170
|
+
base: "bg-red-50 text-red-900",
|
|
171
|
+
dark: "dark:bg-red-900/20 dark:text-red-200"
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
alert: {
|
|
175
|
+
// Info alert
|
|
176
|
+
info: {
|
|
177
|
+
base: "bg-blue-50 border-blue-200 text-blue-800",
|
|
178
|
+
dark: "dark:bg-blue-900/20 dark:border-blue-800 dark:text-blue-200",
|
|
179
|
+
icon: "text-blue-600 dark:text-blue-400"
|
|
180
|
+
},
|
|
181
|
+
// Success alert
|
|
182
|
+
success: {
|
|
183
|
+
base: "bg-green-50 border-green-200 text-green-800",
|
|
184
|
+
dark: "dark:bg-green-900/20 dark:border-green-800 dark:text-green-200",
|
|
185
|
+
icon: "text-green-600 dark:text-green-400"
|
|
186
|
+
},
|
|
187
|
+
// Warning alert
|
|
188
|
+
warning: {
|
|
189
|
+
base: "bg-orange-50 border-orange-200 text-orange-800",
|
|
190
|
+
dark: "dark:bg-orange-900/20 dark:border-orange-800 dark:text-orange-200",
|
|
191
|
+
icon: "text-orange-600 dark:text-orange-400"
|
|
192
|
+
},
|
|
193
|
+
// Attention alert
|
|
194
|
+
attention: {
|
|
195
|
+
base: "bg-amber-50 border-amber-200 text-amber-800",
|
|
196
|
+
dark: "dark:bg-amber-900/20 dark:border-amber-800 dark:text-amber-200",
|
|
197
|
+
icon: "text-amber-600 dark:text-amber-400"
|
|
198
|
+
},
|
|
199
|
+
// Error alert
|
|
200
|
+
error: {
|
|
201
|
+
base: "bg-red-50 border-red-200 text-red-800",
|
|
202
|
+
dark: "dark:bg-red-900/20 dark:border-red-800 dark:text-red-200",
|
|
203
|
+
icon: "text-red-600 dark:text-red-400"
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}, v = {
|
|
207
|
+
get button() {
|
|
208
|
+
return k.button;
|
|
209
|
+
},
|
|
210
|
+
get card() {
|
|
211
|
+
return k.card;
|
|
212
|
+
},
|
|
213
|
+
get badge() {
|
|
214
|
+
return k.badge;
|
|
215
|
+
},
|
|
216
|
+
get alert() {
|
|
217
|
+
return k.alert;
|
|
218
|
+
}
|
|
219
|
+
}, t = {
|
|
220
|
+
// Component-specific colors (use for components)
|
|
221
|
+
component: v
|
|
222
|
+
}, r = (n, l) => l, i = {
|
|
223
|
+
// Border utilities (theme-aware getter)
|
|
224
|
+
get border() {
|
|
225
|
+
return {
|
|
226
|
+
default: r("border-border", "border-gray-200 dark:border-gray-700"),
|
|
227
|
+
subtle: r("border-border/50", "border-gray-100 dark:border-gray-800"),
|
|
228
|
+
radius: "rounded-lg",
|
|
229
|
+
radiusSm: "rounded-md",
|
|
230
|
+
radiusLg: "rounded-xl",
|
|
231
|
+
radiusFull: "rounded-full"
|
|
232
|
+
};
|
|
233
|
+
},
|
|
234
|
+
// Typography utilities (theme-aware getter; legacy fallback when no theme)
|
|
235
|
+
get text() {
|
|
236
|
+
return {
|
|
237
|
+
// Headings
|
|
238
|
+
h1: `text-3xl sm:text-4xl lg:text-5xl font-bold ${r("text-foreground", "text-gray-900 dark:text-white")} leading-tight tracking-tight`,
|
|
239
|
+
h2: `text-2xl sm:text-3xl lg:text-4xl font-bold ${r("text-foreground", "text-gray-900 dark:text-white")} leading-tight tracking-tight`,
|
|
240
|
+
h3: `text-xl sm:text-2xl font-semibold ${r("text-foreground", "text-gray-900 dark:text-white")} leading-tight tracking-tight`,
|
|
241
|
+
h4: `text-lg sm:text-xl font-semibold ${r("text-foreground", "text-gray-900 dark:text-white")} leading-tight tracking-tight`,
|
|
242
|
+
h5: `text-base sm:text-lg font-semibold ${r("text-foreground", "text-gray-900 dark:text-white")} leading-tight tracking-tight`,
|
|
243
|
+
h6: `text-base font-semibold ${r("text-foreground", "text-gray-900 dark:text-white")} leading-tight tracking-tight`,
|
|
244
|
+
// Display headings
|
|
245
|
+
display: `text-4xl sm:text-5xl md:text-6xl lg:text-7xl xl:text-8xl font-extrabold ${r("text-foreground", "text-gray-900 dark:text-white")} leading-none tracking-tight`,
|
|
246
|
+
hero: `text-6xl sm:text-7xl md:text-8xl lg:text-9xl font-black ${r("text-foreground", "text-gray-900 dark:text-white")} leading-none tracking-tight`,
|
|
247
|
+
// Body text
|
|
248
|
+
body: `text-base font-normal ${r("text-foreground", "text-gray-700 dark:text-gray-300")} leading-relaxed`,
|
|
249
|
+
bodyLarge: `text-lg font-normal ${r("text-foreground", "text-gray-700 dark:text-gray-300")} leading-relaxed`,
|
|
250
|
+
bodySmall: `text-sm font-normal ${r("text-muted-foreground", "text-gray-600 dark:text-gray-400")} leading-relaxed`,
|
|
251
|
+
// Lead text (introductory paragraphs)
|
|
252
|
+
lead: `text-xl font-normal ${r("text-foreground", "text-gray-700 dark:text-gray-300")} leading-relaxed`,
|
|
253
|
+
leadLarge: `text-2xl font-normal ${r("text-foreground", "text-gray-700 dark:text-gray-300")} leading-relaxed`,
|
|
254
|
+
// Specialized text
|
|
255
|
+
caption: `text-sm font-normal ${r("text-muted-foreground", "text-gray-500 dark:text-gray-500")} leading-normal`,
|
|
256
|
+
label: `text-sm font-medium ${r("text-foreground", "text-gray-700 dark:text-gray-300")}`,
|
|
257
|
+
helper: `text-sm font-normal ${r("text-muted-foreground", "text-gray-500 dark:text-gray-500")}`,
|
|
258
|
+
// Links
|
|
259
|
+
link: `${r("text-primary hover:text-primary/80 decoration-primary", "text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 decoration-blue-600 dark:decoration-blue-400")} underline underline-offset-2 transition-colors duration-150`,
|
|
260
|
+
linkSubtle: `${r("text-primary hover:text-primary/80", "text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300")} no-underline hover:underline hover:underline-offset-2 transition-all duration-150`,
|
|
261
|
+
linkMuted: `${r("text-muted-foreground hover:text-foreground decoration-border", "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 decoration-gray-400 hover:decoration-gray-600")} underline underline-offset-2 transition-colors duration-150`,
|
|
262
|
+
// Code text
|
|
263
|
+
code: `font-mono text-sm font-medium ${r("bg-muted text-foreground", "text-gray-900 dark:text-gray-100 bg-gray-100 dark:bg-gray-800")} px-1.5 py-0.5 rounded`,
|
|
264
|
+
codeBlock: `font-mono text-sm font-normal ${r("bg-muted text-foreground", "text-gray-900 dark:text-gray-100 bg-gray-100 dark:bg-gray-800")} p-4 rounded-lg overflow-x-auto leading-relaxed`,
|
|
265
|
+
// Status text
|
|
266
|
+
success: `${r("text-success", "text-green-700 dark:text-green-300")} font-medium`,
|
|
267
|
+
warning: `${r("text-warning", "text-orange-700 dark:text-orange-300")} font-medium`,
|
|
268
|
+
attention: `${r("text-warning", "text-amber-700 dark:text-amber-300")} font-medium`,
|
|
269
|
+
error: `${r("text-destructive", "text-red-700 dark:text-red-300")} font-medium`,
|
|
270
|
+
info: `${r("text-info", "text-blue-700 dark:text-blue-300")} font-medium`,
|
|
271
|
+
// Emphasis variants
|
|
272
|
+
emphasis: `font-medium ${r("text-foreground", "text-gray-900 dark:text-gray-100")}`,
|
|
273
|
+
strong: `font-semibold ${r("text-foreground", "text-gray-900 dark:text-gray-100")}`,
|
|
274
|
+
muted: r("text-muted-foreground", "text-gray-500 dark:text-gray-500"),
|
|
275
|
+
// Uppercase labels
|
|
276
|
+
uppercase: `text-xs font-semibold ${r("text-muted-foreground", "text-gray-500 dark:text-gray-500")} uppercase tracking-wider`
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
function y() {
|
|
281
|
+
return /* @__PURE__ */ e(
|
|
282
|
+
"div",
|
|
283
|
+
{
|
|
284
|
+
className: "flex justify-center py-12",
|
|
285
|
+
role: "status",
|
|
286
|
+
"aria-label": "Loading",
|
|
287
|
+
"aria-busy": "true",
|
|
288
|
+
children: /* @__PURE__ */ e(
|
|
289
|
+
"div",
|
|
290
|
+
{
|
|
291
|
+
className: `animate-spin rounded-full h-8 w-8 border-b-2 ${t.component.alert.info.icon.replace(/text-/g, "border-")}`
|
|
292
|
+
}
|
|
293
|
+
)
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
function N({
|
|
298
|
+
isAuthenticated: n,
|
|
299
|
+
balance: l,
|
|
300
|
+
packages: g,
|
|
301
|
+
isLoading: c,
|
|
302
|
+
isPurchasing: u,
|
|
303
|
+
error: o,
|
|
304
|
+
onPurchase: x,
|
|
305
|
+
onLoginClick: f,
|
|
306
|
+
labels: b,
|
|
307
|
+
formatters: a,
|
|
308
|
+
className: h
|
|
309
|
+
}) {
|
|
310
|
+
return /* @__PURE__ */ d("div", { className: h, children: [
|
|
311
|
+
/* @__PURE__ */ e("h1", { className: "text-2xl font-bold mb-6 text-foreground", children: b.title }),
|
|
312
|
+
n && l !== null && /* @__PURE__ */ d(
|
|
313
|
+
"div",
|
|
314
|
+
{
|
|
315
|
+
className: `mb-8 p-4 rounded-lg border ${t.component.alert.info.base} ${t.component.alert.info.dark}`,
|
|
316
|
+
children: [
|
|
317
|
+
/* @__PURE__ */ e(
|
|
318
|
+
"p",
|
|
319
|
+
{
|
|
320
|
+
className: `text-sm font-medium ${t.component.alert.info.icon}`,
|
|
321
|
+
children: b.currentBalanceLabel
|
|
322
|
+
}
|
|
323
|
+
),
|
|
324
|
+
/* @__PURE__ */ e("p", { className: "text-3xl font-bold", children: a.formatCredits(l) })
|
|
325
|
+
]
|
|
326
|
+
}
|
|
327
|
+
),
|
|
328
|
+
o && /* @__PURE__ */ d(
|
|
329
|
+
"div",
|
|
330
|
+
{
|
|
331
|
+
className: `mb-6 p-4 rounded-lg border ${t.component.alert.error.base} ${t.component.alert.error.dark}`,
|
|
332
|
+
role: "alert",
|
|
333
|
+
children: [
|
|
334
|
+
/* @__PURE__ */ e("p", { className: "text-sm font-medium", children: b.errorTitle }),
|
|
335
|
+
/* @__PURE__ */ e("p", { className: `text-sm ${t.component.alert.error.icon}`, children: o })
|
|
336
|
+
]
|
|
337
|
+
}
|
|
338
|
+
),
|
|
339
|
+
!n && /* @__PURE__ */ d(
|
|
340
|
+
"div",
|
|
341
|
+
{
|
|
342
|
+
className: `mb-6 p-4 rounded-lg border ${t.component.alert.warning.base} ${t.component.alert.warning.dark}`,
|
|
343
|
+
children: [
|
|
344
|
+
/* @__PURE__ */ e("p", { className: "text-sm", children: b.loginRequired }),
|
|
345
|
+
/* @__PURE__ */ e(
|
|
346
|
+
"button",
|
|
347
|
+
{
|
|
348
|
+
onClick: f,
|
|
349
|
+
className: `mt-2 px-4 py-2 text-sm font-medium rounded-lg transition-colors ${t.component.button.primary.base} ${t.component.button.primary.dark}`,
|
|
350
|
+
children: b.loginButton ?? "Log in"
|
|
351
|
+
}
|
|
352
|
+
)
|
|
353
|
+
]
|
|
354
|
+
}
|
|
355
|
+
),
|
|
356
|
+
c && /* @__PURE__ */ e(y, {}),
|
|
357
|
+
!c && g.length === 0 && /* @__PURE__ */ e("p", { className: `${i.text.muted} text-center py-8`, children: b.noProducts }),
|
|
358
|
+
!c && g.length > 0 && /* @__PURE__ */ e("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: g.map((m) => /* @__PURE__ */ e(
|
|
359
|
+
"div",
|
|
360
|
+
{
|
|
361
|
+
className: `p-6 rounded-xl border shadow-sm hover:shadow-md transition-shadow ${t.component.card.default.base} ${t.component.card.default.dark}`,
|
|
362
|
+
children: /* @__PURE__ */ d("div", { className: "text-center", children: [
|
|
363
|
+
/* @__PURE__ */ e("p", { className: "text-3xl font-bold text-foreground", children: a.formatCredits(m.credits) }),
|
|
364
|
+
a.getPackageDescription && /* @__PURE__ */ e("p", { className: "text-sm text-muted-foreground mt-1", children: a.getPackageDescription(m.packageId) }),
|
|
365
|
+
/* @__PURE__ */ e(
|
|
366
|
+
"p",
|
|
367
|
+
{
|
|
368
|
+
className: `text-xl font-semibold mt-3 ${t.component.alert.info.icon}`,
|
|
369
|
+
children: m.priceString
|
|
370
|
+
}
|
|
371
|
+
),
|
|
372
|
+
/* @__PURE__ */ e(
|
|
373
|
+
"button",
|
|
374
|
+
{
|
|
375
|
+
onClick: () => x(m.packageId),
|
|
376
|
+
disabled: u || !n,
|
|
377
|
+
className: `mt-4 w-full px-4 py-2.5 font-medium rounded-lg disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 ${t.component.button.primary.base} ${t.component.button.primary.dark}`,
|
|
378
|
+
children: u ? b.purchasingButton : b.purchaseButton
|
|
379
|
+
}
|
|
380
|
+
)
|
|
381
|
+
] })
|
|
382
|
+
},
|
|
383
|
+
m.packageId
|
|
384
|
+
)) })
|
|
385
|
+
] });
|
|
386
|
+
}
|
|
387
|
+
function w({
|
|
388
|
+
purchases: n,
|
|
389
|
+
isLoading: l,
|
|
390
|
+
error: g,
|
|
391
|
+
onLoadMore: c,
|
|
392
|
+
hasMore: u,
|
|
393
|
+
labels: o,
|
|
394
|
+
formatters: x,
|
|
395
|
+
className: f,
|
|
396
|
+
emptyStateComponent: b
|
|
397
|
+
}) {
|
|
398
|
+
return /* @__PURE__ */ d("div", { className: f, children: [
|
|
399
|
+
/* @__PURE__ */ e("h1", { className: "text-2xl font-bold mb-6 text-foreground", children: o.title }),
|
|
400
|
+
g && /* @__PURE__ */ e(
|
|
401
|
+
"div",
|
|
402
|
+
{
|
|
403
|
+
className: `mb-4 p-3 rounded-lg border ${t.component.alert.error.base} ${t.component.alert.error.dark}`,
|
|
404
|
+
role: "alert",
|
|
405
|
+
children: /* @__PURE__ */ e("p", { className: `text-sm ${t.component.alert.error.icon}`, children: g })
|
|
406
|
+
}
|
|
407
|
+
),
|
|
408
|
+
l && /* @__PURE__ */ e(y, {}),
|
|
409
|
+
!l && n.length === 0 && /* @__PURE__ */ e(p, { children: b ?? /* @__PURE__ */ e("p", { className: `${i.text.muted} text-center py-8`, children: o.noRecords }) }),
|
|
410
|
+
!l && n.length > 0 && /* @__PURE__ */ d(p, { children: [
|
|
411
|
+
/* @__PURE__ */ e("div", { className: "hidden sm:block overflow-x-auto", children: /* @__PURE__ */ d("table", { className: "w-full text-sm", "aria-label": o.title, children: [
|
|
412
|
+
/* @__PURE__ */ e("thead", { children: /* @__PURE__ */ d("tr", { className: `border-b ${i.border.default}`, children: [
|
|
413
|
+
/* @__PURE__ */ e(
|
|
414
|
+
"th",
|
|
415
|
+
{
|
|
416
|
+
className: `text-left py-3 px-4 font-medium ${i.text.muted}`,
|
|
417
|
+
children: o.columnDate
|
|
418
|
+
}
|
|
419
|
+
),
|
|
420
|
+
/* @__PURE__ */ e(
|
|
421
|
+
"th",
|
|
422
|
+
{
|
|
423
|
+
className: `text-right py-3 px-4 font-medium ${i.text.muted}`,
|
|
424
|
+
children: o.columnCredits
|
|
425
|
+
}
|
|
426
|
+
),
|
|
427
|
+
/* @__PURE__ */ e(
|
|
428
|
+
"th",
|
|
429
|
+
{
|
|
430
|
+
className: `text-left py-3 px-4 font-medium ${i.text.muted}`,
|
|
431
|
+
children: o.columnSource
|
|
432
|
+
}
|
|
433
|
+
),
|
|
434
|
+
/* @__PURE__ */ e(
|
|
435
|
+
"th",
|
|
436
|
+
{
|
|
437
|
+
className: `text-right py-3 px-4 font-medium ${i.text.muted}`,
|
|
438
|
+
children: o.columnAmount
|
|
439
|
+
}
|
|
440
|
+
)
|
|
441
|
+
] }) }),
|
|
442
|
+
/* @__PURE__ */ e("tbody", { children: n.map((a) => /* @__PURE__ */ d(
|
|
443
|
+
"tr",
|
|
444
|
+
{
|
|
445
|
+
className: `border-b ${i.border.subtle} hover:bg-accent`,
|
|
446
|
+
children: [
|
|
447
|
+
/* @__PURE__ */ e("td", { className: "py-3 px-4 text-foreground", children: x.formatDate(a.created_at) }),
|
|
448
|
+
/* @__PURE__ */ d("td", { className: "py-3 px-4 text-right font-medium text-success", children: [
|
|
449
|
+
"+",
|
|
450
|
+
a.credits
|
|
451
|
+
] }),
|
|
452
|
+
/* @__PURE__ */ e("td", { className: "py-3 px-4 text-muted-foreground", children: x.formatSource(
|
|
453
|
+
a.source
|
|
454
|
+
) }),
|
|
455
|
+
/* @__PURE__ */ e("td", { className: "py-3 px-4 text-right text-muted-foreground", children: a.price_cents != null && a.currency ? x.formatAmount(
|
|
456
|
+
a.price_cents,
|
|
457
|
+
a.currency
|
|
458
|
+
) : "-" })
|
|
459
|
+
]
|
|
460
|
+
},
|
|
461
|
+
a.id
|
|
462
|
+
)) })
|
|
463
|
+
] }) }),
|
|
464
|
+
/* @__PURE__ */ e("div", { className: "sm:hidden space-y-3", children: n.map((a) => /* @__PURE__ */ e(
|
|
465
|
+
"div",
|
|
466
|
+
{
|
|
467
|
+
className: `p-4 rounded-lg border ${t.component.card.default.base} ${t.component.card.default.dark}`,
|
|
468
|
+
children: /* @__PURE__ */ d("div", { className: "flex justify-between items-start", children: [
|
|
469
|
+
/* @__PURE__ */ d("div", { children: [
|
|
470
|
+
/* @__PURE__ */ e("p", { className: "text-sm text-muted-foreground", children: x.formatDate(a.created_at) }),
|
|
471
|
+
/* @__PURE__ */ e("p", { className: "text-sm text-muted-foreground", children: x.formatSource(
|
|
472
|
+
a.source
|
|
473
|
+
) })
|
|
474
|
+
] }),
|
|
475
|
+
/* @__PURE__ */ d("div", { className: "text-right", children: [
|
|
476
|
+
/* @__PURE__ */ d("p", { className: "font-medium text-success", children: [
|
|
477
|
+
"+",
|
|
478
|
+
a.credits
|
|
479
|
+
] }),
|
|
480
|
+
a.price_cents != null && a.currency && /* @__PURE__ */ e("p", { className: "text-sm text-muted-foreground", children: x.formatAmount(
|
|
481
|
+
a.price_cents,
|
|
482
|
+
a.currency
|
|
483
|
+
) })
|
|
484
|
+
] })
|
|
485
|
+
] })
|
|
486
|
+
},
|
|
487
|
+
a.id
|
|
488
|
+
)) }),
|
|
489
|
+
u && c && /* @__PURE__ */ e("div", { className: "mt-4 text-center", children: /* @__PURE__ */ e(
|
|
490
|
+
"button",
|
|
491
|
+
{
|
|
492
|
+
onClick: c,
|
|
493
|
+
className: `px-4 py-2 text-sm font-medium ${i.text.link}`,
|
|
494
|
+
children: o.loadMore
|
|
495
|
+
}
|
|
496
|
+
) })
|
|
497
|
+
] })
|
|
498
|
+
] });
|
|
499
|
+
}
|
|
500
|
+
function C({
|
|
501
|
+
usages: n,
|
|
502
|
+
isLoading: l,
|
|
503
|
+
error: g,
|
|
504
|
+
onLoadMore: c,
|
|
505
|
+
hasMore: u,
|
|
506
|
+
labels: o,
|
|
507
|
+
formatters: x,
|
|
508
|
+
className: f,
|
|
509
|
+
emptyStateComponent: b
|
|
510
|
+
}) {
|
|
511
|
+
const a = (s) => s.reference || s.filename || "-", h = (s) => s.credits ?? 1, m = o.columnCredits !== void 0;
|
|
512
|
+
return /* @__PURE__ */ d("div", { className: f, children: [
|
|
513
|
+
/* @__PURE__ */ e("h1", { className: "text-2xl font-bold mb-6 text-foreground", children: o.title }),
|
|
514
|
+
g && /* @__PURE__ */ e(
|
|
515
|
+
"div",
|
|
516
|
+
{
|
|
517
|
+
className: `mb-4 p-3 rounded-lg border ${t.component.alert.error.base} ${t.component.alert.error.dark}`,
|
|
518
|
+
role: "alert",
|
|
519
|
+
children: /* @__PURE__ */ e("p", { className: `text-sm ${t.component.alert.error.icon}`, children: g })
|
|
520
|
+
}
|
|
521
|
+
),
|
|
522
|
+
l && /* @__PURE__ */ e(y, {}),
|
|
523
|
+
!l && n.length === 0 && /* @__PURE__ */ e(p, { children: b ?? /* @__PURE__ */ e("p", { className: `${i.text.muted} text-center py-8`, children: o.noRecords }) }),
|
|
524
|
+
!l && n.length > 0 && /* @__PURE__ */ d(p, { children: [
|
|
525
|
+
/* @__PURE__ */ e("div", { className: "hidden sm:block overflow-x-auto", children: /* @__PURE__ */ d("table", { className: "w-full text-sm", "aria-label": o.title, children: [
|
|
526
|
+
/* @__PURE__ */ e("thead", { children: /* @__PURE__ */ d("tr", { className: `border-b ${i.border.default}`, children: [
|
|
527
|
+
/* @__PURE__ */ e(
|
|
528
|
+
"th",
|
|
529
|
+
{
|
|
530
|
+
className: `text-left py-3 px-4 font-medium ${i.text.muted}`,
|
|
531
|
+
children: o.columnDate
|
|
532
|
+
}
|
|
533
|
+
),
|
|
534
|
+
/* @__PURE__ */ e(
|
|
535
|
+
"th",
|
|
536
|
+
{
|
|
537
|
+
className: `text-left py-3 px-4 font-medium ${i.text.muted}`,
|
|
538
|
+
children: o.columnFilename
|
|
539
|
+
}
|
|
540
|
+
),
|
|
541
|
+
m && /* @__PURE__ */ e(
|
|
542
|
+
"th",
|
|
543
|
+
{
|
|
544
|
+
className: `text-right py-3 px-4 font-medium ${i.text.muted}`,
|
|
545
|
+
children: o.columnCredits
|
|
546
|
+
}
|
|
547
|
+
)
|
|
548
|
+
] }) }),
|
|
549
|
+
/* @__PURE__ */ e("tbody", { children: n.map((s) => /* @__PURE__ */ d(
|
|
550
|
+
"tr",
|
|
551
|
+
{
|
|
552
|
+
className: `border-b ${i.border.subtle} hover:bg-accent`,
|
|
553
|
+
children: [
|
|
554
|
+
/* @__PURE__ */ e("td", { className: "py-3 px-4 text-foreground", children: x.formatDate(s.created_at) }),
|
|
555
|
+
/* @__PURE__ */ e("td", { className: "py-3 px-4 text-muted-foreground", children: a(s) }),
|
|
556
|
+
m && /* @__PURE__ */ e("td", { className: "py-3 px-4 text-right text-foreground tabular-nums", children: h(s) })
|
|
557
|
+
]
|
|
558
|
+
},
|
|
559
|
+
s.id
|
|
560
|
+
)) })
|
|
561
|
+
] }) }),
|
|
562
|
+
/* @__PURE__ */ e("div", { className: "sm:hidden space-y-3", children: n.map((s) => /* @__PURE__ */ d(
|
|
563
|
+
"div",
|
|
564
|
+
{
|
|
565
|
+
className: `p-4 rounded-lg border ${t.component.card.default.base} ${t.component.card.default.dark}`,
|
|
566
|
+
children: [
|
|
567
|
+
/* @__PURE__ */ e("p", { className: "text-sm text-muted-foreground", children: x.formatDate(s.created_at) }),
|
|
568
|
+
/* @__PURE__ */ e("p", { className: "text-sm text-foreground font-medium", children: a(s) }),
|
|
569
|
+
m && /* @__PURE__ */ d("p", { className: "text-sm text-muted-foreground", children: [
|
|
570
|
+
o.columnCredits,
|
|
571
|
+
": ",
|
|
572
|
+
h(s)
|
|
573
|
+
] })
|
|
574
|
+
]
|
|
575
|
+
},
|
|
576
|
+
s.id
|
|
577
|
+
)) }),
|
|
578
|
+
u && c && /* @__PURE__ */ e("div", { className: "mt-4 text-center", children: /* @__PURE__ */ e(
|
|
579
|
+
"button",
|
|
580
|
+
{
|
|
581
|
+
onClick: c,
|
|
582
|
+
className: `px-4 py-2 text-sm font-medium ${i.text.link}`,
|
|
583
|
+
children: o.loadMore
|
|
584
|
+
}
|
|
585
|
+
) })
|
|
586
|
+
] })
|
|
587
|
+
] });
|
|
588
|
+
}
|
|
589
|
+
function S({
|
|
590
|
+
balance: n,
|
|
591
|
+
isLoading: l,
|
|
592
|
+
onClick: g,
|
|
593
|
+
className: c
|
|
594
|
+
}) {
|
|
595
|
+
return l ? /* @__PURE__ */ e(
|
|
596
|
+
"span",
|
|
597
|
+
{
|
|
598
|
+
className: `inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium ${i.text.muted} ${c || ""}`,
|
|
599
|
+
role: "status",
|
|
600
|
+
"aria-label": "Loading balance",
|
|
601
|
+
"aria-busy": "true",
|
|
602
|
+
children: /* @__PURE__ */ e("span", { className: "animate-pulse", children: "..." })
|
|
603
|
+
}
|
|
604
|
+
) : n === null ? null : /* @__PURE__ */ d(
|
|
605
|
+
g ? "button" : "span",
|
|
606
|
+
{
|
|
607
|
+
onClick: g,
|
|
608
|
+
"aria-label": g ? `Credit balance: ${n}` : void 0,
|
|
609
|
+
className: `inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium ${n > 0 ? `${t.component.badge.primary.base} ${t.component.badge.primary.dark}` : `${t.component.badge.error.base} ${t.component.badge.error.dark}`} ${g ? "cursor-pointer hover:opacity-80" : ""} ${c || ""}`,
|
|
610
|
+
children: [
|
|
611
|
+
/* @__PURE__ */ e(
|
|
612
|
+
"svg",
|
|
613
|
+
{
|
|
614
|
+
className: "w-3.5 h-3.5",
|
|
615
|
+
fill: "currentColor",
|
|
616
|
+
viewBox: "0 0 20 20",
|
|
617
|
+
"aria-hidden": "true",
|
|
618
|
+
children: /* @__PURE__ */ e(
|
|
619
|
+
"path",
|
|
620
|
+
{
|
|
621
|
+
fillRule: "evenodd",
|
|
622
|
+
d: "M10 18a8 8 0 100-16 8 8 0 000 16zm1-13a1 1 0 10-2 0v.092a4.535 4.535 0 00-1.676.662C6.602 6.234 6 7.009 6 8c0 .99.602 1.765 1.324 2.246.48.32 1.054.545 1.676.662v1.941c-.391-.127-.68-.317-.843-.504a1 1 0 10-1.51 1.31c.562.649 1.413 1.076 2.353 1.253V15a1 1 0 102 0v-.092a4.535 4.535 0 001.676-.662C13.398 13.766 14 12.991 14 12c0-.99-.602-1.765-1.324-2.246A4.535 4.535 0 0011 9.092V7.151c.391.127.68.317.843.504a1 1 0 101.511-1.31c-.563-.649-1.413-1.076-2.354-1.253V5z",
|
|
623
|
+
clipRule: "evenodd"
|
|
624
|
+
}
|
|
625
|
+
)
|
|
626
|
+
}
|
|
627
|
+
),
|
|
628
|
+
n
|
|
629
|
+
]
|
|
630
|
+
}
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
export {
|
|
634
|
+
S as CreditBalanceBadge,
|
|
635
|
+
N as CreditStorePage,
|
|
636
|
+
w as PurchaseHistoryPage,
|
|
637
|
+
C as UsageHistoryPage
|
|
638
|
+
};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* PurchaseHistoryPage, UsageHistoryPage, and CreditBalanceBadge.
|
|
5
|
-
* All user-facing strings are defined via Labels for i18n support.
|
|
6
|
-
*/
|
|
7
|
-
import type { CreditPackage } from '@sudobility/consumables_client';
|
|
8
|
-
import type { ConsumablePurchaseRecord, ConsumableSource, ConsumableUsageRecord } from '@sudobility/types';
|
|
9
|
-
import type { ReactNode } from 'react';
|
|
1
|
+
import { CreditPackage } from '@sudobility/consumables_client';
|
|
2
|
+
import { ConsumablePurchaseRecord, ConsumableSource, ConsumableUsageRecord } from '@sudobility/types';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
10
4
|
/** Localizable label strings for the CreditStorePage component. */
|
|
11
5
|
export interface CreditStorePageLabels {
|
|
12
6
|
title: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sudobility/consumables_pages",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.43",
|
|
4
4
|
"description": "Web UI components for consumable credits (credit store, purchase history, usage history)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"CLAUDE.md"
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
|
-
"build": "tsc
|
|
20
|
+
"build": "tsc && vite build",
|
|
21
21
|
"dev": "tsc --watch",
|
|
22
22
|
"clean": "rm -rf dist",
|
|
23
23
|
"typecheck": "bunx tsc --noEmit",
|
|
@@ -30,13 +30,13 @@
|
|
|
30
30
|
"prepublishOnly": "bun run build"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@sudobility/consumables_client": "^0.0.
|
|
33
|
+
"@sudobility/consumables_client": "^0.0.21",
|
|
34
34
|
"@sudobility/types": "1.9.65",
|
|
35
35
|
"react": "^18.0.0 || ^19.0.0",
|
|
36
36
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@sudobility/consumables_client": "^0.0.
|
|
39
|
+
"@sudobility/consumables_client": "^0.0.21",
|
|
40
40
|
"@testing-library/jest-dom": "^6.9.1",
|
|
41
41
|
"@testing-library/react": "^16.3.2",
|
|
42
42
|
"@types/bun": "^1.2.8",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
47
47
|
"@typescript-eslint/parser": "^8.0.0",
|
|
48
48
|
"@vitejs/plugin-react": "^5.1.4",
|
|
49
|
+
"ajv": "^8.17.1",
|
|
49
50
|
"eslint": "^9.0.0",
|
|
50
51
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
51
52
|
"eslint-plugin-react-refresh": "^0.5.0",
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* @fileoverview Inline credit balance badge component for topbar integration.
|
|
4
|
-
* Displays a pill-shaped badge with a coin icon and the current balance.
|
|
5
|
-
* Renders as a button when onClick is provided, otherwise as a span.
|
|
6
|
-
*/
|
|
7
|
-
import { colors, ui } from '@sudobility/design';
|
|
8
|
-
/**
|
|
9
|
-
* Renders a small inline badge showing the user's credit balance.
|
|
10
|
-
* Blue when balance > 0, red when balance is 0. Returns null when balance is null.
|
|
11
|
-
* @param props - See {@link CreditBalanceBadgeProps} for full prop documentation.
|
|
12
|
-
*/
|
|
13
|
-
export function CreditBalanceBadge({ balance, isLoading, onClick, className, }) {
|
|
14
|
-
if (isLoading) {
|
|
15
|
-
return (_jsx("span", { className: `inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium ${ui.text.muted} ${className || ''}`, role: 'status', "aria-label": 'Loading balance', "aria-busy": 'true', children: _jsx("span", { className: 'animate-pulse', children: "..." }) }));
|
|
16
|
-
}
|
|
17
|
-
if (balance === null)
|
|
18
|
-
return null;
|
|
19
|
-
const Wrapper = onClick ? 'button' : 'span';
|
|
20
|
-
return (_jsxs(Wrapper, { onClick: onClick, "aria-label": onClick ? `Credit balance: ${balance}` : undefined, className: `inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium ${balance > 0
|
|
21
|
-
? `${colors.component.badge.primary.base} ${colors.component.badge.primary.dark}`
|
|
22
|
-
: `${colors.component.badge.error.base} ${colors.component.badge.error.dark}`} ${onClick ? 'cursor-pointer hover:opacity-80' : ''} ${className || ''}`, children: [_jsx("svg", { className: 'w-3.5 h-3.5', fill: 'currentColor', viewBox: '0 0 20 20', "aria-hidden": 'true', children: _jsx("path", { fillRule: 'evenodd', d: 'M10 18a8 8 0 100-16 8 8 0 000 16zm1-13a1 1 0 10-2 0v.092a4.535 4.535 0 00-1.676.662C6.602 6.234 6 7.009 6 8c0 .99.602 1.765 1.324 2.246.48.32 1.054.545 1.676.662v1.941c-.391-.127-.68-.317-.843-.504a1 1 0 10-1.51 1.31c.562.649 1.413 1.076 2.353 1.253V15a1 1 0 102 0v-.092a4.535 4.535 0 001.676-.662C13.398 13.766 14 12.991 14 12c0-.99-.602-1.765-1.324-2.246A4.535 4.535 0 0011 9.092V7.151c.391.127.68.317.843.504a1 1 0 101.511-1.31c-.563-.649-1.413-1.076-2.354-1.253V5z', clipRule: 'evenodd' }) }), balance] }));
|
|
23
|
-
}
|
package/dist/CreditStorePage.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* @fileoverview Credit store page component displaying the user's balance and
|
|
4
|
-
* a responsive grid of purchasable credit packages. Purely presentational --
|
|
5
|
-
* all data and callbacks are passed via props.
|
|
6
|
-
*/
|
|
7
|
-
import { colors, ui } from '@sudobility/design';
|
|
8
|
-
import { LoadingSpinner } from './LoadingSpinner.js';
|
|
9
|
-
/**
|
|
10
|
-
* Renders a credit store with balance display, purchase packages grid,
|
|
11
|
-
* loading/error states, and a login prompt for unauthenticated users.
|
|
12
|
-
* @param props - See {@link CreditStorePageProps} for full prop documentation.
|
|
13
|
-
*/
|
|
14
|
-
export function CreditStorePage({ isAuthenticated, balance, packages, isLoading, isPurchasing, error, onPurchase, onLoginClick, labels, formatters, className, }) {
|
|
15
|
-
return (_jsxs("div", { className: className, children: [_jsx("h1", { className: 'text-2xl font-bold mb-6 text-foreground', children: labels.title }), isAuthenticated && balance !== null && (_jsxs("div", { className: `mb-8 p-4 rounded-lg border ${colors.component.alert.info.base} ${colors.component.alert.info.dark}`, children: [_jsx("p", { className: `text-sm font-medium ${colors.component.alert.info.icon}`, children: labels.currentBalanceLabel }), _jsx("p", { className: 'text-3xl font-bold', children: formatters.formatCredits(balance) })] })), error && (_jsxs("div", { className: `mb-6 p-4 rounded-lg border ${colors.component.alert.error.base} ${colors.component.alert.error.dark}`, role: 'alert', children: [_jsx("p", { className: 'text-sm font-medium', children: labels.errorTitle }), _jsx("p", { className: `text-sm ${colors.component.alert.error.icon}`, children: error })] })), !isAuthenticated && (_jsxs("div", { className: `mb-6 p-4 rounded-lg border ${colors.component.alert.warning.base} ${colors.component.alert.warning.dark}`, children: [_jsx("p", { className: 'text-sm', children: labels.loginRequired }), _jsx("button", { onClick: onLoginClick, className: `mt-2 px-4 py-2 text-sm font-medium rounded-lg transition-colors ${colors.component.button.primary.base} ${colors.component.button.primary.dark}`, children: labels.loginButton ?? 'Log in' })] })), isLoading && _jsx(LoadingSpinner, {}), !isLoading && packages.length === 0 && (_jsx("p", { className: `${ui.text.muted} text-center py-8`, children: labels.noProducts })), !isLoading && packages.length > 0 && (_jsx("div", { className: 'grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4', children: packages.map(pkg => (_jsx("div", { className: `p-6 rounded-xl border shadow-sm hover:shadow-md transition-shadow ${colors.component.card.default.base} ${colors.component.card.default.dark}`, children: _jsxs("div", { className: 'text-center', children: [_jsx("p", { className: 'text-3xl font-bold text-foreground', children: formatters.formatCredits(pkg.credits) }), formatters.getPackageDescription && (_jsx("p", { className: 'text-sm text-muted-foreground mt-1', children: formatters.getPackageDescription(pkg.packageId) })), _jsx("p", { className: `text-xl font-semibold mt-3 ${colors.component.alert.info.icon}`, children: pkg.priceString }), _jsx("button", { onClick: () => onPurchase(pkg.packageId), disabled: isPurchasing || !isAuthenticated, className: `mt-4 w-full px-4 py-2.5 font-medium rounded-lg disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 ${colors.component.button.primary.base} ${colors.component.button.primary.dark}`, children: isPurchasing
|
|
16
|
-
? labels.purchasingButton
|
|
17
|
-
: labels.purchaseButton })] }) }, pkg.packageId))) }))] }));
|
|
18
|
-
}
|
package/dist/LoadingSpinner.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* @fileoverview Shared internal loading spinner component used across all page
|
|
4
|
-
* components. Extracted to reduce markup duplication and centralize accessibility
|
|
5
|
-
* attributes.
|
|
6
|
-
*/
|
|
7
|
-
import { colors } from '@sudobility/design';
|
|
8
|
-
/**
|
|
9
|
-
* Renders a centered spinning loading indicator with appropriate ARIA attributes.
|
|
10
|
-
* Internal component -- not exported from the package barrel.
|
|
11
|
-
*/
|
|
12
|
-
export function LoadingSpinner() {
|
|
13
|
-
return (_jsx("div", { className: 'flex justify-center py-12', role: 'status', "aria-label": 'Loading', "aria-busy": 'true', children: _jsx("div", { className: `animate-spin rounded-full h-8 w-8 border-b-2 ${colors.component.alert.info.icon.replace(/text-/g, 'border-')}` }) }));
|
|
14
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* @fileoverview Purchase history page component with responsive table (desktop)
|
|
4
|
-
* and card (mobile) layouts. Supports load-more pagination.
|
|
5
|
-
*/
|
|
6
|
-
import { colors, ui } from '@sudobility/design';
|
|
7
|
-
import { LoadingSpinner } from './LoadingSpinner.js';
|
|
8
|
-
/**
|
|
9
|
-
* Renders a paginated list of purchase records.
|
|
10
|
-
* Desktop: table with date, credits, source, and amount columns.
|
|
11
|
-
* Mobile: compact card layout.
|
|
12
|
-
* @param props - See {@link PurchaseHistoryPageProps} for full prop documentation.
|
|
13
|
-
*/
|
|
14
|
-
export function PurchaseHistoryPage({ purchases, isLoading, error, onLoadMore, hasMore, labels, formatters, className, emptyStateComponent, }) {
|
|
15
|
-
return (_jsxs("div", { className: className, children: [_jsx("h1", { className: 'text-2xl font-bold mb-6 text-foreground', children: labels.title }), error && (_jsx("div", { className: `mb-4 p-3 rounded-lg border ${colors.component.alert.error.base} ${colors.component.alert.error.dark}`, role: 'alert', children: _jsx("p", { className: `text-sm ${colors.component.alert.error.icon}`, children: error }) })), isLoading && _jsx(LoadingSpinner, {}), !isLoading && purchases.length === 0 && (_jsx(_Fragment, { children: emptyStateComponent ?? (_jsx("p", { className: `${ui.text.muted} text-center py-8`, children: labels.noRecords })) })), !isLoading && purchases.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: 'hidden sm:block overflow-x-auto', children: _jsxs("table", { className: 'w-full text-sm', "aria-label": labels.title, children: [_jsx("thead", { children: _jsxs("tr", { className: `border-b ${ui.border.default}`, children: [_jsx("th", { className: `text-left py-3 px-4 font-medium ${ui.text.muted}`, children: labels.columnDate }), _jsx("th", { className: `text-right py-3 px-4 font-medium ${ui.text.muted}`, children: labels.columnCredits }), _jsx("th", { className: `text-left py-3 px-4 font-medium ${ui.text.muted}`, children: labels.columnSource }), _jsx("th", { className: `text-right py-3 px-4 font-medium ${ui.text.muted}`, children: labels.columnAmount })] }) }), _jsx("tbody", { children: purchases.map(purchase => (_jsxs("tr", { className: `border-b ${ui.border.subtle} hover:bg-accent`, children: [_jsx("td", { className: 'py-3 px-4 text-foreground', children: formatters.formatDate(purchase.created_at) }), _jsxs("td", { className: 'py-3 px-4 text-right font-medium text-success', children: ["+", purchase.credits] }), _jsx("td", { className: 'py-3 px-4 text-muted-foreground', children: formatters.formatSource(purchase.source) }), _jsx("td", { className: 'py-3 px-4 text-right text-muted-foreground', children: purchase.price_cents != null && purchase.currency
|
|
16
|
-
? formatters.formatAmount(purchase.price_cents, purchase.currency)
|
|
17
|
-
: '-' })] }, purchase.id))) })] }) }), _jsx("div", { className: 'sm:hidden space-y-3', children: purchases.map(purchase => (_jsx("div", { className: `p-4 rounded-lg border ${colors.component.card.default.base} ${colors.component.card.default.dark}`, children: _jsxs("div", { className: 'flex justify-between items-start', children: [_jsxs("div", { children: [_jsx("p", { className: 'text-sm text-muted-foreground', children: formatters.formatDate(purchase.created_at) }), _jsx("p", { className: 'text-sm text-muted-foreground', children: formatters.formatSource(purchase.source) })] }), _jsxs("div", { className: 'text-right', children: [_jsxs("p", { className: 'font-medium text-success', children: ["+", purchase.credits] }), purchase.price_cents != null && purchase.currency && (_jsx("p", { className: 'text-sm text-muted-foreground', children: formatters.formatAmount(purchase.price_cents, purchase.currency) }))] })] }) }, purchase.id))) }), hasMore && onLoadMore && (_jsx("div", { className: 'mt-4 text-center', children: _jsx("button", { onClick: onLoadMore, className: `px-4 py-2 text-sm font-medium ${ui.text.link}`, children: labels.loadMore }) }))] }))] }));
|
|
18
|
-
}
|
package/dist/UsageHistoryPage.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* @fileoverview Usage history page component with responsive table (desktop)
|
|
4
|
-
* and card (mobile) layouts. Supports load-more pagination.
|
|
5
|
-
*/
|
|
6
|
-
import { colors, ui } from '@sudobility/design';
|
|
7
|
-
import { LoadingSpinner } from './LoadingSpinner.js';
|
|
8
|
-
/**
|
|
9
|
-
* Renders a paginated list of usage records.
|
|
10
|
-
* Desktop: table with date, description and (optionally) credits columns.
|
|
11
|
-
* Mobile: compact card layout.
|
|
12
|
-
* @param props - See {@link UsageHistoryPageProps} for full prop documentation.
|
|
13
|
-
*/
|
|
14
|
-
export function UsageHistoryPage({ usages, isLoading, error, onLoadMore, hasMore, labels, formatters, className, emptyStateComponent, }) {
|
|
15
|
-
// Whichever the product sets. A file-based product fills `filename`; one that
|
|
16
|
-
// spends credits on something else fills `reference`.
|
|
17
|
-
const describe = (usage) => usage.reference || usage.filename || '-';
|
|
18
|
-
// Absent means one, never zero: rows written before variable amounts existed
|
|
19
|
-
// spent exactly one credit.
|
|
20
|
-
const spent = (usage) => usage.credits ?? 1;
|
|
21
|
-
const showCredits = labels.columnCredits !== undefined;
|
|
22
|
-
return (_jsxs("div", { className: className, children: [_jsx("h1", { className: 'text-2xl font-bold mb-6 text-foreground', children: labels.title }), error && (_jsx("div", { className: `mb-4 p-3 rounded-lg border ${colors.component.alert.error.base} ${colors.component.alert.error.dark}`, role: 'alert', children: _jsx("p", { className: `text-sm ${colors.component.alert.error.icon}`, children: error }) })), isLoading && _jsx(LoadingSpinner, {}), !isLoading && usages.length === 0 && (_jsx(_Fragment, { children: emptyStateComponent ?? (_jsx("p", { className: `${ui.text.muted} text-center py-8`, children: labels.noRecords })) })), !isLoading && usages.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: 'hidden sm:block overflow-x-auto', children: _jsxs("table", { className: 'w-full text-sm', "aria-label": labels.title, children: [_jsx("thead", { children: _jsxs("tr", { className: `border-b ${ui.border.default}`, children: [_jsx("th", { className: `text-left py-3 px-4 font-medium ${ui.text.muted}`, children: labels.columnDate }), _jsx("th", { className: `text-left py-3 px-4 font-medium ${ui.text.muted}`, children: labels.columnFilename }), showCredits && (_jsx("th", { className: `text-right py-3 px-4 font-medium ${ui.text.muted}`, children: labels.columnCredits }))] }) }), _jsx("tbody", { children: usages.map(usage => (_jsxs("tr", { className: `border-b ${ui.border.subtle} hover:bg-accent`, children: [_jsx("td", { className: 'py-3 px-4 text-foreground', children: formatters.formatDate(usage.created_at) }), _jsx("td", { className: 'py-3 px-4 text-muted-foreground', children: describe(usage) }), showCredits && (_jsx("td", { className: 'py-3 px-4 text-right text-foreground tabular-nums', children: spent(usage) }))] }, usage.id))) })] }) }), _jsx("div", { className: 'sm:hidden space-y-3', children: usages.map(usage => (_jsxs("div", { className: `p-4 rounded-lg border ${colors.component.card.default.base} ${colors.component.card.default.dark}`, children: [_jsx("p", { className: 'text-sm text-muted-foreground', children: formatters.formatDate(usage.created_at) }), _jsx("p", { className: 'text-sm text-foreground font-medium', children: describe(usage) }), showCredits && (_jsxs("p", { className: 'text-sm text-muted-foreground', children: [labels.columnCredits, ": ", spent(usage)] }))] }, usage.id))) }), hasMore && onLoadMore && (_jsx("div", { className: 'mt-4 text-center', children: _jsx("button", { onClick: onLoadMore, className: `px-4 py-2 text-sm font-medium ${ui.text.link}`, children: labels.loadMore }) }))] }))] }));
|
|
23
|
-
}
|
package/dist/types.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Type definitions for all consumables page components.
|
|
3
|
-
* Defines Labels, Formatters, and Props interfaces for CreditStorePage,
|
|
4
|
-
* PurchaseHistoryPage, UsageHistoryPage, and CreditBalanceBadge.
|
|
5
|
-
* All user-facing strings are defined via Labels for i18n support.
|
|
6
|
-
*/
|
|
7
|
-
export {};
|