@actuate-media/cms-admin 0.63.2 → 0.64.0
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/CHANGELOG.md +10 -0
- package/design-system/README.md +53 -0
- package/design-system/tokens.css +114 -0
- package/design-system/tokens.json +149 -0
- package/design-system/tokens.scss +108 -0
- package/design-system/tokens.tailwind.cjs +80 -0
- package/dist/__tests__/layout/primitives.test.js +9 -2
- package/dist/__tests__/layout/primitives.test.js.map +1 -1
- package/dist/actuate-admin.css +1 -1
- package/dist/components/EnabledSwitch.d.ts +2 -5
- package/dist/components/EnabledSwitch.d.ts.map +1 -1
- package/dist/components/EnabledSwitch.js +4 -7
- package/dist/components/EnabledSwitch.js.map +1 -1
- package/dist/components/ThemeProvider.d.ts.map +1 -1
- package/dist/components/ThemeProvider.js +5 -3
- package/dist/components/ThemeProvider.js.map +1 -1
- package/dist/components/forms/FieldsPanel.js +2 -2
- package/dist/components/forms/FieldsPanel.js.map +1 -1
- package/dist/components/forms/NotificationsPanel.js +2 -2
- package/dist/components/forms/NotificationsPanel.js.map +1 -1
- package/dist/components/forms/WebhooksPanel.d.ts.map +1 -1
- package/dist/components/forms/WebhooksPanel.js +2 -2
- package/dist/components/forms/WebhooksPanel.js.map +1 -1
- package/dist/components/seo/primitives.d.ts.map +1 -1
- package/dist/components/seo/primitives.js +2 -1
- package/dist/components/seo/primitives.js.map +1 -1
- package/dist/components/ui/Button.d.ts +1 -1
- package/dist/components/ui/Button.js +1 -1
- package/dist/components/ui/Button.js.map +1 -1
- package/dist/components/ui/Card.d.ts +6 -5
- package/dist/components/ui/Card.d.ts.map +1 -1
- package/dist/components/ui/Card.js +20 -18
- package/dist/components/ui/Card.js.map +1 -1
- package/dist/components/ui/Input.d.ts +2 -1
- package/dist/components/ui/Input.d.ts.map +1 -1
- package/dist/components/ui/Input.js +9 -8
- package/dist/components/ui/Input.js.map +1 -1
- package/dist/components/ui/SearchInput.d.ts.map +1 -1
- package/dist/components/ui/SearchInput.js +2 -1
- package/dist/components/ui/SearchInput.js.map +1 -1
- package/dist/components/ui/Select.d.ts.map +1 -1
- package/dist/components/ui/Select.js +9 -10
- package/dist/components/ui/Select.js.map +1 -1
- package/dist/components/ui/Toggle.d.ts +31 -0
- package/dist/components/ui/Toggle.d.ts.map +1 -0
- package/dist/components/ui/Toggle.js +41 -0
- package/dist/components/ui/Toggle.js.map +1 -0
- package/dist/components/ui/form-control.d.ts +11 -0
- package/dist/components/ui/form-control.d.ts.map +1 -0
- package/dist/components/ui/form-control.js +11 -0
- package/dist/components/ui/form-control.js.map +1 -0
- package/dist/components/ui/index.d.ts +3 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +2 -0
- package/dist/components/ui/index.js.map +1 -1
- package/dist/layout/Header.d.ts.map +1 -1
- package/dist/layout/Header.js +5 -2
- package/dist/layout/Header.js.map +1 -1
- package/dist/layout/Sidebar.js +1 -1
- package/dist/layout/Sidebar.js.map +1 -1
- package/dist/layout/primitives/tokens.d.ts +10 -4
- package/dist/layout/primitives/tokens.d.ts.map +1 -1
- package/dist/layout/primitives/tokens.js +10 -4
- package/dist/layout/primitives/tokens.js.map +1 -1
- package/dist/views/Forms.js +2 -2
- package/dist/views/Forms.js.map +1 -1
- package/dist/views/page-builder/BottomBar.d.ts.map +1 -1
- package/dist/views/page-builder/BottomBar.js +2 -2
- package/dist/views/page-builder/BottomBar.js.map +1 -1
- package/dist/views/seo/TechnicalTab.d.ts.map +1 -1
- package/dist/views/seo/TechnicalTab.js +2 -2
- package/dist/views/seo/TechnicalTab.js.map +1 -1
- package/dist/views/settings/components.d.ts.map +1 -1
- package/dist/views/settings/components.js +2 -1
- package/dist/views/settings/components.js.map +1 -1
- package/package.json +8 -3
- package/src/__tests__/layout/primitives.test.ts +10 -2
- package/src/components/EnabledSwitch.tsx +4 -22
- package/src/components/ThemeProvider.tsx +5 -3
- package/src/components/forms/FieldsPanel.tsx +4 -6
- package/src/components/forms/NotificationsPanel.tsx +2 -9
- package/src/components/forms/WebhooksPanel.tsx +4 -6
- package/src/components/seo/primitives.tsx +8 -7
- package/src/components/ui/Button.tsx +1 -1
- package/src/components/ui/Card.tsx +35 -18
- package/src/components/ui/Input.tsx +15 -17
- package/src/components/ui/SearchInput.tsx +9 -4
- package/src/components/ui/Select.tsx +15 -18
- package/src/components/ui/Toggle.tsx +85 -0
- package/src/components/ui/form-control.ts +12 -0
- package/src/components/ui/index.ts +3 -0
- package/src/layout/Header.tsx +6 -2
- package/src/layout/Sidebar.tsx +3 -3
- package/src/layout/primitives/tokens.ts +11 -4
- package/src/styles/actuate-tokens.css +97 -0
- package/src/styles/theme.css +88 -156
- package/src/views/Forms.tsx +4 -6
- package/src/views/page-builder/BottomBar.tsx +3 -6
- package/src/views/seo/TechnicalTab.tsx +3 -6
- package/src/views/settings/components.tsx +11 -10
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as Dialog from '@radix-ui/react-dialog';
|
|
4
4
|
import { AlertTriangle, Check, Loader2, Lock } from 'lucide-react';
|
|
5
5
|
import { useId } from 'react';
|
|
6
|
+
import { Card, CardContent, CardDescription, CardHeader } from '../../components/ui/Card.js';
|
|
6
7
|
import { adminPortalContainer } from '../../lib/portal-container.js';
|
|
7
8
|
/**
|
|
8
9
|
* The canonical Settings section card: a bordered `bg-card` surface with a
|
|
@@ -15,7 +16,7 @@ import { adminPortalContainer } from '../../lib/portal-container.js';
|
|
|
15
16
|
*/
|
|
16
17
|
export function SettingsCard({ title, description, actions, children, className, headingLevel: Heading = 'h3', }) {
|
|
17
18
|
const headingId = useId();
|
|
18
|
-
return (_jsxs(
|
|
19
|
+
return (_jsxs(Card, { padding: "none", "aria-labelledby": headingId, role: "region", className: className, children: [_jsxs(CardHeader, { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx(Heading, { id: headingId, className: "text-[length:var(--fs-card)] font-semibold text-[var(--txt)]", children: title }), description && _jsx(CardDescription, { children: description })] }), actions && _jsx("div", { className: "flex shrink-0 items-center gap-2", children: actions })] }), _jsx(CardContent, { className: "pt-0 text-[var(--txt)]", children: children })] }));
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
22
|
* A sub-section inside a {@link SettingsCard}: a top divider plus a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.js","sourceRoot":"","sources":["../../../src/views/settings/components.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,KAAK,MAAM,MAAM,wBAAwB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAClE,OAAO,EAAE,KAAK,EAAkB,MAAM,OAAO,CAAA;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA;AAGpE;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,EAC3B,KAAK,EACL,WAAW,EACX,OAAO,EACP,QAAQ,EACR,SAAS,EACT,YAAY,EAAE,OAAO,GAAG,IAAI,GAU7B;IACC,MAAM,SAAS,GAAG,KAAK,EAAE,CAAA;IACzB,OAAO,CACL,
|
|
1
|
+
{"version":3,"file":"components.js","sourceRoot":"","sources":["../../../src/views/settings/components.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actuate-media/cms-admin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.64.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/actuate-media/actuatecms.git",
|
|
@@ -20,9 +20,14 @@
|
|
|
20
20
|
},
|
|
21
21
|
"./styles": "./src/styles/tailwind.css",
|
|
22
22
|
"./styles/theme.css": "./src/styles/theme.css",
|
|
23
|
-
"./styles/precompiled.css": "./dist/actuate-admin.css"
|
|
23
|
+
"./styles/precompiled.css": "./dist/actuate-admin.css",
|
|
24
|
+
"./design-system/tokens.css": "./design-system/tokens.css",
|
|
25
|
+
"./design-system/tokens.json": "./design-system/tokens.json",
|
|
26
|
+
"./design-system/tokens.scss": "./design-system/tokens.scss",
|
|
27
|
+
"./design-system/tokens.tailwind.cjs": "./design-system/tokens.tailwind.cjs"
|
|
24
28
|
},
|
|
25
29
|
"files": [
|
|
30
|
+
"design-system",
|
|
26
31
|
"dist",
|
|
27
32
|
"src/styles",
|
|
28
33
|
"src/**/*.tsx",
|
|
@@ -90,7 +95,7 @@
|
|
|
90
95
|
"tailwindcss": "^4.0.0",
|
|
91
96
|
"typescript": "^5.7.0",
|
|
92
97
|
"vitest": "^4.1.0",
|
|
93
|
-
"@actuate-media/cms-core": "0.85.
|
|
98
|
+
"@actuate-media/cms-core": "0.85.2",
|
|
94
99
|
"@actuate-media/component-blocks": "0.2.1"
|
|
95
100
|
},
|
|
96
101
|
"scripts": {
|
|
@@ -12,8 +12,16 @@ describe('layout primitive tokens', () => {
|
|
|
12
12
|
|
|
13
13
|
it('exposes the canonical radius scale', () => {
|
|
14
14
|
expect(tokens.radius.none).toBe(0)
|
|
15
|
-
expect(tokens.radius.
|
|
16
|
-
expect(tokens.radius.
|
|
15
|
+
expect(tokens.radius.sm).toBe(6)
|
|
16
|
+
expect(tokens.radius.md).toBe(8)
|
|
17
|
+
expect(tokens.radius.lg).toBe(10)
|
|
18
|
+
expect(tokens.radius.full).toBe(99)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('exposes layout dimensions from the design system', () => {
|
|
22
|
+
expect(tokens.layout.sidebarWidth).toBe(224)
|
|
23
|
+
expect(tokens.layout.sidebarWidthCollapsed).toBe(60)
|
|
24
|
+
expect(tokens.layout.topbarHeight).toBe(56)
|
|
17
25
|
})
|
|
18
26
|
|
|
19
27
|
it('exposes the canonical breakpoint scale', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import { Toggle } from './ui/Toggle.js'
|
|
4
4
|
|
|
5
5
|
export interface EnabledSwitchProps {
|
|
6
6
|
checked: boolean
|
|
@@ -10,25 +10,7 @@ export interface EnabledSwitchProps {
|
|
|
10
10
|
'aria-label': string
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
*/
|
|
17
|
-
export function EnabledSwitch({
|
|
18
|
-
checked,
|
|
19
|
-
onCheckedChange,
|
|
20
|
-
disabled,
|
|
21
|
-
'aria-label': ariaLabel,
|
|
22
|
-
}: EnabledSwitchProps) {
|
|
23
|
-
return (
|
|
24
|
-
<Switch.Root
|
|
25
|
-
checked={checked}
|
|
26
|
-
onCheckedChange={onCheckedChange}
|
|
27
|
-
disabled={disabled}
|
|
28
|
-
aria-label={ariaLabel}
|
|
29
|
-
className="bg-destructive data-[state=checked]:bg-success focus-visible:ring-ring relative inline-flex h-[22px] w-11 shrink-0 rounded-full transition-colors focus-visible:ring-2 focus-visible:outline-none disabled:opacity-50"
|
|
30
|
-
>
|
|
31
|
-
<Switch.Thumb className="bg-background block h-[18px] w-[18px] translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[22px]" />
|
|
32
|
-
</Switch.Root>
|
|
33
|
-
)
|
|
13
|
+
/** Enable/disable toggle — design-system track + success green when on. */
|
|
14
|
+
export function EnabledSwitch(props: EnabledSwitchProps) {
|
|
15
|
+
return <Toggle {...props} variant="enabled" />
|
|
34
16
|
}
|
|
@@ -89,7 +89,7 @@ const ThemeContext = createContext<ThemeContextValue>({
|
|
|
89
89
|
setAccent: () => {},
|
|
90
90
|
density: 'default',
|
|
91
91
|
setDensity: () => {},
|
|
92
|
-
font: '
|
|
92
|
+
font: 'System UI',
|
|
93
93
|
setFont: () => {},
|
|
94
94
|
reduceMotion: false,
|
|
95
95
|
setReduceMotion: () => {},
|
|
@@ -126,6 +126,8 @@ function applyColorMode(resolved: 'light' | 'dark') {
|
|
|
126
126
|
const el = adminRootEl()
|
|
127
127
|
if (!el) return
|
|
128
128
|
el.classList.toggle('dark', resolved === 'dark')
|
|
129
|
+
// Mirror handoff tokens.css selector so unscoped handoff styles can target the admin root.
|
|
130
|
+
el.setAttribute('data-theme', resolved)
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
function applyAccent(accent: string, resolved: 'light' | 'dark') {
|
|
@@ -166,7 +168,7 @@ export function ThemeProvider({ children, defaultDarkMode }: ThemeProviderProps)
|
|
|
166
168
|
const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>('light')
|
|
167
169
|
const [accent, setAccentState] = useState('purple')
|
|
168
170
|
const [density, setDensityState] = useState<SidebarDensity>('default')
|
|
169
|
-
const [font, setFontState] = useState('
|
|
171
|
+
const [font, setFontState] = useState('System UI')
|
|
170
172
|
const [reduceMotion, setReduceMotionState] = useState(false)
|
|
171
173
|
const [adminBrand, setAdminBrandState] = useState<AdminBrandCache>(DEFAULT_BRAND)
|
|
172
174
|
|
|
@@ -187,7 +189,7 @@ export function ThemeProvider({ children, defaultDarkMode }: ThemeProviderProps)
|
|
|
187
189
|
|
|
188
190
|
const storedAccent = localStorage.getItem(KEY_ACCENT) || 'purple'
|
|
189
191
|
const storedDensity = (localStorage.getItem(KEY_DENSITY) as SidebarDensity | null) || 'default'
|
|
190
|
-
const storedFont = localStorage.getItem(KEY_FONT) || '
|
|
192
|
+
const storedFont = localStorage.getItem(KEY_FONT) || 'System UI'
|
|
191
193
|
const storedMotion = localStorage.getItem(KEY_MOTION) === 'true'
|
|
192
194
|
let storedBrand = DEFAULT_BRAND
|
|
193
195
|
try {
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from '@dnd-kit/sortable'
|
|
24
24
|
import { CSS } from '@dnd-kit/utilities'
|
|
25
25
|
import { ChevronDown, GripVertical, Plus, Trash2 } from 'lucide-react'
|
|
26
|
-
import
|
|
26
|
+
import { Toggle } from '../ui/Toggle.js'
|
|
27
27
|
import { useId, useState } from 'react'
|
|
28
28
|
import type { FormField, FormFieldType } from '../../lib/forms-service.js'
|
|
29
29
|
import { FieldTypeBadge, FormsEmptyState } from './primitives.js'
|
|
@@ -353,14 +353,12 @@ function FieldEditor({
|
|
|
353
353
|
<label htmlFor={reqId} className="text-foreground text-sm font-medium">
|
|
354
354
|
Required
|
|
355
355
|
</label>
|
|
356
|
-
<
|
|
356
|
+
<Toggle
|
|
357
357
|
id={reqId}
|
|
358
358
|
checked={field.required}
|
|
359
359
|
onCheckedChange={(v) => onUpdate({ required: v })}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
<Switch.Thumb className="bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[14px]" />
|
|
363
|
-
</Switch.Root>
|
|
360
|
+
aria-labelledby={reqId}
|
|
361
|
+
/>
|
|
364
362
|
</div>
|
|
365
363
|
</div>
|
|
366
364
|
)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* autoresponder). Email delivery uses the configured email adapter when enabled.
|
|
7
7
|
*/
|
|
8
8
|
import { useEffect, useState } from 'react'
|
|
9
|
-
import
|
|
9
|
+
import { Toggle } from '../ui/Toggle.js'
|
|
10
10
|
import { toast } from 'sonner'
|
|
11
11
|
import {
|
|
12
12
|
fetchNotificationSettings,
|
|
@@ -210,14 +210,7 @@ function ToggleRow({
|
|
|
210
210
|
<span className="text-foreground block text-sm font-medium">{label}</span>
|
|
211
211
|
<span className="text-muted-foreground block text-sm">{help}</span>
|
|
212
212
|
</span>
|
|
213
|
-
<
|
|
214
|
-
checked={checked}
|
|
215
|
-
onCheckedChange={onChange}
|
|
216
|
-
aria-label={label}
|
|
217
|
-
className="bg-destructive data-[state=checked]:bg-success focus-visible:ring-ring relative h-[18px] w-8 shrink-0 rounded-full transition-colors focus-visible:ring-2 focus-visible:outline-none"
|
|
218
|
-
>
|
|
219
|
-
<Switch.Thumb className="bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[14px]" />
|
|
220
|
-
</Switch.Root>
|
|
213
|
+
<Toggle checked={checked} onCheckedChange={onChange} aria-label={label} />
|
|
221
214
|
</div>
|
|
222
215
|
)
|
|
223
216
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* (Zapier Catch Hook, Make, custom CRM endpoints) and guides editors through
|
|
6
6
|
* the default Zapier → Webhooks by Zapier → Catch Hook setup.
|
|
7
7
|
*/
|
|
8
|
-
import
|
|
8
|
+
import { Toggle } from '../ui/Toggle.js'
|
|
9
9
|
import { ExternalLink, Loader2, Plus, Trash2, Zap } from 'lucide-react'
|
|
10
10
|
import { useEffect, useState } from 'react'
|
|
11
11
|
import { toast } from 'sonner'
|
|
@@ -265,14 +265,12 @@ export function WebhooksPanel({ formId, formSlug }: { formId: string; formSlug:
|
|
|
265
265
|
</p>
|
|
266
266
|
</div>
|
|
267
267
|
<div className="flex shrink-0 flex-wrap items-center gap-2">
|
|
268
|
-
<
|
|
268
|
+
<Toggle
|
|
269
269
|
checked={webhook.enabled}
|
|
270
270
|
onCheckedChange={(v) => void toggleEnabled(webhook, v)}
|
|
271
271
|
aria-label={`Enable webhook ${webhook.url}`}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
<Switch.Thumb className="bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[14px]" />
|
|
275
|
-
</Switch.Root>
|
|
272
|
+
variant="enabled"
|
|
273
|
+
/>
|
|
276
274
|
<button
|
|
277
275
|
type="button"
|
|
278
276
|
className={btnSecondary}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { ReactNode } from 'react'
|
|
9
9
|
import { AlertTriangle, Loader2 } from 'lucide-react'
|
|
10
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../ui/Card.js'
|
|
10
11
|
import type { SeoGrade, SeoSeverity } from '../../lib/seo-service.js'
|
|
11
12
|
|
|
12
13
|
// ─── Grade + severity styling ────────────────────────────────────────
|
|
@@ -159,18 +160,18 @@ export function SectionCard({
|
|
|
159
160
|
className?: string
|
|
160
161
|
}) {
|
|
161
162
|
return (
|
|
162
|
-
<
|
|
163
|
+
<Card padding="none" className={className} role="region">
|
|
163
164
|
{(title || action) && (
|
|
164
|
-
<
|
|
165
|
+
<CardHeader className="flex items-center justify-between gap-3">
|
|
165
166
|
<div className="min-w-0">
|
|
166
|
-
{title && <
|
|
167
|
-
{description && <
|
|
167
|
+
{title && <CardTitle>{title}</CardTitle>}
|
|
168
|
+
{description && <CardDescription>{description}</CardDescription>}
|
|
168
169
|
</div>
|
|
169
170
|
{action}
|
|
170
|
-
</
|
|
171
|
+
</CardHeader>
|
|
171
172
|
)}
|
|
172
|
-
<
|
|
173
|
-
</
|
|
173
|
+
<CardContent className={title || action ? 'pt-0' : ''}>{children}</CardContent>
|
|
174
|
+
</Card>
|
|
174
175
|
)
|
|
175
176
|
}
|
|
176
177
|
|
|
@@ -5,7 +5,7 @@ import { cv, type VariantProps } from '../../lib/cv.js'
|
|
|
5
5
|
|
|
6
6
|
const button = cv(
|
|
7
7
|
// Base classes apply to every variant.
|
|
8
|
-
'focus-visible:ring-offset-background inline-flex items-center justify-center gap-2 rounded-[var(--
|
|
8
|
+
'focus-visible:ring-offset-background inline-flex items-center justify-center gap-2 rounded-[var(--r-control)] font-medium transition-colors duration-[var(--motion-fast)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50',
|
|
9
9
|
{
|
|
10
10
|
variants: {
|
|
11
11
|
variant: {
|
|
@@ -2,29 +2,31 @@ import { forwardRef, type HTMLAttributes, type ReactNode } from 'react'
|
|
|
2
2
|
import { cv, type VariantProps } from '../../lib/cv.js'
|
|
3
3
|
|
|
4
4
|
const card = cv(
|
|
5
|
-
'rounded-[var(--
|
|
5
|
+
'overflow-hidden rounded-[var(--r)] border border-[var(--bdr)] bg-[var(--card)] text-[var(--txt)]',
|
|
6
6
|
{
|
|
7
7
|
variants: {
|
|
8
8
|
padding: {
|
|
9
9
|
none: 'p-0',
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
/** Stat / compact surfaces (`.dstat`). */
|
|
11
|
+
sm: 'px-4 py-3.5',
|
|
12
|
+
/** Simple padded panel (`.dcard-b`). */
|
|
13
|
+
md: 'px-[18px] py-4',
|
|
14
|
+
lg: 'px-[18px] py-6',
|
|
13
15
|
},
|
|
14
16
|
elevation: {
|
|
15
17
|
flat: 'shadow-none',
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
lg: 'shadow-lg',
|
|
18
|
+
resting: 'shadow-[var(--shd)]',
|
|
19
|
+
elevated: 'shadow-[var(--shd2)]',
|
|
19
20
|
},
|
|
20
21
|
},
|
|
21
|
-
defaultVariants: { padding: '
|
|
22
|
+
defaultVariants: { padding: 'none', elevation: 'resting' },
|
|
22
23
|
},
|
|
23
24
|
)
|
|
24
25
|
|
|
25
26
|
export type CardVariants = VariantProps<typeof card>
|
|
26
27
|
|
|
27
|
-
const INTERACTIVE_CLASS =
|
|
28
|
+
const INTERACTIVE_CLASS =
|
|
29
|
+
'motion-safe:transition-shadow motion-safe:duration-[var(--motion-fast)] hover:shadow-[var(--shd2)] focus-within:shadow-[var(--shd2)]'
|
|
28
30
|
|
|
29
31
|
export interface CardProps extends HTMLAttributes<HTMLDivElement>, CardVariants {
|
|
30
32
|
/** Apply hover/focus elevation transitions (e.g. for clickable cards). */
|
|
@@ -44,12 +46,20 @@ export const Card = forwardRef<HTMLDivElement, CardProps>(function Card(
|
|
|
44
46
|
)
|
|
45
47
|
})
|
|
46
48
|
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
/** Header slot — `.dcard-h` in the design system handoff. */
|
|
50
|
+
export function CardHeader({
|
|
51
|
+
className = '',
|
|
52
|
+
bordered = true,
|
|
53
|
+
children,
|
|
54
|
+
...rest
|
|
55
|
+
}: HTMLAttributes<HTMLDivElement> & { bordered?: boolean }) {
|
|
51
56
|
return (
|
|
52
|
-
<div
|
|
57
|
+
<div
|
|
58
|
+
className={[bordered ? 'border-b border-[var(--bdr)] px-[18px] py-[14px]' : '', className]
|
|
59
|
+
.filter(Boolean)
|
|
60
|
+
.join(' ')}
|
|
61
|
+
{...rest}
|
|
62
|
+
>
|
|
53
63
|
{children}
|
|
54
64
|
</div>
|
|
55
65
|
)
|
|
@@ -62,7 +72,7 @@ export function CardTitle({
|
|
|
62
72
|
}: HTMLAttributes<HTMLHeadingElement>) {
|
|
63
73
|
return (
|
|
64
74
|
<h3
|
|
65
|
-
className={`text-
|
|
75
|
+
className={`text-[length:var(--fs-card)] font-semibold text-[var(--txt)] ${className}`}
|
|
66
76
|
{...rest}
|
|
67
77
|
>
|
|
68
78
|
{children}
|
|
@@ -76,15 +86,19 @@ export function CardDescription({
|
|
|
76
86
|
...rest
|
|
77
87
|
}: HTMLAttributes<HTMLParagraphElement>) {
|
|
78
88
|
return (
|
|
79
|
-
<p className={`text-
|
|
89
|
+
<p className={`mt-px text-[length:var(--fs-hint)] text-[var(--muted)] ${className}`} {...rest}>
|
|
80
90
|
{children}
|
|
81
91
|
</p>
|
|
82
92
|
)
|
|
83
93
|
}
|
|
84
94
|
|
|
95
|
+
/** Body slot — `.dcard-b` in the design system handoff. */
|
|
85
96
|
export function CardContent({ className = '', children, ...rest }: HTMLAttributes<HTMLDivElement>) {
|
|
86
97
|
return (
|
|
87
|
-
<div
|
|
98
|
+
<div
|
|
99
|
+
className={`px-[18px] py-4 text-[length:var(--fs-body)] leading-[1.55] text-[var(--sub)] ${className}`}
|
|
100
|
+
{...rest}
|
|
101
|
+
>
|
|
88
102
|
{children}
|
|
89
103
|
</div>
|
|
90
104
|
)
|
|
@@ -92,7 +106,10 @@ export function CardContent({ className = '', children, ...rest }: HTMLAttribute
|
|
|
92
106
|
|
|
93
107
|
export function CardFooter({ className = '', children, ...rest }: HTMLAttributes<HTMLDivElement>) {
|
|
94
108
|
return (
|
|
95
|
-
<div
|
|
109
|
+
<div
|
|
110
|
+
className={`flex items-center justify-end gap-2 border-t border-[var(--bdr)] px-[18px] py-3 ${className}`}
|
|
111
|
+
{...rest}
|
|
112
|
+
>
|
|
96
113
|
{children}
|
|
97
114
|
</div>
|
|
98
115
|
)
|
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
import { forwardRef, type InputHTMLAttributes } from 'react'
|
|
2
2
|
import { cv, type VariantProps } from '../../lib/cv.js'
|
|
3
|
+
import { formControlBase, formControlState } from './form-control.js'
|
|
3
4
|
|
|
4
|
-
const input = cv(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
invalid: 'border-[var(--destructive)] focus-visible:ring-[var(--destructive)]',
|
|
16
|
-
valid: 'border-emerald-500 focus-visible:ring-emerald-500',
|
|
17
|
-
},
|
|
5
|
+
const input = cv(formControlBase, {
|
|
6
|
+
variants: {
|
|
7
|
+
size: {
|
|
8
|
+
sm: 'py-1.5 text-[length:var(--fs-sub)]',
|
|
9
|
+
md: '',
|
|
10
|
+
lg: 'py-2.5 text-[length:var(--fs-body)]',
|
|
11
|
+
},
|
|
12
|
+
state: {
|
|
13
|
+
default: formControlState.default,
|
|
14
|
+
invalid: formControlState.invalid,
|
|
15
|
+
valid: formControlState.valid,
|
|
18
16
|
},
|
|
19
|
-
defaultVariants: { size: 'md', state: 'default' },
|
|
20
17
|
},
|
|
21
|
-
|
|
18
|
+
defaultVariants: { size: 'md', state: 'default' },
|
|
19
|
+
})
|
|
22
20
|
|
|
23
21
|
export type InputVariants = VariantProps<typeof input>
|
|
24
22
|
|
|
@@ -32,4 +30,4 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
|
|
|
32
30
|
return <input ref={ref} className={input({ size, state, class: className })} {...rest} />
|
|
33
31
|
})
|
|
34
32
|
|
|
35
|
-
export { input as inputVariants }
|
|
33
|
+
export { input as inputVariants, formControlBase, formControlState }
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
+
import { inputVariants } from './Input.js'
|
|
4
|
+
|
|
3
5
|
export interface SearchInputProps {
|
|
4
6
|
value: string
|
|
5
7
|
onChange: (value: string) => void
|
|
@@ -10,11 +12,12 @@ export function SearchInput({ value, onChange, placeholder = 'Search...' }: Sear
|
|
|
10
12
|
return (
|
|
11
13
|
<div className="relative flex-1">
|
|
12
14
|
<svg
|
|
13
|
-
className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-[var(--muted
|
|
15
|
+
className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-[var(--muted)]"
|
|
14
16
|
fill="none"
|
|
15
17
|
viewBox="0 0 24 24"
|
|
16
18
|
stroke="currentColor"
|
|
17
19
|
strokeWidth={2}
|
|
20
|
+
aria-hidden
|
|
18
21
|
>
|
|
19
22
|
<path
|
|
20
23
|
strokeLinecap="round"
|
|
@@ -27,12 +30,13 @@ export function SearchInput({ value, onChange, placeholder = 'Search...' }: Sear
|
|
|
27
30
|
value={value}
|
|
28
31
|
onChange={(e) => onChange(e.target.value)}
|
|
29
32
|
placeholder={placeholder}
|
|
30
|
-
className=
|
|
33
|
+
className={inputVariants({ class: 'py-2 pr-8 pl-9' })}
|
|
31
34
|
/>
|
|
32
35
|
{value && (
|
|
33
36
|
<button
|
|
37
|
+
type="button"
|
|
34
38
|
onClick={() => onChange('')}
|
|
35
|
-
className="absolute top-1/2 right-2 -translate-y-1/2 rounded p-0.5 text-[var(--muted
|
|
39
|
+
className="absolute top-1/2 right-2 -translate-y-1/2 rounded p-0.5 text-[var(--muted)] hover:text-[var(--txt)]"
|
|
36
40
|
aria-label="Clear search"
|
|
37
41
|
>
|
|
38
42
|
<svg
|
|
@@ -41,12 +45,13 @@ export function SearchInput({ value, onChange, placeholder = 'Search...' }: Sear
|
|
|
41
45
|
viewBox="0 0 24 24"
|
|
42
46
|
stroke="currentColor"
|
|
43
47
|
strokeWidth={2}
|
|
48
|
+
aria-hidden
|
|
44
49
|
>
|
|
45
50
|
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
46
51
|
</svg>
|
|
47
52
|
</button>
|
|
48
53
|
)}
|
|
49
|
-
<kbd className="pointer-events-none absolute top-1/2 right-8 hidden -translate-y-1/2 rounded border border-[var(--
|
|
54
|
+
<kbd className="pointer-events-none absolute top-1/2 right-8 hidden -translate-y-1/2 rounded border border-[var(--bdr)] px-1.5 py-0.5 text-[10px] text-[var(--muted)] sm:inline-block">
|
|
50
55
|
⌘K
|
|
51
56
|
</kbd>
|
|
52
57
|
</div>
|
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
import { forwardRef, type SelectHTMLAttributes, type ReactNode } from 'react'
|
|
2
2
|
import { cv, type VariantProps } from '../../lib/cv.js'
|
|
3
|
+
import { formControlBase, formControlState } from './form-control.js'
|
|
3
4
|
|
|
4
|
-
const select = cv(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
default: 'border-[var(--border)]',
|
|
16
|
-
invalid: 'border-[var(--destructive)] focus-visible:ring-[var(--destructive)]',
|
|
17
|
-
valid: 'border-emerald-500 focus-visible:ring-emerald-500',
|
|
18
|
-
},
|
|
5
|
+
const select = cv(`${formControlBase} appearance-none pr-8`, {
|
|
6
|
+
variants: {
|
|
7
|
+
size: {
|
|
8
|
+
sm: 'py-1.5 pr-7 pl-3 text-[length:var(--fs-sub)]',
|
|
9
|
+
md: '',
|
|
10
|
+
lg: 'py-2.5 pr-9 pl-3',
|
|
11
|
+
},
|
|
12
|
+
state: {
|
|
13
|
+
default: formControlState.default,
|
|
14
|
+
invalid: formControlState.invalid,
|
|
15
|
+
valid: formControlState.valid,
|
|
19
16
|
},
|
|
20
|
-
defaultVariants: { size: 'md', state: 'default' },
|
|
21
17
|
},
|
|
22
|
-
|
|
18
|
+
defaultVariants: { size: 'md', state: 'default' },
|
|
19
|
+
})
|
|
23
20
|
|
|
24
21
|
export type SelectVariants = VariantProps<typeof select>
|
|
25
22
|
|
|
@@ -39,7 +36,7 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(function Select
|
|
|
39
36
|
</select>
|
|
40
37
|
<svg
|
|
41
38
|
aria-hidden
|
|
42
|
-
className="pointer-events-none absolute top-1/2 right-2 h-4 w-4 -translate-y-1/2 text-[var(--muted
|
|
39
|
+
className="pointer-events-none absolute top-1/2 right-2 h-4 w-4 -translate-y-1/2 text-[var(--muted)]"
|
|
43
40
|
viewBox="0 0 20 20"
|
|
44
41
|
fill="currentColor"
|
|
45
42
|
>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as Switch from '@radix-ui/react-switch'
|
|
4
|
+
import { cv, type VariantProps } from '../../lib/cv.js'
|
|
5
|
+
|
|
6
|
+
const toggleTrack = cv(
|
|
7
|
+
'relative inline-flex shrink-0 cursor-pointer rounded-[var(--r-pill)] transition-colors duration-[var(--motion-base)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
/** Design system default — accent when on. */
|
|
12
|
+
accent: 'bg-[var(--bdr)] data-[state=checked]:bg-[var(--acc)]',
|
|
13
|
+
/** Semantic enable/disable — success green when on (tables, script tags). */
|
|
14
|
+
enabled: 'bg-[var(--bdr)] data-[state=checked]:bg-[var(--suc)]',
|
|
15
|
+
},
|
|
16
|
+
size: {
|
|
17
|
+
/** Matches `.tog-track` in the design system handoff (38×21). */
|
|
18
|
+
md: 'h-[21px] w-[38px]',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: {
|
|
22
|
+
variant: 'accent',
|
|
23
|
+
size: 'md',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
const toggleThumb = cv(
|
|
29
|
+
'pointer-events-none block rounded-full bg-white shadow-[0_1px_3px_rgba(0,0,0,0.2)] transition-transform duration-[var(--motion-base)]',
|
|
30
|
+
{
|
|
31
|
+
variants: {
|
|
32
|
+
size: {
|
|
33
|
+
md: 'h-4 w-4 translate-x-0.5 data-[state=checked]:translate-x-[17.5px]',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
defaultVariants: {
|
|
37
|
+
size: 'md',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
export type ToggleVariants = VariantProps<typeof toggleTrack>
|
|
43
|
+
|
|
44
|
+
export interface ToggleProps extends ToggleVariants {
|
|
45
|
+
checked: boolean
|
|
46
|
+
onCheckedChange: (checked: boolean) => void
|
|
47
|
+
disabled?: boolean
|
|
48
|
+
id?: string
|
|
49
|
+
'aria-label'?: string
|
|
50
|
+
'aria-labelledby'?: string
|
|
51
|
+
'aria-describedby'?: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Design-system toggle (`.tog-track` / `.tog-thumb`). Use `variant="enabled"`
|
|
56
|
+
* for on/off tables where green communicates active state.
|
|
57
|
+
*/
|
|
58
|
+
export function Toggle({
|
|
59
|
+
checked,
|
|
60
|
+
onCheckedChange,
|
|
61
|
+
disabled,
|
|
62
|
+
variant,
|
|
63
|
+
size,
|
|
64
|
+
id,
|
|
65
|
+
'aria-label': ariaLabel,
|
|
66
|
+
'aria-labelledby': ariaLabelledBy,
|
|
67
|
+
'aria-describedby': ariaDescribedBy,
|
|
68
|
+
}: ToggleProps) {
|
|
69
|
+
return (
|
|
70
|
+
<Switch.Root
|
|
71
|
+
id={id}
|
|
72
|
+
checked={checked}
|
|
73
|
+
onCheckedChange={onCheckedChange}
|
|
74
|
+
disabled={disabled}
|
|
75
|
+
aria-label={ariaLabel}
|
|
76
|
+
aria-labelledby={ariaLabelledBy}
|
|
77
|
+
aria-describedby={ariaDescribedBy}
|
|
78
|
+
className={toggleTrack({ variant, size })}
|
|
79
|
+
>
|
|
80
|
+
<Switch.Thumb className={toggleThumb({ size })} />
|
|
81
|
+
</Switch.Root>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export { toggleTrack as toggleTrackVariants, toggleThumb as toggleThumbVariants }
|