@open-mercato/core 0.6.7-develop.6785.1.1dd7cfac55 → 0.6.7-develop.6795.1.8a3f27921c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/generated/entities.ids.generated.js +1 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/modules/auth/backend/settings/page.js +14 -9
- package/dist/modules/auth/backend/settings/page.js.map +2 -2
- package/dist/modules/customers/cli.js +17 -7
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +229 -216
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
- package/dist/modules/customers/search.js +50 -29
- package/dist/modules/customers/search.js.map +2 -2
- package/dist/modules/data_sync/api/mappings/[id]/route.js +22 -9
- package/dist/modules/data_sync/api/mappings/[id]/route.js.map +2 -2
- package/dist/modules/data_sync/api/mappings/route.js +13 -4
- package/dist/modules/data_sync/api/mappings/route.js.map +2 -2
- package/dist/modules/data_sync/api/options.js +7 -2
- package/dist/modules/data_sync/api/options.js.map +2 -2
- package/dist/modules/data_sync/api/run.js +7 -2
- package/dist/modules/data_sync/api/run.js.map +2 -2
- package/dist/modules/data_sync/api/runs/[id]/cancel.js +8 -3
- package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +2 -2
- package/dist/modules/data_sync/api/runs/[id]/retry.js +7 -2
- package/dist/modules/data_sync/api/runs/[id]/retry.js.map +2 -2
- package/dist/modules/data_sync/api/runs/[id]/route.js +8 -3
- package/dist/modules/data_sync/api/runs/[id]/route.js.map +2 -2
- package/dist/modules/data_sync/api/runs.js +7 -2
- package/dist/modules/data_sync/api/runs.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/[id]/route.js +19 -6
- package/dist/modules/data_sync/api/schedules/[id]/route.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/route.js +13 -4
- package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
- package/dist/modules/data_sync/api/validate.js +9 -4
- package/dist/modules/data_sync/api/validate.js.map +2 -2
- package/dist/modules/design_system/acl.js +9 -0
- package/dist/modules/design_system/acl.js.map +7 -0
- package/dist/modules/design_system/backend/design-system/page.js +11 -0
- package/dist/modules/design_system/backend/design-system/page.js.map +7 -0
- package/dist/modules/design_system/backend/design-system/page.meta.js +15 -0
- package/dist/modules/design_system/backend/design-system/page.meta.js.map +7 -0
- package/dist/modules/design_system/gallery/components/CodeSnippet.js +52 -0
- package/dist/modules/design_system/gallery/components/CodeSnippet.js.map +7 -0
- package/dist/modules/design_system/gallery/components/EntryCard.js +63 -0
- package/dist/modules/design_system/gallery/components/EntryCard.js.map +7 -0
- package/dist/modules/design_system/gallery/components/GalleryShell.js +163 -0
- package/dist/modules/design_system/gallery/components/GalleryShell.js.map +7 -0
- package/dist/modules/design_system/gallery/components/VariantPreview.js +9 -0
- package/dist/modules/design_system/gallery/components/VariantPreview.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/banners.js +186 -0
- package/dist/modules/design_system/gallery/entries/banners.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/buttons.js +361 -0
- package/dist/modules/design_system/gallery/entries/buttons.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/charts.js +457 -0
- package/dist/modules/design_system/gallery/entries/charts.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/dates.js +306 -0
- package/dist/modules/design_system/gallery/entries/dates.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/detail.js +358 -0
- package/dist/modules/design_system/gallery/entries/detail.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/display.js +785 -0
- package/dist/modules/design_system/gallery/entries/display.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/feedback.js +658 -0
- package/dist/modules/design_system/gallery/entries/feedback.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/filters.js +505 -0
- package/dist/modules/design_system/gallery/entries/filters.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/foundations.js +453 -0
- package/dist/modules/design_system/gallery/entries/foundations.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/icons.js +140 -0
- package/dist/modules/design_system/gallery/entries/icons.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/inputs.js +1217 -0
- package/dist/modules/design_system/gallery/entries/inputs.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/messages.js +334 -0
- package/dist/modules/design_system/gallery/entries/messages.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/navigation.js +475 -0
- package/dist/modules/design_system/gallery/entries/navigation.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/notifications.js +257 -0
- package/dist/modules/design_system/gallery/entries/notifications.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/overlays.js +576 -0
- package/dist/modules/design_system/gallery/entries/overlays.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/scaffolding.js +378 -0
- package/dist/modules/design_system/gallery/entries/scaffolding.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/schedule.js +297 -0
- package/dist/modules/design_system/gallery/entries/schedule.js.map +7 -0
- package/dist/modules/design_system/gallery/registry.js +139 -0
- package/dist/modules/design_system/gallery/registry.js.map +7 -0
- package/dist/modules/design_system/gallery/types.js +1 -0
- package/dist/modules/design_system/gallery/types.js.map +7 -0
- package/dist/modules/design_system/index.js +9 -0
- package/dist/modules/design_system/index.js.map +7 -0
- package/dist/modules/design_system/setup.js +14 -0
- package/dist/modules/design_system/setup.js.map +7 -0
- package/dist/modules/inbox_ops/search.js +15 -4
- package/dist/modules/inbox_ops/search.js.map +2 -2
- package/dist/modules/integrations/api/[id]/credentials/route.js +11 -5
- package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
- package/dist/modules/integrations/api/[id]/health/route.js +6 -3
- package/dist/modules/integrations/api/[id]/health/route.js.map +2 -2
- package/dist/modules/integrations/api/[id]/route.js +6 -3
- package/dist/modules/integrations/api/[id]/route.js.map +2 -2
- package/dist/modules/integrations/api/[id]/state/route.js +6 -3
- package/dist/modules/integrations/api/[id]/state/route.js.map +2 -2
- package/dist/modules/integrations/api/[id]/version/route.js +6 -3
- package/dist/modules/integrations/api/[id]/version/route.js.map +2 -2
- package/dist/modules/integrations/api/logs/route.js +6 -3
- package/dist/modules/integrations/api/logs/route.js.map +2 -2
- package/dist/modules/integrations/api/route.js +6 -3
- package/dist/modules/integrations/api/route.js.map +2 -2
- package/dist/modules/integrations/api/umes-read.js +2 -2
- package/dist/modules/integrations/api/umes-read.js.map +2 -2
- package/dist/modules/integrations/lib/organization-scope.js +2 -9
- package/dist/modules/integrations/lib/organization-scope.js.map +2 -2
- package/dist/modules/messages/search.js +10 -5
- package/dist/modules/messages/search.js.map +2 -2
- package/dist/modules/query_index/data/entities.js +2 -1
- package/dist/modules/query_index/data/entities.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +32 -50
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/migrations/Migration20260731105052_query_index.js +17 -0
- package/dist/modules/query_index/migrations/Migration20260731105052_query_index.js.map +7 -0
- package/generated/entities.ids.generated.ts +1 -0
- package/package.json +16 -16
- package/src/modules/auth/backend/settings/page.tsx +17 -8
- package/src/modules/customers/cli.ts +17 -7
- package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +24 -13
- package/src/modules/customers/i18n/de.json +17 -0
- package/src/modules/customers/i18n/en.json +17 -0
- package/src/modules/customers/i18n/es.json +17 -0
- package/src/modules/customers/i18n/pl.json +17 -0
- package/src/modules/customers/search.ts +59 -27
- package/src/modules/data_sync/AGENTS.md +1 -0
- package/src/modules/data_sync/api/mappings/[id]/route.ts +22 -9
- package/src/modules/data_sync/api/mappings/route.ts +13 -4
- package/src/modules/data_sync/api/options.ts +7 -2
- package/src/modules/data_sync/api/run.ts +7 -2
- package/src/modules/data_sync/api/runs/[id]/cancel.ts +8 -3
- package/src/modules/data_sync/api/runs/[id]/retry.ts +7 -2
- package/src/modules/data_sync/api/runs/[id]/route.ts +8 -3
- package/src/modules/data_sync/api/runs.ts +7 -2
- package/src/modules/data_sync/api/schedules/[id]/route.ts +19 -6
- package/src/modules/data_sync/api/schedules/route.ts +13 -4
- package/src/modules/data_sync/api/validate.ts +9 -4
- package/src/modules/design_system/AGENTS.md +34 -0
- package/src/modules/design_system/acl.ts +5 -0
- package/src/modules/design_system/backend/design-system/page.meta.ts +11 -0
- package/src/modules/design_system/backend/design-system/page.tsx +14 -0
- package/src/modules/design_system/gallery/components/CodeSnippet.tsx +55 -0
- package/src/modules/design_system/gallery/components/EntryCard.tsx +95 -0
- package/src/modules/design_system/gallery/components/GalleryShell.tsx +206 -0
- package/src/modules/design_system/gallery/components/VariantPreview.tsx +15 -0
- package/src/modules/design_system/gallery/entries/banners.tsx +226 -0
- package/src/modules/design_system/gallery/entries/buttons.tsx +422 -0
- package/src/modules/design_system/gallery/entries/charts.tsx +518 -0
- package/src/modules/design_system/gallery/entries/dates.tsx +325 -0
- package/src/modules/design_system/gallery/entries/detail.tsx +403 -0
- package/src/modules/design_system/gallery/entries/display.tsx +893 -0
- package/src/modules/design_system/gallery/entries/feedback.tsx +746 -0
- package/src/modules/design_system/gallery/entries/filters.tsx +570 -0
- package/src/modules/design_system/gallery/entries/foundations.tsx +529 -0
- package/src/modules/design_system/gallery/entries/icons.tsx +168 -0
- package/src/modules/design_system/gallery/entries/inputs.tsx +1516 -0
- package/src/modules/design_system/gallery/entries/messages.tsx +339 -0
- package/src/modules/design_system/gallery/entries/navigation.tsx +573 -0
- package/src/modules/design_system/gallery/entries/notifications.tsx +285 -0
- package/src/modules/design_system/gallery/entries/overlays.tsx +677 -0
- package/src/modules/design_system/gallery/entries/scaffolding.tsx +430 -0
- package/src/modules/design_system/gallery/entries/schedule.tsx +307 -0
- package/src/modules/design_system/gallery/registry.ts +152 -0
- package/src/modules/design_system/gallery/types.ts +32 -0
- package/src/modules/design_system/i18n/.hardcoded-allowlist.json +71 -0
- package/src/modules/design_system/i18n/de.json +46 -0
- package/src/modules/design_system/i18n/en.json +46 -0
- package/src/modules/design_system/i18n/es.json +46 -0
- package/src/modules/design_system/i18n/pl.json +46 -0
- package/src/modules/design_system/index.ts +7 -0
- package/src/modules/design_system/setup.ts +12 -0
- package/src/modules/inbox_ops/i18n/de.json +3 -0
- package/src/modules/inbox_ops/i18n/en.json +3 -0
- package/src/modules/inbox_ops/i18n/es.json +3 -0
- package/src/modules/inbox_ops/i18n/pl.json +3 -0
- package/src/modules/inbox_ops/search.ts +20 -4
- package/src/modules/integrations/api/[id]/credentials/route.ts +11 -5
- package/src/modules/integrations/api/[id]/health/route.ts +6 -3
- package/src/modules/integrations/api/[id]/route.ts +6 -3
- package/src/modules/integrations/api/[id]/state/route.ts +6 -3
- package/src/modules/integrations/api/[id]/version/route.ts +6 -3
- package/src/modules/integrations/api/logs/route.ts +6 -3
- package/src/modules/integrations/api/route.ts +6 -3
- package/src/modules/integrations/api/umes-read.ts +2 -2
- package/src/modules/integrations/lib/organization-scope.ts +5 -25
- package/src/modules/messages/i18n/de.json +2 -0
- package/src/modules/messages/i18n/en.json +2 -0
- package/src/modules/messages/i18n/es.json +2 -0
- package/src/modules/messages/i18n/pl.json +2 -0
- package/src/modules/messages/search.ts +11 -5
- package/src/modules/query_index/data/entities.ts +7 -0
- package/src/modules/query_index/lib/engine.ts +40 -63
- package/src/modules/query_index/migrations/.snapshot-open-mercato.json +12 -0
- package/src/modules/query_index/migrations/Migration20260731105052_query_index.ts +35 -0
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { Circle } from 'lucide-react'
|
|
3
|
+
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
4
|
+
import type { GalleryEntry } from '../types'
|
|
5
|
+
|
|
6
|
+
// Token names are proper nouns from the codebase and are deliberately not
|
|
7
|
+
// translated. Structure mirrors the DS Figma color-system sheet (node
|
|
8
|
+
// 553:14956): Brand Colors → Color Tokens by role → State Color Tokens.
|
|
9
|
+
// Figma state names map to code tokens per the contract documented in
|
|
10
|
+
// globals.css: state/{x}/base→icon, /light→border, /lighter→bg.
|
|
11
|
+
|
|
12
|
+
const TOKENS_IMPORT = 'apps/mercato/src/app/globals.css'
|
|
13
|
+
const FIGMA_COLORS_NODE = '553:14956'
|
|
14
|
+
|
|
15
|
+
function SwatchCard({ copyText, label, children }: { copyText: string; label: string; children: React.ReactNode }) {
|
|
16
|
+
const onCopy = React.useCallback(async () => {
|
|
17
|
+
try {
|
|
18
|
+
await navigator.clipboard.writeText(copyText)
|
|
19
|
+
flash(`${copyText} copied`, 'success')
|
|
20
|
+
} catch {
|
|
21
|
+
flash('Could not copy the token', 'error')
|
|
22
|
+
}
|
|
23
|
+
}, [copyText])
|
|
24
|
+
return (
|
|
25
|
+
<button
|
|
26
|
+
type="button"
|
|
27
|
+
onClick={onCopy}
|
|
28
|
+
className="flex w-36 flex-col items-start gap-1 rounded-md border border-border bg-background p-2 text-left transition-colors hover:bg-muted/40 focus-visible:outline-none focus-visible:shadow-focus"
|
|
29
|
+
title={`Copy ${copyText}`}
|
|
30
|
+
>
|
|
31
|
+
{children}
|
|
32
|
+
<code className="break-all text-[11px] leading-tight text-muted-foreground">{label}</code>
|
|
33
|
+
</button>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function TokenSwatch({ tokenClass, label }: { tokenClass: string; label: string }) {
|
|
38
|
+
return (
|
|
39
|
+
<SwatchCard copyText={label} label={label}>
|
|
40
|
+
<span aria-hidden className={`h-10 w-full rounded-sm border border-border ${tokenClass}`} />
|
|
41
|
+
</SwatchCard>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// A text-color token shown in its actual role — as type, not as a fill.
|
|
46
|
+
function TextSwatch({ textClass, label }: { textClass: string; label: string }) {
|
|
47
|
+
return (
|
|
48
|
+
<SwatchCard copyText={textClass} label={label}>
|
|
49
|
+
<span aria-hidden className="flex h-10 w-full items-center justify-center rounded-sm border border-border bg-background">
|
|
50
|
+
<span className={`text-xl font-semibold leading-none ${textClass}`}>Aa</span>
|
|
51
|
+
</span>
|
|
52
|
+
</SwatchCard>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// A border-color token shown as a 2px outline on the neutral surface.
|
|
57
|
+
function BorderSwatch({ borderClass, label }: { borderClass: string; label: string }) {
|
|
58
|
+
return (
|
|
59
|
+
<SwatchCard copyText={borderClass} label={label}>
|
|
60
|
+
<span aria-hidden className={`h-10 w-full rounded-sm border-2 bg-background ${borderClass}`} />
|
|
61
|
+
</SwatchCard>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// An icon-color token shown on a real glyph.
|
|
66
|
+
function IconSwatch({ iconClass, label }: { iconClass: string; label: string }) {
|
|
67
|
+
return (
|
|
68
|
+
<SwatchCard copyText={iconClass} label={label}>
|
|
69
|
+
<span aria-hidden className="flex h-10 w-full items-center justify-center rounded-sm border border-border bg-background">
|
|
70
|
+
<Circle className={`size-4 fill-current ${iconClass}`} />
|
|
71
|
+
</span>
|
|
72
|
+
</SwatchCard>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function SwatchRow({ items }: { items: Array<{ tokenClass: string; label: string }> }) {
|
|
77
|
+
return (
|
|
78
|
+
<div className="flex flex-wrap gap-2">
|
|
79
|
+
{items.map((item) => (
|
|
80
|
+
<TokenSwatch key={item.label} tokenClass={item.tokenClass} label={item.label} />
|
|
81
|
+
))}
|
|
82
|
+
</div>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const brandColorsEntry: GalleryEntry = {
|
|
87
|
+
id: 'brand-colors',
|
|
88
|
+
title: 'Brand colors',
|
|
89
|
+
importPath: TOKENS_IMPORT,
|
|
90
|
+
usage: {
|
|
91
|
+
do: ['brand-violet 10/30/100 pattern (bg/border/text) for proposed and feature accents.'],
|
|
92
|
+
dont: ['Never theme or repurpose accent-indigo — it is the selection-control contract.'],
|
|
93
|
+
},
|
|
94
|
+
figmaNodeId: FIGMA_COLORS_NODE,
|
|
95
|
+
variants: [
|
|
96
|
+
{
|
|
97
|
+
id: 'gradient',
|
|
98
|
+
title: 'gradient 135°',
|
|
99
|
+
render: () => (
|
|
100
|
+
<div className="space-y-2">
|
|
101
|
+
<div
|
|
102
|
+
aria-hidden
|
|
103
|
+
className="h-16 w-full max-w-md rounded-md border border-border bg-linear-135 from-brand-lime from-0% via-brand-yellow via-35% to-brand-violet to-70%"
|
|
104
|
+
/>
|
|
105
|
+
<code className="text-xs text-muted-foreground">brand-lime 0%, brand-yellow 35%, brand-violet 70%</code>
|
|
106
|
+
</div>
|
|
107
|
+
),
|
|
108
|
+
code: `<div className="bg-linear-135 from-brand-lime from-0% via-brand-yellow via-35% to-brand-violet to-70%" />`,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 'identity',
|
|
112
|
+
title: 'identity',
|
|
113
|
+
render: () => (
|
|
114
|
+
<SwatchRow
|
|
115
|
+
items={[
|
|
116
|
+
{ tokenClass: 'bg-brand-lime', label: 'brand-lime' },
|
|
117
|
+
{ tokenClass: 'bg-brand-yellow', label: 'brand-yellow' },
|
|
118
|
+
{ tokenClass: 'bg-brand-violet', label: 'brand-violet' },
|
|
119
|
+
{ tokenClass: 'bg-brand-violet-foreground', label: 'brand-violet-foreground' },
|
|
120
|
+
{ tokenClass: 'bg-accent-indigo', label: 'accent-indigo' },
|
|
121
|
+
]}
|
|
122
|
+
/>
|
|
123
|
+
),
|
|
124
|
+
code: `<span className="bg-brand-violet/10 border-brand-violet/30 text-brand-violet" />`,
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: 'social',
|
|
128
|
+
title: 'social',
|
|
129
|
+
render: () => (
|
|
130
|
+
<SwatchRow
|
|
131
|
+
items={[
|
|
132
|
+
{ tokenClass: 'bg-brand-apple', label: 'brand-apple' },
|
|
133
|
+
{ tokenClass: 'bg-brand-github', label: 'brand-github' },
|
|
134
|
+
{ tokenClass: 'bg-brand-facebook', label: 'brand-facebook' },
|
|
135
|
+
{ tokenClass: 'bg-brand-dropbox', label: 'brand-dropbox' },
|
|
136
|
+
{ tokenClass: 'bg-brand-linkedin', label: 'brand-linkedin' },
|
|
137
|
+
{ tokenClass: 'bg-brand-x', label: 'brand-x' },
|
|
138
|
+
]}
|
|
139
|
+
/>
|
|
140
|
+
),
|
|
141
|
+
code: `<SocialButton provider="github" />`,
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const colorTokensEntry: GalleryEntry = {
|
|
147
|
+
id: 'color-tokens',
|
|
148
|
+
title: 'Color tokens',
|
|
149
|
+
importPath: TOKENS_IMPORT,
|
|
150
|
+
usage: {
|
|
151
|
+
do: ['Pair every surface with its -foreground counterpart.', 'Borders come from border-border / border-input — nothing else.'],
|
|
152
|
+
dont: ['Never border-gray-* or any raw palette shade.'],
|
|
153
|
+
},
|
|
154
|
+
figmaNodeId: FIGMA_COLORS_NODE,
|
|
155
|
+
variants: [
|
|
156
|
+
{
|
|
157
|
+
id: 'primary',
|
|
158
|
+
title: 'primary',
|
|
159
|
+
render: () => (
|
|
160
|
+
<SwatchRow
|
|
161
|
+
items={[
|
|
162
|
+
{ tokenClass: 'bg-primary', label: 'primary' },
|
|
163
|
+
{ tokenClass: 'bg-primary-foreground', label: 'primary-foreground' },
|
|
164
|
+
{ tokenClass: 'bg-primary-hover', label: 'primary-hover' },
|
|
165
|
+
{ tokenClass: 'bg-destructive', label: 'destructive' },
|
|
166
|
+
]}
|
|
167
|
+
/>
|
|
168
|
+
),
|
|
169
|
+
code: `<div className="bg-primary text-primary-foreground hover:bg-primary-hover" />`,
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
id: 'background',
|
|
173
|
+
title: 'background (bg)',
|
|
174
|
+
render: () => (
|
|
175
|
+
<SwatchRow
|
|
176
|
+
items={[
|
|
177
|
+
{ tokenClass: 'bg-background', label: 'background' },
|
|
178
|
+
{ tokenClass: 'bg-card', label: 'card' },
|
|
179
|
+
{ tokenClass: 'bg-popover', label: 'popover' },
|
|
180
|
+
{ tokenClass: 'bg-muted', label: 'muted' },
|
|
181
|
+
{ tokenClass: 'bg-accent', label: 'accent' },
|
|
182
|
+
{ tokenClass: 'bg-sidebar', label: 'sidebar' },
|
|
183
|
+
{ tokenClass: 'bg-bg-disabled', label: 'bg-disabled' },
|
|
184
|
+
]}
|
|
185
|
+
/>
|
|
186
|
+
),
|
|
187
|
+
code: `<div className="bg-card text-card-foreground" />`,
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
id: 'text',
|
|
191
|
+
title: 'text',
|
|
192
|
+
render: () => (
|
|
193
|
+
<div className="flex flex-wrap gap-2">
|
|
194
|
+
<TextSwatch textClass="text-foreground" label="text-foreground" />
|
|
195
|
+
<TextSwatch textClass="text-muted-foreground" label="text-muted-foreground" />
|
|
196
|
+
<TextSwatch textClass="text-card-foreground" label="text-card-foreground" />
|
|
197
|
+
<TextSwatch textClass="text-accent-foreground" label="text-accent-foreground" />
|
|
198
|
+
<TextSwatch textClass="text-text-disabled" label="text-text-disabled" />
|
|
199
|
+
</div>
|
|
200
|
+
),
|
|
201
|
+
code: `<p className="text-muted-foreground">Secondary copy</p>`,
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: 'stroke',
|
|
205
|
+
title: 'stroke',
|
|
206
|
+
render: () => (
|
|
207
|
+
<div className="flex flex-wrap gap-2">
|
|
208
|
+
<BorderSwatch borderClass="border-border" label="border-border" />
|
|
209
|
+
<BorderSwatch borderClass="border-input" label="border-input" />
|
|
210
|
+
<BorderSwatch borderClass="border-ring" label="border-ring" />
|
|
211
|
+
<BorderSwatch borderClass="border-border-disabled" label="border-border-disabled" />
|
|
212
|
+
</div>
|
|
213
|
+
),
|
|
214
|
+
code: `<div className="border-border focus-visible:ring-ring" />`,
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Literal class strings on purpose: the Tailwind scanner only sees complete
|
|
220
|
+
// literals, so `bg-status-${x}` variants would silently never be generated.
|
|
221
|
+
type StatusFamily = {
|
|
222
|
+
figma: string
|
|
223
|
+
status: string
|
|
224
|
+
chipLabel: string
|
|
225
|
+
bg: string
|
|
226
|
+
text: string
|
|
227
|
+
border: string
|
|
228
|
+
icon: string
|
|
229
|
+
dot: string
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const FIGMA_STATE_TO_CODE: StatusFamily[] = [
|
|
233
|
+
{ figma: 'Faded', status: 'neutral', chipLabel: 'Neutral', bg: 'bg-status-neutral-bg', text: 'text-status-neutral-text', border: 'border-status-neutral-border', icon: 'text-status-neutral-icon', dot: 'bg-status-neutral-icon' },
|
|
234
|
+
{ figma: 'Information', status: 'info', chipLabel: 'Info', bg: 'bg-status-info-bg', text: 'text-status-info-text', border: 'border-status-info-border', icon: 'text-status-info-icon', dot: 'bg-status-info-icon' },
|
|
235
|
+
{ figma: 'Warning', status: 'warning', chipLabel: 'Warning', bg: 'bg-status-warning-bg', text: 'text-status-warning-text', border: 'border-status-warning-border', icon: 'text-status-warning-icon', dot: 'bg-status-warning-icon' },
|
|
236
|
+
{ figma: 'Error', status: 'error', chipLabel: 'Error', bg: 'bg-status-error-bg', text: 'text-status-error-text', border: 'border-status-error-border', icon: 'text-status-error-icon', dot: 'bg-status-error-icon' },
|
|
237
|
+
{ figma: 'Success', status: 'success', chipLabel: 'Success', bg: 'bg-status-success-bg', text: 'text-status-success-text', border: 'border-status-success-border', icon: 'text-status-success-icon', dot: 'bg-status-success-icon' },
|
|
238
|
+
{ figma: 'Highlighted', status: 'pink', chipLabel: 'Highlighted', bg: 'bg-status-pink-bg', text: 'text-status-pink-text', border: 'border-status-pink-border', icon: 'text-status-pink-icon', dot: 'bg-status-pink-icon' },
|
|
239
|
+
]
|
|
240
|
+
|
|
241
|
+
// One status family: the composed chip first (how the roles work together),
|
|
242
|
+
// then each token presented in its actual role.
|
|
243
|
+
function StatusFamilyPreview({ family }: { family: StatusFamily }) {
|
|
244
|
+
return (
|
|
245
|
+
<div className="space-y-3">
|
|
246
|
+
<span
|
|
247
|
+
className={`inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-sm font-medium ${family.bg} ${family.text} ${family.border}`}
|
|
248
|
+
>
|
|
249
|
+
<span aria-hidden className={`size-2 rounded-full ${family.dot}`} />
|
|
250
|
+
{family.chipLabel}
|
|
251
|
+
</span>
|
|
252
|
+
<div className="flex flex-wrap gap-2">
|
|
253
|
+
<TokenSwatch tokenClass={family.bg} label={family.bg} />
|
|
254
|
+
<TextSwatch textClass={family.text} label={family.text} />
|
|
255
|
+
<BorderSwatch borderClass={family.border} label={family.border} />
|
|
256
|
+
<IconSwatch iconClass={family.icon} label={family.icon} />
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const stateTokensEntry: GalleryEntry = {
|
|
263
|
+
id: 'state-tokens',
|
|
264
|
+
title: 'State color tokens',
|
|
265
|
+
importPath: TOKENS_IMPORT,
|
|
266
|
+
usage: {
|
|
267
|
+
do: [
|
|
268
|
+
'Pair -bg with -text of the same family — the shades are contrast-tested together.',
|
|
269
|
+
'-icon for glyphs and dots, -border for outlines; both handle dark mode themselves.',
|
|
270
|
+
],
|
|
271
|
+
dont: [
|
|
272
|
+
'Never hardcode Tailwind status colors (text-red-*, bg-green-*, text-amber-*).',
|
|
273
|
+
'No dark: overrides on status tokens — they already theme.',
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
figmaNodeId: FIGMA_COLORS_NODE,
|
|
277
|
+
variants: [
|
|
278
|
+
...FIGMA_STATE_TO_CODE.map((family) => ({
|
|
279
|
+
id: family.status,
|
|
280
|
+
title: `${family.figma} → status-${family.status}`,
|
|
281
|
+
render: () => <StatusFamilyPreview family={family} />,
|
|
282
|
+
code: `<span className="${family.bg} ${family.text} ${family.border}" />`,
|
|
283
|
+
})),
|
|
284
|
+
{
|
|
285
|
+
id: 'feature',
|
|
286
|
+
title: 'Feature → brand-violet pattern',
|
|
287
|
+
render: () => (
|
|
288
|
+
<div className="flex max-w-md items-center gap-2 rounded-md border border-brand-violet/30 bg-brand-violet/10 p-3 text-sm text-brand-violet">
|
|
289
|
+
Feature state uses the brand-violet 10/30/100 pattern, not a status family.
|
|
290
|
+
</div>
|
|
291
|
+
),
|
|
292
|
+
code: `<Alert status="feature" />`,
|
|
293
|
+
},
|
|
294
|
+
],
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const chartPaletteEntry: GalleryEntry = {
|
|
298
|
+
id: 'chart-palette',
|
|
299
|
+
title: 'Chart palette',
|
|
300
|
+
importPath: TOKENS_IMPORT,
|
|
301
|
+
usage: {
|
|
302
|
+
dont: [
|
|
303
|
+
'Never build token class names dynamically (`bg-chart-${n}`) — the Tailwind scanner only sees complete literals, so the class is silently never generated.',
|
|
304
|
+
],
|
|
305
|
+
},
|
|
306
|
+
variants: [
|
|
307
|
+
{
|
|
308
|
+
id: 'numbered',
|
|
309
|
+
title: 'numbered',
|
|
310
|
+
render: () => (
|
|
311
|
+
<SwatchRow
|
|
312
|
+
items={[
|
|
313
|
+
{ tokenClass: 'bg-chart-1', label: 'chart-1' },
|
|
314
|
+
{ tokenClass: 'bg-chart-2', label: 'chart-2' },
|
|
315
|
+
{ tokenClass: 'bg-chart-3', label: 'chart-3' },
|
|
316
|
+
{ tokenClass: 'bg-chart-4', label: 'chart-4' },
|
|
317
|
+
{ tokenClass: 'bg-chart-5', label: 'chart-5' },
|
|
318
|
+
]}
|
|
319
|
+
/>
|
|
320
|
+
),
|
|
321
|
+
code: `<BarChart data={data} />`,
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
id: 'named',
|
|
325
|
+
title: 'named',
|
|
326
|
+
render: () => (
|
|
327
|
+
<SwatchRow
|
|
328
|
+
items={[
|
|
329
|
+
{ tokenClass: 'bg-chart-blue', label: 'chart-blue' },
|
|
330
|
+
{ tokenClass: 'bg-chart-emerald', label: 'chart-emerald' },
|
|
331
|
+
{ tokenClass: 'bg-chart-amber', label: 'chart-amber' },
|
|
332
|
+
{ tokenClass: 'bg-chart-rose', label: 'chart-rose' },
|
|
333
|
+
{ tokenClass: 'bg-chart-violet', label: 'chart-violet' },
|
|
334
|
+
{ tokenClass: 'bg-chart-cyan', label: 'chart-cyan' },
|
|
335
|
+
{ tokenClass: 'bg-chart-indigo', label: 'chart-indigo' },
|
|
336
|
+
{ tokenClass: 'bg-chart-pink', label: 'chart-pink' },
|
|
337
|
+
{ tokenClass: 'bg-chart-teal', label: 'chart-teal' },
|
|
338
|
+
{ tokenClass: 'bg-chart-orange', label: 'chart-orange' },
|
|
339
|
+
]}
|
|
340
|
+
/>
|
|
341
|
+
),
|
|
342
|
+
code: `<Sparkline className="text-chart-blue" data={points} />`,
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
type ColorRole = {
|
|
348
|
+
surface: string
|
|
349
|
+
onSurface: string
|
|
350
|
+
surfaceCls: string
|
|
351
|
+
onSurfaceCls: string
|
|
352
|
+
borderCls?: string
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function RoleCard({ role }: { role: ColorRole }) {
|
|
356
|
+
const label = `${role.surface} / ${role.onSurface}`
|
|
357
|
+
const onCopy = React.useCallback(async () => {
|
|
358
|
+
try {
|
|
359
|
+
await navigator.clipboard.writeText(`${role.surfaceCls} ${role.onSurfaceCls}`)
|
|
360
|
+
flash(`${role.surfaceCls} ${role.onSurfaceCls} copied`, 'success')
|
|
361
|
+
} catch {
|
|
362
|
+
flash('Could not copy the classes', 'error')
|
|
363
|
+
}
|
|
364
|
+
}, [role])
|
|
365
|
+
return (
|
|
366
|
+
<button
|
|
367
|
+
type="button"
|
|
368
|
+
onClick={onCopy}
|
|
369
|
+
title={`Copy ${role.surfaceCls} ${role.onSurfaceCls}`}
|
|
370
|
+
className={`flex h-24 w-full flex-col justify-between rounded-md border p-3 text-left transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:shadow-focus ${role.surfaceCls} ${role.onSurfaceCls} ${role.borderCls ?? 'border-border'}`}
|
|
371
|
+
>
|
|
372
|
+
<span className="text-sm font-medium leading-tight">{role.surface}</span>
|
|
373
|
+
<code className="text-xs opacity-80">{role.onSurface}</code>
|
|
374
|
+
</button>
|
|
375
|
+
)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function RoleGrid({ roles }: { roles: ColorRole[] }) {
|
|
379
|
+
return (
|
|
380
|
+
<div className="grid w-full gap-2 sm:grid-cols-2 lg:grid-cols-3">
|
|
381
|
+
{roles.map((role) => (
|
|
382
|
+
<RoleCard key={role.surface + role.onSurface} role={role} />
|
|
383
|
+
))}
|
|
384
|
+
</div>
|
|
385
|
+
)
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const colorRolesEntry: GalleryEntry = {
|
|
389
|
+
id: 'color-roles',
|
|
390
|
+
title: 'Color roles',
|
|
391
|
+
importPath: TOKENS_IMPORT,
|
|
392
|
+
figmaNodeId: FIGMA_COLORS_NODE,
|
|
393
|
+
keywords: ['roles', 'pairs', 'on-color', 'material'],
|
|
394
|
+
usage: {
|
|
395
|
+
do: [
|
|
396
|
+
'A role is a surface paired with its content color — always use them together, never mix pairs.',
|
|
397
|
+
'Click a card to copy both classes of the pair.',
|
|
398
|
+
],
|
|
399
|
+
dont: [
|
|
400
|
+
'Never put foreground on a surface from a different pair — contrast is only tested within a pair.',
|
|
401
|
+
'Never use a -foreground token as a standalone accent color.',
|
|
402
|
+
],
|
|
403
|
+
},
|
|
404
|
+
variants: [
|
|
405
|
+
{
|
|
406
|
+
id: 'action',
|
|
407
|
+
title: 'action',
|
|
408
|
+
render: () => (
|
|
409
|
+
<RoleGrid
|
|
410
|
+
roles={[
|
|
411
|
+
{ surface: 'primary', onSurface: 'primary-foreground', surfaceCls: 'bg-primary', onSurfaceCls: 'text-primary-foreground' },
|
|
412
|
+
{ surface: 'destructive', onSurface: 'white', surfaceCls: 'bg-destructive', onSurfaceCls: 'text-white' },
|
|
413
|
+
{ surface: 'brand-violet', onSurface: 'brand-violet-foreground', surfaceCls: 'bg-brand-violet', onSurfaceCls: 'text-brand-violet-foreground' },
|
|
414
|
+
{ surface: 'accent-indigo', onSurface: 'accent-indigo-foreground', surfaceCls: 'bg-accent-indigo', onSurfaceCls: 'text-accent-indigo-foreground' },
|
|
415
|
+
]}
|
|
416
|
+
/>
|
|
417
|
+
),
|
|
418
|
+
code: `<button className="bg-primary text-primary-foreground" />`,
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
id: 'surfaces',
|
|
422
|
+
title: 'surfaces',
|
|
423
|
+
render: () => (
|
|
424
|
+
<RoleGrid
|
|
425
|
+
roles={[
|
|
426
|
+
{ surface: 'background', onSurface: 'foreground', surfaceCls: 'bg-background', onSurfaceCls: 'text-foreground' },
|
|
427
|
+
{ surface: 'card', onSurface: 'card-foreground', surfaceCls: 'bg-card', onSurfaceCls: 'text-card-foreground' },
|
|
428
|
+
{ surface: 'popover', onSurface: 'popover-foreground', surfaceCls: 'bg-popover', onSurfaceCls: 'text-popover-foreground' },
|
|
429
|
+
{ surface: 'muted', onSurface: 'muted-foreground', surfaceCls: 'bg-muted', onSurfaceCls: 'text-muted-foreground' },
|
|
430
|
+
{ surface: 'accent', onSurface: 'accent-foreground', surfaceCls: 'bg-accent', onSurfaceCls: 'text-accent-foreground' },
|
|
431
|
+
{ surface: 'sidebar', onSurface: 'sidebar-foreground', surfaceCls: 'bg-sidebar', onSurfaceCls: 'text-sidebar-foreground' },
|
|
432
|
+
]}
|
|
433
|
+
/>
|
|
434
|
+
),
|
|
435
|
+
code: `<div className="bg-card text-card-foreground" />`,
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
id: 'status',
|
|
439
|
+
title: 'status',
|
|
440
|
+
render: () => (
|
|
441
|
+
<RoleGrid
|
|
442
|
+
roles={['error', 'success', 'warning', 'info', 'neutral', 'pink'].map((status) => ({
|
|
443
|
+
surface: `status-${status}-bg`,
|
|
444
|
+
onSurface: `status-${status}-text`,
|
|
445
|
+
surfaceCls: `bg-status-${status}-bg`,
|
|
446
|
+
onSurfaceCls: `text-status-${status}-text`,
|
|
447
|
+
borderCls: `border-status-${status}-border`,
|
|
448
|
+
}))}
|
|
449
|
+
/>
|
|
450
|
+
),
|
|
451
|
+
code: `<span className="bg-status-error-bg text-status-error-text border-status-error-border" />`,
|
|
452
|
+
},
|
|
453
|
+
],
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const RADIUS_SCALE: Array<{ cls: string; label: string; px: string }> = [
|
|
457
|
+
{ cls: 'rounded-none', label: 'rounded-none', px: '0px' },
|
|
458
|
+
{ cls: 'rounded-sm', label: 'rounded-sm', px: '6px' },
|
|
459
|
+
{ cls: 'rounded-md', label: 'rounded-md', px: '8px' },
|
|
460
|
+
{ cls: 'rounded-lg', label: 'rounded-lg', px: '10px' },
|
|
461
|
+
{ cls: 'rounded-xl', label: 'rounded-xl', px: '16px' },
|
|
462
|
+
{ cls: 'rounded-full', label: 'rounded-full', px: '999px' },
|
|
463
|
+
]
|
|
464
|
+
|
|
465
|
+
function RadiusCard({ cls, label, px }: { cls: string; label: string; px: string }) {
|
|
466
|
+
const onCopy = React.useCallback(async () => {
|
|
467
|
+
try {
|
|
468
|
+
await navigator.clipboard.writeText(label)
|
|
469
|
+
flash(`${label} copied`, 'success')
|
|
470
|
+
} catch {
|
|
471
|
+
flash('Could not copy the class', 'error')
|
|
472
|
+
}
|
|
473
|
+
}, [label])
|
|
474
|
+
return (
|
|
475
|
+
<button
|
|
476
|
+
type="button"
|
|
477
|
+
onClick={onCopy}
|
|
478
|
+
title={`Copy ${label}`}
|
|
479
|
+
className="flex w-36 flex-col items-start gap-2 rounded-md border border-border bg-background p-2 text-left transition-colors hover:bg-muted/40"
|
|
480
|
+
>
|
|
481
|
+
<span aria-hidden className={`h-14 w-full border-2 border-dashed border-status-pink-icon bg-status-pink-bg ${cls}`} />
|
|
482
|
+
<span className="space-y-0.5">
|
|
483
|
+
<code className="block text-xs text-foreground">{label}</code>
|
|
484
|
+
<span className="block text-xs text-muted-foreground">{px}</span>
|
|
485
|
+
</span>
|
|
486
|
+
</button>
|
|
487
|
+
)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
const radiusEntry: GalleryEntry = {
|
|
491
|
+
id: 'corner-radius',
|
|
492
|
+
title: 'Corner radius',
|
|
493
|
+
importPath: TOKENS_IMPORT,
|
|
494
|
+
keywords: ['radius', 'rounded', 'border-radius', 'corners'],
|
|
495
|
+
usage: {
|
|
496
|
+
do: [
|
|
497
|
+
'The scale derives from the --radius base token (10px): sm 6px, md 8px, lg 10px, xl 16px.',
|
|
498
|
+
'Cards and panels use rounded-lg; controls, chips and filter buttons use rounded-md.',
|
|
499
|
+
'rounded-full is reserved for Badge, Tag, SegmentedControl, Avatar and status dots.',
|
|
500
|
+
],
|
|
501
|
+
dont: [
|
|
502
|
+
'No arbitrary values (rounded-[24px]) — pick from the scale.',
|
|
503
|
+
'No full-pill radii on filter chips or custom controls outside the reserved primitives.',
|
|
504
|
+
],
|
|
505
|
+
},
|
|
506
|
+
variants: [
|
|
507
|
+
{
|
|
508
|
+
id: 'scale',
|
|
509
|
+
title: 'scale',
|
|
510
|
+
render: () => (
|
|
511
|
+
<div className="flex flex-wrap gap-2">
|
|
512
|
+
{RADIUS_SCALE.map((item) => (
|
|
513
|
+
<RadiusCard key={item.cls} {...item} />
|
|
514
|
+
))}
|
|
515
|
+
</div>
|
|
516
|
+
),
|
|
517
|
+
code: `<div className="rounded-lg border border-border" />`,
|
|
518
|
+
},
|
|
519
|
+
],
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
export const entries: GalleryEntry[] = [
|
|
523
|
+
brandColorsEntry,
|
|
524
|
+
colorRolesEntry,
|
|
525
|
+
colorTokensEntry,
|
|
526
|
+
stateTokensEntry,
|
|
527
|
+
chartPaletteEntry,
|
|
528
|
+
radiusEntry,
|
|
529
|
+
]
|