create-mercato-app 0.5.1-develop.2860.07af3a6a9d → 0.5.1-develop.2874.77704bccbd
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/package.json +1 -1
- package/template/src/app/globals.css +70 -8
- package/template/src/components/DemoFeedbackWidget.tsx +8 -8
- package/template/src/components/GlobalNoticeBars.tsx +7 -7
- package/template/src/components/StartPageContent.tsx +9 -9
- package/template/src/components/ui/button.tsx +2 -2
- package/template/src/components/ui/checkbox.tsx +1 -29
- package/template/src/components/ui/input.tsx +1 -1
- package/template/src/modules/example/backend/payments/page.tsx +1 -1
- package/template/src/modules/example/components/TodosTable.tsx +1 -1
- package/template/src/modules/example/widgets/components.ts +3 -3
- package/template/src/modules/example/widgets/dashboard/notes/widget.client.tsx +1 -1
- package/template/src/modules/example/widgets/dashboard/todos/widget.client.tsx +4 -4
- package/template/src/modules/example/widgets/dashboard/welcome/widget.client.tsx +2 -2
- package/template/src/modules/example/widgets/injection/catalog-seo-report/widget.client.tsx +4 -4
- package/template/src/modules/example/widgets/injection/crud-validation/widget.client.tsx +1 -1
- package/template/src/modules/example/widgets/injection/portal-quick-links/widget.client.tsx +3 -3
- package/template/src/modules/example/widgets/injection/portal-recent-activity/widget.client.tsx +6 -6
- package/template/src/modules/example/widgets/injection/portal-stats/widget.client.tsx +2 -2
- package/template/src/modules/example/widgets/injection/sales-todos/widget.client.tsx +3 -3
package/package.json
CHANGED
|
@@ -47,9 +47,31 @@ TODO: Fix that latter to have reference by the package names
|
|
|
47
47
|
--color-secondary-foreground: var(--secondary-foreground);
|
|
48
48
|
--color-secondary: var(--secondary);
|
|
49
49
|
--color-primary-foreground: var(--primary-foreground);
|
|
50
|
+
--color-primary-hover: var(--primary-hover);
|
|
50
51
|
--color-primary: var(--primary);
|
|
51
52
|
--color-brand-violet: var(--brand-violet);
|
|
52
53
|
--color-brand-violet-foreground: var(--brand-violet-foreground);
|
|
54
|
+
|
|
55
|
+
/* Accent indigo — used by selection controls (checkbox/radio/switch) */
|
|
56
|
+
--color-accent-indigo: var(--accent-indigo);
|
|
57
|
+
--color-accent-indigo-foreground: var(--accent-indigo-foreground);
|
|
58
|
+
|
|
59
|
+
/* Disabled control tokens */
|
|
60
|
+
--color-bg-disabled: var(--bg-disabled);
|
|
61
|
+
--color-text-disabled: var(--text-disabled);
|
|
62
|
+
--color-border-disabled: var(--border-disabled);
|
|
63
|
+
|
|
64
|
+
/* Figma focus ring shadow */
|
|
65
|
+
--shadow-focus: 0 0 0 2px var(--focus-ring-inner), 0 0 0 4px var(--focus-ring-outer);
|
|
66
|
+
|
|
67
|
+
/* Social brand colors (theme-invariant) */
|
|
68
|
+
--color-brand-apple: var(--brand-apple);
|
|
69
|
+
--color-brand-github: var(--brand-github);
|
|
70
|
+
--color-brand-x: var(--brand-x);
|
|
71
|
+
--color-brand-google-stroke: var(--brand-google-stroke);
|
|
72
|
+
--color-brand-facebook: var(--brand-facebook);
|
|
73
|
+
--color-brand-dropbox: var(--brand-dropbox);
|
|
74
|
+
--color-brand-linkedin: var(--brand-linkedin);
|
|
53
75
|
--color-popover-foreground: var(--popover-foreground);
|
|
54
76
|
--color-popover: var(--popover);
|
|
55
77
|
--color-card-foreground: var(--card-foreground);
|
|
@@ -89,14 +111,16 @@ TODO: Fix that latter to have reference by the package names
|
|
|
89
111
|
--font-size-overline: 0.6875rem;
|
|
90
112
|
--font-size-overline--line-height: 1rem;
|
|
91
113
|
|
|
92
|
-
/* ═══ Design System: Z-Index Scale ═══ */
|
|
93
|
-
--z-base: 0;
|
|
94
|
-
--z-sticky: 10;
|
|
95
|
-
--z-dropdown: 20;
|
|
96
|
-
--z-overlay: 30;
|
|
97
|
-
--z-modal: 40;
|
|
98
|
-
--z-toast: 50;
|
|
99
|
-
--z-tooltip: 60;
|
|
114
|
+
/* ═══ Design System: Z-Index Scale (Tailwind v4 namespace: z-{name} → var(--z-index-{name})) ═══ */
|
|
115
|
+
--z-index-base: 0;
|
|
116
|
+
--z-index-sticky: 10;
|
|
117
|
+
--z-index-dropdown: 20;
|
|
118
|
+
--z-index-overlay: 30;
|
|
119
|
+
--z-index-modal: 40;
|
|
120
|
+
--z-index-toast: 50;
|
|
121
|
+
--z-index-tooltip: 60;
|
|
122
|
+
--z-index-banner: 70;
|
|
123
|
+
--z-index-top: 100;
|
|
100
124
|
}
|
|
101
125
|
|
|
102
126
|
:root {
|
|
@@ -104,6 +128,17 @@ TODO: Fix that latter to have reference by the package names
|
|
|
104
128
|
--font-geist-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
105
129
|
--font-geist-mono: ui-monospace, "SFMono-Regular", "SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
|
|
106
130
|
--radius: 0.625rem;
|
|
131
|
+
/* Focus ring tokens (opt-in via .focus-ring-fancy) */
|
|
132
|
+
--focus-ring-inner: rgba(255, 255, 255, 1);
|
|
133
|
+
--focus-ring-outer: rgba(153, 160, 174, 0.16);
|
|
134
|
+
/* Social brand colors — theme-invariant */
|
|
135
|
+
--brand-apple: #000000;
|
|
136
|
+
--brand-github: #181717;
|
|
137
|
+
--brand-x: #000000;
|
|
138
|
+
--brand-google-stroke: #DADCE0;
|
|
139
|
+
--brand-facebook: #1877F2;
|
|
140
|
+
--brand-dropbox: #0061FF;
|
|
141
|
+
--brand-linkedin: #0A66C2;
|
|
107
142
|
--background: oklch(1 0 0);
|
|
108
143
|
--foreground: oklch(0.145 0 0);
|
|
109
144
|
--card: oklch(1 0 0);
|
|
@@ -114,6 +149,12 @@ TODO: Fix that latter to have reference by the package names
|
|
|
114
149
|
--primary-foreground: oklch(0.985 0 0);
|
|
115
150
|
--brand-violet: oklch(0.55 0.2 293);
|
|
116
151
|
--brand-violet-foreground: oklch(0.985 0 0);
|
|
152
|
+
--primary-hover: oklch(0.145 0 0);
|
|
153
|
+
--accent-indigo: #6366f1;
|
|
154
|
+
--accent-indigo-foreground: #ffffff;
|
|
155
|
+
--bg-disabled: #f7f7f7;
|
|
156
|
+
--text-disabled: #d1d1d1;
|
|
157
|
+
--border-disabled: #ebebeb;
|
|
117
158
|
--secondary: oklch(0.97 0 0);
|
|
118
159
|
--secondary-foreground: oklch(0.205 0 0);
|
|
119
160
|
--muted: oklch(0.97 0 0);
|
|
@@ -181,8 +222,18 @@ TODO: Fix that latter to have reference by the package names
|
|
|
181
222
|
--status-neutral-icon: oklch(0.556 0 0); /* = --muted-foreground */
|
|
182
223
|
}
|
|
183
224
|
|
|
225
|
+
/* Opt-in Figma-style focus ring: 2px inner ring + 4px outer ring */
|
|
226
|
+
.focus-ring-fancy:focus-visible {
|
|
227
|
+
outline: none;
|
|
228
|
+
box-shadow:
|
|
229
|
+
0 0 0 2px var(--focus-ring-inner),
|
|
230
|
+
0 0 0 6px var(--focus-ring-outer);
|
|
231
|
+
}
|
|
232
|
+
|
|
184
233
|
.dark {
|
|
185
234
|
color-scheme: dark;
|
|
235
|
+
--focus-ring-inner: var(--background);
|
|
236
|
+
--focus-ring-outer: rgba(255, 255, 255, 0.18);
|
|
186
237
|
--background: oklch(0.145 0 0);
|
|
187
238
|
--foreground: oklch(0.985 0 0);
|
|
188
239
|
--card: oklch(0.205 0 0);
|
|
@@ -193,6 +244,12 @@ TODO: Fix that latter to have reference by the package names
|
|
|
193
244
|
--primary-foreground: oklch(0.205 0 0);
|
|
194
245
|
--brand-violet: oklch(0.65 0.2 293);
|
|
195
246
|
--brand-violet-foreground: oklch(0.985 0 0);
|
|
247
|
+
--primary-hover: oklch(0.85 0 0);
|
|
248
|
+
--accent-indigo: #818cf8;
|
|
249
|
+
--accent-indigo-foreground: #ffffff;
|
|
250
|
+
--bg-disabled: oklch(0.25 0 0);
|
|
251
|
+
--text-disabled: oklch(0.45 0 0);
|
|
252
|
+
--border-disabled: oklch(0.30 0 0);
|
|
196
253
|
--secondary: oklch(0.269 0 0);
|
|
197
254
|
--secondary-foreground: oklch(0.985 0 0);
|
|
198
255
|
--muted: oklch(0.269 0 0);
|
|
@@ -267,6 +324,11 @@ TODO: Fix that latter to have reference by the package names
|
|
|
267
324
|
body {
|
|
268
325
|
@apply bg-background text-foreground;
|
|
269
326
|
}
|
|
327
|
+
/* Native form controls — use the DS indigo accent */
|
|
328
|
+
input[type="checkbox"],
|
|
329
|
+
input[type="radio"] {
|
|
330
|
+
accent-color: var(--accent-indigo);
|
|
331
|
+
}
|
|
270
332
|
select,
|
|
271
333
|
select option {
|
|
272
334
|
background-color: var(--background);
|
|
@@ -176,7 +176,7 @@ export function DemoFeedbackWidget({ demoModeEnabled }: { demoModeEnabled: boole
|
|
|
176
176
|
<button
|
|
177
177
|
type="button"
|
|
178
178
|
onClick={() => { setOpen(true); if (submitState === 'sent') resetForm() }}
|
|
179
|
-
className="fixed bottom-6 right-6 z-
|
|
179
|
+
className="fixed bottom-6 right-6 z-banner flex items-center gap-2 rounded-full px-5 py-3 text-sm font-semibold text-white shadow-xl transition-all hover:scale-105 hover:shadow-2xl active:scale-95 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 animate-[subtle-bounce_2s_ease-in-out_infinite]"
|
|
180
180
|
style={{
|
|
181
181
|
background: 'linear-gradient(135deg, #B4F372 0%, #EEFB63 50%, #BC9AFF 100%)',
|
|
182
182
|
color: '#1B1B1B',
|
|
@@ -209,18 +209,18 @@ export function DemoFeedbackWidget({ demoModeEnabled }: { demoModeEnabled: boole
|
|
|
209
209
|
</DialogHeader>
|
|
210
210
|
|
|
211
211
|
{submitState === 'sent' ? (
|
|
212
|
-
<div className="rounded-lg border border-
|
|
213
|
-
<p className="font-medium text-
|
|
212
|
+
<div className="rounded-lg border border-status-success-border bg-status-success-bg px-4 py-6 text-center">
|
|
213
|
+
<p className="font-medium text-status-success-text">
|
|
214
214
|
{t('demoFeedback.dialog.successTitle', 'Thank you!')}
|
|
215
215
|
</p>
|
|
216
|
-
<p className="mt-1 text-sm text-
|
|
216
|
+
<p className="mt-1 text-sm text-status-success-text">
|
|
217
217
|
{t('demoFeedback.dialog.successBody', 'We\u2019ll get back to you shortly.')}
|
|
218
218
|
</p>
|
|
219
219
|
</div>
|
|
220
220
|
) : (
|
|
221
221
|
<div className="grid gap-3">
|
|
222
222
|
{submitError && (
|
|
223
|
-
<div className="rounded-md border border-
|
|
223
|
+
<div className="rounded-md border border-status-error-border bg-status-error-bg px-3 py-2 text-sm text-status-error-text">
|
|
224
224
|
{submitError}
|
|
225
225
|
</div>
|
|
226
226
|
)}
|
|
@@ -234,9 +234,9 @@ export function DemoFeedbackWidget({ demoModeEnabled }: { demoModeEnabled: boole
|
|
|
234
234
|
onChange={(e) => setEmail(e.target.value)}
|
|
235
235
|
disabled={submitState === 'sending'}
|
|
236
236
|
aria-invalid={Boolean(fieldErrors.email)}
|
|
237
|
-
className={fieldErrors.email ? 'border-
|
|
237
|
+
className={fieldErrors.email ? 'border-status-error-border aria-invalid:ring-destructive' : undefined}
|
|
238
238
|
/>
|
|
239
|
-
{fieldErrors.email && <p className="text-xs text-
|
|
239
|
+
{fieldErrors.email && <p className="text-xs text-status-error-text">{fieldErrors.email}</p>}
|
|
240
240
|
</div>
|
|
241
241
|
|
|
242
242
|
<textarea
|
|
@@ -270,7 +270,7 @@ export function DemoFeedbackWidget({ demoModeEnabled }: { demoModeEnabled: boole
|
|
|
270
270
|
{t('demoFeedback.form.privacyLink', 'Privacy Policy')}
|
|
271
271
|
</a>
|
|
272
272
|
{fieldErrors.termsAccepted && (
|
|
273
|
-
<span className="mt-0.5 block text-
|
|
273
|
+
<span className="mt-0.5 block text-status-error-text">{fieldErrors.termsAccepted}</span>
|
|
274
274
|
)}
|
|
275
275
|
</span>
|
|
276
276
|
</label>
|
|
@@ -54,11 +54,11 @@ export function GlobalNoticeBars({ demoModeEnabled }: { demoModeEnabled: boolean
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
return (
|
|
57
|
-
<div className="pointer-events-none fixed inset-x-0 bottom-4 z-
|
|
57
|
+
<div className="pointer-events-none fixed inset-x-0 bottom-4 z-banner flex flex-col items-center gap-3 px-4">
|
|
58
58
|
{showDemoNotice ? (
|
|
59
|
-
<div className="pointer-events-auto w-full max-w-4xl rounded-lg border border-
|
|
59
|
+
<div className="pointer-events-auto w-full max-w-4xl rounded-lg border border-status-warning-border bg-status-warning-bg p-4 shadow-lg backdrop-blur">
|
|
60
60
|
<div className="flex items-start gap-3">
|
|
61
|
-
<div className="flex-1 text-sm text-
|
|
61
|
+
<div className="flex-1 text-sm text-status-warning-text space-y-1">
|
|
62
62
|
<p className="font-medium">{t('notices.demo.title', 'Demo Environment')}</p>
|
|
63
63
|
<p>
|
|
64
64
|
{t('notices.demo.description', 'This instance is provided for demo purposes only. Data may be reset at any time and is not retained for any guaranteed period.')}
|
|
@@ -69,22 +69,22 @@ export function GlobalNoticeBars({ demoModeEnabled }: { demoModeEnabled: boolean
|
|
|
69
69
|
href="https://github.com/open-mercato"
|
|
70
70
|
target="_blank"
|
|
71
71
|
rel="noreferrer"
|
|
72
|
-
className="underline font-medium hover:text-
|
|
72
|
+
className="underline font-medium hover:text-status-warning-text"
|
|
73
73
|
>
|
|
74
74
|
{t('notices.demo.installLink', 'Install Open Mercato locally')}
|
|
75
75
|
</a>
|
|
76
76
|
. {t('notices.demo.reviewLinks', 'Review our')}{' '}
|
|
77
|
-
<Link className="underline font-medium hover:text-
|
|
77
|
+
<Link className="underline font-medium hover:text-status-warning-text" href="/terms">
|
|
78
78
|
{t('common.terms')}
|
|
79
79
|
</Link>{' '}
|
|
80
80
|
{t('notices.demo.and', 'and')}{' '}
|
|
81
|
-
<Link className="underline font-medium hover:text-
|
|
81
|
+
<Link className="underline font-medium hover:text-status-warning-text" href="/privacy">
|
|
82
82
|
{t('common.privacy')}
|
|
83
83
|
</Link>
|
|
84
84
|
.
|
|
85
85
|
</p>
|
|
86
86
|
</div>
|
|
87
|
-
<Button variant="ghost" size="icon" onClick={handleDismissDemo} className="shrink-0 text-
|
|
87
|
+
<Button variant="ghost" size="icon" onClick={handleDismissDemo} className="shrink-0 text-status-warning-text">
|
|
88
88
|
<X className="size-4" />
|
|
89
89
|
</Button>
|
|
90
90
|
</div>
|
|
@@ -125,7 +125,7 @@ export function StartPageContent({ showStartPage: initialShowStartPage, showOnbo
|
|
|
125
125
|
</div>
|
|
126
126
|
</div>
|
|
127
127
|
<div className="md:ml-auto">
|
|
128
|
-
<Button asChild className="bg-emerald-600 hover:bg-emerald-700 focus-visible:ring-
|
|
128
|
+
<Button asChild className="bg-emerald-600 hover:bg-emerald-700 focus-visible:ring-ring px-6 py-5 text-base font-semibold text-white shadow-md">
|
|
129
129
|
<Link href="/onboarding">
|
|
130
130
|
{t('startPage.onboarding.cta', 'Start onboarding')}
|
|
131
131
|
<ArrowRight className="size-4" aria-hidden />
|
|
@@ -135,16 +135,16 @@ export function StartPageContent({ showStartPage: initialShowStartPage, showOnbo
|
|
|
135
135
|
</section>
|
|
136
136
|
) : null}
|
|
137
137
|
|
|
138
|
-
<section className="rounded-lg border bg-
|
|
138
|
+
<section className="rounded-lg border bg-status-info-bg border-status-info-border p-4">
|
|
139
139
|
<div className="flex items-start gap-3">
|
|
140
|
-
<Info className="size-5 text-
|
|
140
|
+
<Info className="size-5 text-status-info-icon shrink-0 mt-0.5" />
|
|
141
141
|
<div className="flex-1">
|
|
142
|
-
<h3 className="text-sm font-semibold text-
|
|
143
|
-
<p className="text-sm text-
|
|
142
|
+
<h3 className="text-sm font-semibold text-status-info-text mb-1">{t('startPage.defaultPassword.title', 'Default Password')}</h3>
|
|
143
|
+
<p className="text-sm text-status-info-text">
|
|
144
144
|
{t('startPage.defaultPassword.description1', 'The default password for all demo accounts is')}{' '}
|
|
145
|
-
<code className="px-1.5 py-0.5 rounded bg-
|
|
145
|
+
<code className="px-1.5 py-0.5 rounded bg-status-info-bg font-mono text-xs">secret</code>.
|
|
146
146
|
{' '}{t('startPage.defaultPassword.description2', 'To change passwords, use the CLI command:')}{' '}
|
|
147
|
-
<code className="px-1.5 py-0.5 rounded bg-
|
|
147
|
+
<code className="px-1.5 py-0.5 rounded bg-status-info-bg font-mono text-xs">yarn mercato auth set-password --email <email> --password <newPassword></code>
|
|
148
148
|
<span className="mt-2 block">{t('startPage.defaultPassword.description3', 'Demo account emails are printed in the terminal output during yarn initialize.')}</span>
|
|
149
149
|
</p>
|
|
150
150
|
</div>
|
|
@@ -248,7 +248,7 @@ export function StartPageContent({ showStartPage: initialShowStartPage, showOnbo
|
|
|
248
248
|
</div>
|
|
249
249
|
<p className="text-xs text-muted-foreground">
|
|
250
250
|
{t('startPage.apiResources.baseUrl', 'Current API base URL:')}{' '}
|
|
251
|
-
<code className="rounded bg-muted px-2 py-0.5 text-
|
|
251
|
+
<code className="rounded bg-muted px-2 py-0.5 text-overline text-foreground">{baseUrl}</code>
|
|
252
252
|
</p>
|
|
253
253
|
</section>
|
|
254
254
|
|
|
@@ -260,7 +260,7 @@ export function StartPageContent({ showStartPage: initialShowStartPage, showOnbo
|
|
|
260
260
|
/>
|
|
261
261
|
<label
|
|
262
262
|
htmlFor="show-start-page"
|
|
263
|
-
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-
|
|
263
|
+
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-50 cursor-pointer"
|
|
264
264
|
>
|
|
265
265
|
{t('startPage.showNextTime', 'Display this start page next time')}
|
|
266
266
|
</label>
|
|
@@ -5,14 +5,14 @@ import { cva, type VariantProps } from "class-variance-authority"
|
|
|
5
5
|
import { cn } from "@open-mercato/shared/lib/utils"
|
|
6
6
|
|
|
7
7
|
const buttonVariants = cva(
|
|
8
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-
|
|
8
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
9
9
|
{
|
|
10
10
|
variants: {
|
|
11
11
|
variant: {
|
|
12
12
|
default:
|
|
13
13
|
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
14
14
|
destructive:
|
|
15
|
-
"bg-destructive text-white shadow-xs hover:bg-destructive/90
|
|
15
|
+
"bg-destructive text-white shadow-xs hover:bg-destructive/90 aria-invalid:ring-destructive dark:aria-invalid:ring-destructive dark:bg-destructive/10",
|
|
16
16
|
outline:
|
|
17
17
|
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
18
18
|
secondary:
|
|
@@ -1,29 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
|
|
3
|
-
import { Check } from "lucide-react"
|
|
4
|
-
|
|
5
|
-
import { cn } from "@open-mercato/shared/lib/utils"
|
|
6
|
-
|
|
7
|
-
const Checkbox = React.forwardRef<
|
|
8
|
-
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
|
9
|
-
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
|
|
10
|
-
>(({ className, ...props }, ref) => (
|
|
11
|
-
<CheckboxPrimitive.Root
|
|
12
|
-
ref={ref}
|
|
13
|
-
className={cn(
|
|
14
|
-
"peer size-4 shrink-0 rounded-sm border border-input bg-background shadow-xs ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary",
|
|
15
|
-
className
|
|
16
|
-
)}
|
|
17
|
-
{...props}
|
|
18
|
-
>
|
|
19
|
-
<CheckboxPrimitive.Indicator
|
|
20
|
-
className={cn("flex items-center justify-center text-current")}
|
|
21
|
-
>
|
|
22
|
-
<Check className="size-3.5" />
|
|
23
|
-
</CheckboxPrimitive.Indicator>
|
|
24
|
-
</CheckboxPrimitive.Root>
|
|
25
|
-
))
|
|
26
|
-
Checkbox.displayName = CheckboxPrimitive.Root.displayName
|
|
27
|
-
|
|
28
|
-
export { Checkbox }
|
|
29
|
-
|
|
1
|
+
export { Checkbox, checkboxVariants, type CheckboxProps } from '@open-mercato/ui/primitives/checkbox'
|
|
@@ -9,7 +9,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
|
|
9
9
|
data-slot="input"
|
|
10
10
|
className={cn(
|
|
11
11
|
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
12
|
-
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-
|
|
12
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-2",
|
|
13
13
|
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
14
14
|
className
|
|
15
15
|
)}
|
|
@@ -180,7 +180,7 @@ function StripePaymentForm({
|
|
|
180
180
|
}, [clientSecret, elements, onError, onSuccess, stripe, t])
|
|
181
181
|
|
|
182
182
|
return (
|
|
183
|
-
<div className="space-y-4 rounded-lg border bg-muted/
|
|
183
|
+
<div className="space-y-4 rounded-lg border bg-muted/30 p-4">
|
|
184
184
|
<div className="space-y-1">
|
|
185
185
|
<p className="text-sm font-semibold">{t('example.payments.stripe.form.title', 'Complete Stripe payment')}</p>
|
|
186
186
|
<p className="text-sm text-muted-foreground">
|
|
@@ -72,7 +72,7 @@ function buildBaseColumns(t: (key: string, params?: Record<string, string | numb
|
|
|
72
72
|
return (
|
|
73
73
|
<span className="flex flex-wrap gap-1">
|
|
74
74
|
{vals.map((v) => (
|
|
75
|
-
<span key={v} className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs border bg-accent/
|
|
75
|
+
<span key={v} className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs border bg-accent/50">
|
|
76
76
|
{v}
|
|
77
77
|
</span>
|
|
78
78
|
))}
|
|
@@ -18,7 +18,7 @@ const alwaysEnabledComponentOverrides: ComponentOverride[] = [
|
|
|
18
18
|
React.createElement(
|
|
19
19
|
'div',
|
|
20
20
|
{
|
|
21
|
-
className: 'rounded-md border border-dotted border-border/
|
|
21
|
+
className: 'rounded-md border border-dotted border-border/70 p-2',
|
|
22
22
|
'data-testid': 'example-notes-wrapper',
|
|
23
23
|
},
|
|
24
24
|
React.createElement(Original, props as object)
|
|
@@ -39,7 +39,7 @@ const checkoutTestComponentOverrides: ComponentOverride[] = [
|
|
|
39
39
|
React.createElement(
|
|
40
40
|
'div',
|
|
41
41
|
{
|
|
42
|
-
className: 'rounded-
|
|
42
|
+
className: 'rounded-xl border border-dashed border-blue-300 bg-blue-50/40 p-3',
|
|
43
43
|
'data-testid': 'example-checkout-summary-wrapper',
|
|
44
44
|
},
|
|
45
45
|
React.createElement(Original, props as object)
|
|
@@ -57,7 +57,7 @@ const checkoutTestComponentOverrides: ComponentOverride[] = [
|
|
|
57
57
|
React.createElement(
|
|
58
58
|
'div',
|
|
59
59
|
{
|
|
60
|
-
className: 'rounded-
|
|
60
|
+
className: 'rounded-xl border border-dashed border-amber-300 bg-amber-50/40 p-3',
|
|
61
61
|
'data-testid': 'example-checkout-help-wrapper',
|
|
62
62
|
},
|
|
63
63
|
React.createElement(Original, props as object)
|
|
@@ -24,7 +24,7 @@ const NotesWidgetClient: React.FC<DashboardWidgetComponentProps<NotesSettings>>
|
|
|
24
24
|
</label>
|
|
25
25
|
<textarea
|
|
26
26
|
id="dashboard-notes"
|
|
27
|
-
className="min-h-[160px] w-full resize-y rounded-md border px-3 py-2 text-sm focus:border-
|
|
27
|
+
className="min-h-[160px] w-full resize-y rounded-md border px-3 py-2 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
28
28
|
value={value.text}
|
|
29
29
|
onChange={(event) => onSettingsChange({ text: event.target.value })}
|
|
30
30
|
placeholder={t('example.widgets.notes.settings.placeholder', 'Write quick notes you want to keep handy.')}
|
|
@@ -143,7 +143,7 @@ const TodoWidgetClient: React.FC<DashboardWidgetComponentProps<TodoSettings>> =
|
|
|
143
143
|
type="number"
|
|
144
144
|
min={1}
|
|
145
145
|
max={20}
|
|
146
|
-
className="w-24 rounded-md border px-2 py-1 text-sm focus:border-
|
|
146
|
+
className="w-24 rounded-md border px-2 py-1 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
147
147
|
value={value.pageSize}
|
|
148
148
|
onChange={(event) => onSettingsChange({ ...value, pageSize: Number(event.target.value) })}
|
|
149
149
|
/>
|
|
@@ -168,7 +168,7 @@ const TodoWidgetClient: React.FC<DashboardWidgetComponentProps<TodoSettings>> =
|
|
|
168
168
|
<div className="flex gap-2">
|
|
169
169
|
<input
|
|
170
170
|
type="text"
|
|
171
|
-
className="flex-1 rounded-md border px-3 py-2 text-sm focus:border-
|
|
171
|
+
className="flex-1 rounded-md border px-3 py-2 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
172
172
|
placeholder={t('example.widgets.todo.input.placeholder')}
|
|
173
173
|
value={draft}
|
|
174
174
|
onChange={(event) => setDraft(event.target.value)}
|
|
@@ -187,14 +187,14 @@ const TodoWidgetClient: React.FC<DashboardWidgetComponentProps<TodoSettings>> =
|
|
|
187
187
|
) : (
|
|
188
188
|
<ul className="space-y-2">
|
|
189
189
|
{items.length === 0 ? (
|
|
190
|
-
<li className="rounded-md border bg-muted/
|
|
190
|
+
<li className="rounded-md border bg-muted/50 px-3 py-6 text-sm text-muted-foreground text-center">
|
|
191
191
|
{value.showCompleted ? t('example.widgets.todo.state.empty') : t('example.widgets.todo.state.allCaughtUp')}
|
|
192
192
|
</li>
|
|
193
193
|
) : null}
|
|
194
194
|
{items.map((item) => (
|
|
195
195
|
<li
|
|
196
196
|
key={item.id}
|
|
197
|
-
className="flex items-center justify-between gap-2 rounded-md border bg-muted/
|
|
197
|
+
className="flex items-center justify-between gap-2 rounded-md border bg-muted/50 px-3 py-2 text-sm"
|
|
198
198
|
>
|
|
199
199
|
<label className="flex flex-1 items-center gap-2">
|
|
200
200
|
<input
|
|
@@ -40,7 +40,7 @@ const WelcomeWidgetClient: React.FC<DashboardWidgetComponentProps<WelcomeSetting
|
|
|
40
40
|
</label>
|
|
41
41
|
<input
|
|
42
42
|
id="welcome-headline"
|
|
43
|
-
className="w-full rounded-md border px-3 py-2 text-sm focus:border-
|
|
43
|
+
className="w-full rounded-md border px-3 py-2 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
44
44
|
value={value.headline}
|
|
45
45
|
onChange={(event) => handleChange('headline', event.target.value)}
|
|
46
46
|
placeholder={t('example.widgets.welcome.settings.headlinePlaceholder', 'Welcome back, {{user}}!')}
|
|
@@ -55,7 +55,7 @@ const WelcomeWidgetClient: React.FC<DashboardWidgetComponentProps<WelcomeSetting
|
|
|
55
55
|
</label>
|
|
56
56
|
<textarea
|
|
57
57
|
id="welcome-message"
|
|
58
|
-
className="min-h-[120px] w-full resize-y rounded-md border px-3 py-2 text-sm focus:border-
|
|
58
|
+
className="min-h-[120px] w-full resize-y rounded-md border px-3 py-2 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
59
59
|
value={value.message ?? ''}
|
|
60
60
|
onChange={(event) => handleChange('message', event.target.value)}
|
|
61
61
|
placeholder={DEFAULT_SETTINGS.message}
|
|
@@ -96,15 +96,15 @@ export default function CatalogSeoReportWidget(_props: InjectionWidgetComponentP
|
|
|
96
96
|
) : loading ? (
|
|
97
97
|
<p className="mt-2 text-xs text-muted-foreground">{t('common.loading', 'Loading…')}</p>
|
|
98
98
|
) : issues.length === 0 ? (
|
|
99
|
-
<p className="mt-2 text-xs text-
|
|
99
|
+
<p className="mt-2 text-xs text-status-success-text">{t('example.widgets.catalogSeoReport.healthy', 'All reviewed items look good!')}</p>
|
|
100
100
|
) : (
|
|
101
101
|
<ul className="mt-3 space-y-2">
|
|
102
102
|
{issues.map((issue) => (
|
|
103
|
-
<li key={issue.id} className="rounded border border-
|
|
103
|
+
<li key={issue.id} className="rounded border border-status-warning-border bg-status-warning-bg px-3 py-2">
|
|
104
104
|
<div className="flex items-center justify-between gap-3">
|
|
105
105
|
<div>
|
|
106
|
-
<div className="text-sm font-medium text-foreground
|
|
107
|
-
<div className="text-
|
|
106
|
+
<div className="text-sm font-medium text-foreground">{issue.title}</div>
|
|
107
|
+
<div className="text-overline text-status-warning-text">{issue.issue}</div>
|
|
108
108
|
</div>
|
|
109
109
|
<Button asChild size="sm" variant="outline">
|
|
110
110
|
<a href={`/backend/catalog/products/${issue.id}`} className="text-xs">
|
|
@@ -72,7 +72,7 @@ export default function ValidationWidget({ context, data, disabled }: InjectionW
|
|
|
72
72
|
<div data-testid="widget-transform-display-data" className="text-xs text-muted-foreground">transformDisplayData={print(lastTransformDisplayData)}</div>
|
|
73
73
|
<div data-testid="widget-transform-validation" className="text-xs text-muted-foreground">transformValidation={print(lastTransformValidation)}</div>
|
|
74
74
|
<div data-testid="widget-recursive-before-save" className="text-xs text-muted-foreground">recursiveBeforeSave={print(lastRecursiveAddonBeforeSave)}</div>
|
|
75
|
-
<div data-testid="widget-recursive-addon-host" className="mt-2 rounded border border-dashed border-border/
|
|
75
|
+
<div data-testid="widget-recursive-addon-host" className="mt-2 rounded border border-dashed border-border/70 bg-background/80 p-2">
|
|
76
76
|
<InjectionSpot
|
|
77
77
|
spotId="widget:example.injection.crud-validation:addon"
|
|
78
78
|
context={context}
|
|
@@ -16,12 +16,12 @@ export default function PortalQuickLinksWidget() {
|
|
|
16
16
|
href={link.href}
|
|
17
17
|
className="flex items-center gap-3 rounded-lg border p-3 transition-colors hover:bg-muted"
|
|
18
18
|
>
|
|
19
|
-
<div className="flex size-9 shrink-0 items-center justify-center rounded-lg bg-foreground text-
|
|
19
|
+
<div className="flex size-9 shrink-0 items-center justify-center rounded-lg bg-foreground text-xs font-bold text-background">
|
|
20
20
|
{link.icon}
|
|
21
21
|
</div>
|
|
22
22
|
<div className="min-w-0">
|
|
23
|
-
<p className="text-
|
|
24
|
-
<p className="text-
|
|
23
|
+
<p className="text-sm font-medium">{link.label}</p>
|
|
24
|
+
<p className="text-overline text-muted-foreground">{link.description}</p>
|
|
25
25
|
</div>
|
|
26
26
|
</a>
|
|
27
27
|
))}
|
package/template/src/modules/example/widgets/injection/portal-recent-activity/widget.client.tsx
CHANGED
|
@@ -10,11 +10,11 @@ const MOCK_ACTIVITY = [
|
|
|
10
10
|
|
|
11
11
|
function ActivityIcon({ type }: { type: string }) {
|
|
12
12
|
const colors: Record<string, string> = {
|
|
13
|
-
login: 'bg-
|
|
14
|
-
profile: 'bg-
|
|
15
|
-
order: 'bg-
|
|
13
|
+
login: 'bg-status-success-bg text-status-success-icon',
|
|
14
|
+
profile: 'bg-status-info-bg text-status-info-icon',
|
|
15
|
+
order: 'bg-status-warning-bg text-status-warning-icon',
|
|
16
16
|
download: 'bg-violet-100 text-violet-600 dark:bg-violet-900/30 dark:text-violet-400',
|
|
17
|
-
security: 'bg-
|
|
17
|
+
security: 'bg-status-error-bg text-status-error-icon',
|
|
18
18
|
}
|
|
19
19
|
return (
|
|
20
20
|
<div className={`flex size-8 shrink-0 items-center justify-center rounded-lg text-xs font-bold ${colors[type] ?? 'bg-muted text-muted-foreground'}`}>
|
|
@@ -30,8 +30,8 @@ export default function PortalRecentActivityWidget() {
|
|
|
30
30
|
<div key={item.id} className={`flex items-center gap-3 py-2.5 ${idx > 0 ? 'border-t' : ''}`}>
|
|
31
31
|
<ActivityIcon type={item.icon} />
|
|
32
32
|
<div className="min-w-0 flex-1">
|
|
33
|
-
<p className="text-
|
|
34
|
-
<p className="text-
|
|
33
|
+
<p className="text-sm font-medium">{item.action}</p>
|
|
34
|
+
<p className="text-overline text-muted-foreground">{item.time}</p>
|
|
35
35
|
</div>
|
|
36
36
|
</div>
|
|
37
37
|
))}
|
|
@@ -12,13 +12,13 @@ export default function PortalStatsWidget() {
|
|
|
12
12
|
<div className="grid grid-cols-2 gap-4">
|
|
13
13
|
{STATS.map((stat) => (
|
|
14
14
|
<div key={stat.label}>
|
|
15
|
-
<p className="text-
|
|
15
|
+
<p className="text-overline font-semibold uppercase tracking-wider text-muted-foreground/60">
|
|
16
16
|
{stat.label}
|
|
17
17
|
</p>
|
|
18
18
|
<p className={`mt-0.5 text-2xl font-bold tracking-tight ${stat.color}`}>
|
|
19
19
|
{stat.value}
|
|
20
20
|
</p>
|
|
21
|
-
<p className="mt-0.5 text-
|
|
21
|
+
<p className="mt-0.5 text-overline text-muted-foreground">{stat.trend}</p>
|
|
22
22
|
</div>
|
|
23
23
|
))}
|
|
24
24
|
</div>
|
|
@@ -148,10 +148,10 @@ export default function SalesTodosWidget({ context }: InjectionWidgetComponentPr
|
|
|
148
148
|
</Button>
|
|
149
149
|
</form>
|
|
150
150
|
{lastEvent ? (
|
|
151
|
-
<div className="flex items-center gap-2 rounded bg-
|
|
152
|
-
<span className="inline-block h-2 w-2 animate-pulse rounded-full bg-
|
|
151
|
+
<div className="flex items-center gap-2 rounded bg-status-info-bg px-3 py-1.5 text-xs text-status-info-text">
|
|
152
|
+
<span className="inline-block h-2 w-2 animate-pulse rounded-full bg-status-info-icon" />
|
|
153
153
|
SSE Event received: <code className="font-mono">{lastEvent.id}</code>
|
|
154
|
-
<span className="text-
|
|
154
|
+
<span className="text-status-info-text">
|
|
155
155
|
{new Date(lastEvent.timestamp).toLocaleTimeString()}
|
|
156
156
|
</span>
|
|
157
157
|
</div>
|