@santi020k/lumen 3.0.1 → 4.1.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/README.md +211 -3
- package/dist/cli.js +49 -5
- package/dist/consumer-upgrade-audit.d.ts +10 -0
- package/dist/consumer-upgrade-audit.d.ts.map +1 -0
- package/dist/consumer-upgrade-audit.js +52 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +16 -0
- package/dist/integration-diagnostics.d.ts.map +1 -1
- package/dist/integration-diagnostics.js +199 -3
- package/dist/registry-component-name.d.ts +2 -0
- package/dist/registry-component-name.d.ts.map +1 -0
- package/dist/registry-component-name.js +53 -0
- package/dist/registry-data.d.ts +339 -18
- package/dist/registry-data.d.ts.map +1 -1
- package/dist/registry-data.js +789 -3
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +11 -9
- package/dist/source-script-ranges.d.ts +3 -0
- package/dist/source-script-ranges.d.ts.map +1 -0
- package/dist/source-script-ranges.js +41 -0
- package/dist/v2-migration.d.ts +38 -0
- package/dist/v2-migration.d.ts.map +1 -1
- package/dist/v2-migration.js +26 -14
- package/dist/v4-migration.d.ts +26 -0
- package/dist/v4-migration.d.ts.map +1 -0
- package/dist/v4-migration.js +272 -0
- package/dist/version-migration-dependencies.d.ts +8 -0
- package/dist/version-migration-dependencies.d.ts.map +1 -0
- package/dist/version-migration-dependencies.js +10 -0
- package/dist/version-migration-source.d.ts +4 -0
- package/dist/version-migration-source.d.ts.map +1 -0
- package/dist/version-migration-source.js +281 -0
- package/dist/version-migration.d.ts +34 -0
- package/dist/version-migration.d.ts.map +1 -0
- package/dist/version-migration.js +158 -0
- package/native-components.json +564 -17
- package/package.json +26 -11
- package/release-manifest.json +22 -17
- package/styles/critical.css +696 -66
- package/styles/motion.css +61 -0
- package/styles/world-map.css +30 -0
- package/styles.css +1756 -409
- package/templates/astro/advanced-fields/src/lumen/advanced-fields.astro +35 -0
- package/templates/astro/ai-docs/llms.txt +3 -0
- package/templates/astro/analytics-dashboard/src/lumen/analytics-dashboard.astro +110 -0
- package/templates/astro/auth-onboarding/src/lumen/auth-onboarding.astro +107 -0
- package/templates/astro/command-center/src/lumen/command-center.astro +34 -0
- package/templates/astro/commerce-dashboard/src/lumen/commerce-dashboard.astro +108 -0
- package/templates/astro/content-flow-actions/src/lumen/content-flow-actions.astro +10 -0
- package/templates/astro/content-flow-header/src/lumen/content-flow-header.astro +14 -0
- package/templates/astro/content-flow-list/src/lumen/content-flow-list.astro +13 -0
- package/templates/astro/content-flow-settings/src/lumen/content-flow-settings.astro +17 -0
- package/templates/astro/data-collections/src/lumen/data-collections.astro +52 -0
- package/templates/astro/feature-preview/src/lumen/feature-preview.astro +32 -0
- package/templates/astro/guided-onboarding/src/lumen/guided-onboarding.astro +35 -0
- package/templates/astro/interactive-pricing/src/lumen/interactive-pricing.astro +32 -0
- package/templates/astro/media-workspace/src/lumen/adjustment-controls.astro +89 -0
- package/templates/astro/media-workspace/src/lumen/media-processing.astro +47 -0
- package/templates/astro/media-workspace/src/lumen/media-workspace.astro +77 -0
- package/templates/astro/page-header/src/lumen/page-header.astro +41 -0
- package/templates/astro/project-workspace/src/lumen/project-workspace.astro +103 -0
- package/templates/astro/rich-text-editor/src/lumen/rich-text-editor.astro +21 -0
- package/templates/astro/saas-admin/src/lumen/saas-admin.astro +110 -0
- package/templates/astro/scheduler/src/lumen/scheduler.astro +36 -0
- package/templates/astro/section-header/src/lumen/section-header.astro +35 -0
- package/templates/astro/theme-builder/src/lumen/theme-builder.astro +28 -0
- package/templates/elements/advanced-fields/src/lumen/advanced-fields.html +25 -0
- package/templates/elements/analytics-dashboard/src/lumen/analytics-dashboard.html +28 -0
- package/templates/elements/auth-onboarding/src/lumen/auth-onboarding.html +79 -0
- package/templates/elements/command-center/src/lumen/command-center.html +15 -0
- package/templates/elements/commerce-dashboard/src/lumen/commerce-dashboard.html +24 -0
- package/templates/elements/content-flow-actions/src/lumen/content-flow-actions.html +11 -0
- package/templates/elements/content-flow-header/src/lumen/content-flow-header.html +15 -0
- package/templates/elements/content-flow-list/src/lumen/content-flow-list.html +14 -0
- package/templates/elements/content-flow-settings/src/lumen/content-flow-settings.html +18 -0
- package/templates/elements/data-collections/src/lumen/data-collections.html +31 -0
- package/templates/elements/feature-preview/src/lumen/feature-preview.html +13 -0
- package/templates/elements/guided-onboarding/src/lumen/guided-onboarding.html +16 -0
- package/templates/elements/interactive-pricing/src/lumen/interactive-pricing.html +13 -0
- package/templates/elements/media-workspace/src/lumen/media-workspace.html +57 -0
- package/templates/elements/media-workspace/src/lumen/media-workspace.ts +163 -0
- package/templates/elements/page-header/src/lumen/page-header.html +20 -0
- package/templates/elements/project-workspace/src/lumen/project-workspace.html +17 -0
- package/templates/elements/rich-text-editor/src/lumen/rich-text-editor.html +17 -0
- package/templates/elements/saas-admin/src/lumen/saas-admin.html +18 -0
- package/templates/elements/scheduler/src/lumen/scheduler.html +27 -0
- package/templates/elements/section-header/src/lumen/section-header.html +21 -0
- package/templates/elements/theme-builder/src/lumen/theme-builder.html +59 -0
- package/templates/react/advanced-fields/src/lumen/advanced-fields.tsx +37 -0
- package/templates/react/analytics-dashboard/src/lumen/analytics-dashboard.tsx +143 -0
- package/templates/react/auth-onboarding/src/lumen/auth-onboarding.tsx +129 -0
- package/templates/react/command-center/src/lumen/command-center.tsx +85 -0
- package/templates/react/commerce-dashboard/src/lumen/commerce-dashboard.tsx +148 -0
- package/templates/react/content-flow-actions/src/lumen/content-flow-actions.tsx +11 -0
- package/templates/react/content-flow-header/src/lumen/content-flow-header.tsx +14 -0
- package/templates/react/content-flow-list/src/lumen/content-flow-list.tsx +19 -0
- package/templates/react/content-flow-settings/src/lumen/content-flow-settings.tsx +26 -0
- package/templates/react/data-collections/src/lumen/data-collections.tsx +60 -0
- package/templates/react/feature-preview/src/lumen/feature-preview.tsx +42 -0
- package/templates/react/guided-onboarding/src/lumen/guided-onboarding.tsx +100 -0
- package/templates/react/import-review/src/lumen/import-review.tsx +150 -0
- package/templates/react/interactive-pricing/src/lumen/interactive-pricing.tsx +60 -0
- package/templates/react/media-workspace/src/lumen/adjustment-controls.tsx +61 -0
- package/templates/react/media-workspace/src/lumen/media-processing.tsx +43 -0
- package/templates/react/media-workspace/src/lumen/media-workspace.tsx +100 -0
- package/templates/react/operational-records/src/lumen/operational-records.tsx +92 -0
- package/templates/react/page-header/src/lumen/page-header.tsx +41 -0
- package/templates/react/project-workspace/src/lumen/project-workspace.tsx +112 -0
- package/templates/react/record-workspace/src/lumen/record-workspace.tsx +67 -0
- package/templates/react/review-workflow/src/lumen/review-workflow.tsx +202 -0
- package/templates/react/rich-text-editor/src/lumen/rich-text-editor.tsx +33 -0
- package/templates/react/saas-admin/src/lumen/saas-admin.tsx +119 -0
- package/templates/react/scheduler/src/lumen/scheduler.tsx +45 -0
- package/templates/react/section-header/src/lumen/section-header.tsx +33 -0
- package/templates/react/styles.d.ts +1 -0
- package/templates/react/theme-builder/src/lumen/theme-builder.tsx +57 -0
- package/templates/react/tsconfig.json +14 -0
- package/templates/react/validated-form/src/lumen/validated-form.tsx +166 -0
- package/templates/shared/common/src/lumen/lumen-template.css +247 -0
- package/templates/shared/media-workspace/src/lumen/media-workspace.css +14 -0
- package/templates/shared/visual-blocks/src/lumen/product-blocks.ts +224 -0
- package/v4-migration.json +448 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Badge, Button, Field, Label, Slider, Stack } from '@santi020k/lumen-astro'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
adjustmentId: string
|
|
6
|
+
label: string
|
|
7
|
+
value: number
|
|
8
|
+
defaultValue: number
|
|
9
|
+
min: number
|
|
10
|
+
max: number
|
|
11
|
+
step: number
|
|
12
|
+
unit?: string
|
|
13
|
+
locale?: string
|
|
14
|
+
disabled?: boolean
|
|
15
|
+
modifiedLabel: string
|
|
16
|
+
resetLabel: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare const Astro: Readonly<{ props: Props, slots: { has: (name: string) => boolean } }>
|
|
20
|
+
|
|
21
|
+
const { adjustmentId, label, value, defaultValue, min, max, step, unit = '', locale = 'en', disabled = false, modifiedLabel, resetLabel } = Astro.props
|
|
22
|
+
const id = `adjustment-${crypto.randomUUID()}`
|
|
23
|
+
let formatter: Intl.NumberFormat
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
formatter = new Intl.NumberFormat(locale, { maximumFractionDigits: 3 })
|
|
27
|
+
} catch {
|
|
28
|
+
formatter = new Intl.NumberFormat('en', { maximumFractionDigits: 3 })
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const format = (amount: number) => `${formatter.format(amount)}${unit}`
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
<Field data-media-adjustment={adjustmentId} data-default-value={defaultValue} data-unit={unit} data-locale={locale}>
|
|
35
|
+
<Stack direction="horizontal" align="center" justify="between" wrap>
|
|
36
|
+
<Label for={id}>{label}</Label><output id={`${id}-output`} for={id}>{format(value)}</output>
|
|
37
|
+
<Badge variant="secondary" hidden={value === defaultValue} data-adjustment-modified>{modifiedLabel}</Badge>
|
|
38
|
+
</Stack>
|
|
39
|
+
<Slider id={id} aria-describedby={`${id}-output`} aria-valuetext={format(value)} min={min} max={max} step={step} value={value} disabled={disabled} />
|
|
40
|
+
<Button variant="ghost" disabled={disabled || value === defaultValue} data-adjustment-reset>{resetLabel}</Button>
|
|
41
|
+
</Field>
|
|
42
|
+
|
|
43
|
+
<script>
|
|
44
|
+
for (const field of document.querySelectorAll<HTMLElement>('[data-media-adjustment]')) {
|
|
45
|
+
const slider = field.querySelector<HTMLInputElement>('input[type="range"]')
|
|
46
|
+
const output = field.querySelector('output')
|
|
47
|
+
const reset = field.querySelector<HTMLButtonElement>('button[data-adjustment-reset]')
|
|
48
|
+
const badge = field.querySelector<HTMLElement>('[data-adjustment-modified]')
|
|
49
|
+
|
|
50
|
+
if (!slider || !output || !reset || !badge) continue
|
|
51
|
+
|
|
52
|
+
let formatter: Intl.NumberFormat
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
formatter = new Intl.NumberFormat(field.dataset.locale, { maximumFractionDigits: 3 })
|
|
56
|
+
} catch {
|
|
57
|
+
formatter = new Intl.NumberFormat('en', { maximumFractionDigits: 3 })
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const update = () => {
|
|
61
|
+
const value = slider.valueAsNumber
|
|
62
|
+
const formatted = `${formatter.format(value)}${field.dataset.unit ?? ''}`
|
|
63
|
+
|
|
64
|
+
output.textContent = formatted
|
|
65
|
+
|
|
66
|
+
slider.ariaValueText = formatted
|
|
67
|
+
|
|
68
|
+
badge.hidden = value === Number(field.dataset.defaultValue)
|
|
69
|
+
|
|
70
|
+
reset.disabled = slider.disabled || badge.hidden
|
|
71
|
+
|
|
72
|
+
field.dispatchEvent(new CustomEvent('ui:adjustment-change', { bubbles: true, detail: { id: field.dataset.mediaAdjustment, value } }))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
slider.addEventListener('input', () => {
|
|
76
|
+
if (!slider.disabled) update()
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
reset.addEventListener('click', () => {
|
|
80
|
+
if (reset.disabled || slider.disabled) return
|
|
81
|
+
|
|
82
|
+
slider.value = field.dataset.defaultValue ?? '0'
|
|
83
|
+
|
|
84
|
+
update()
|
|
85
|
+
|
|
86
|
+
slider.focus()
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
</script>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Button, ErrorState, Progress, Stack } from '@santi020k/lumen-astro'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
phase: 'idle' | 'pending' | 'cancelled' | 'error' | 'success'
|
|
6
|
+
message: string
|
|
7
|
+
recovery?: string
|
|
8
|
+
progress?: number
|
|
9
|
+
progressLabel: string
|
|
10
|
+
startLabel: string
|
|
11
|
+
cancelLabel: string
|
|
12
|
+
retryLabel: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare const Astro: Readonly<{ props: Props, slots: { has: (name: string) => boolean } }>
|
|
16
|
+
|
|
17
|
+
const { phase, message, recovery, progress, progressLabel, startLabel, cancelLabel, retryLabel } = Astro.props
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<Stack gap="related" data-media-processing data-phase={phase}>
|
|
21
|
+
{phase === 'error' ? <ErrorState title={message} description={recovery} showGraphic={false} announce="polite" headingLevel={3}><Button data-media-processing-action="retry">{retryLabel}</Button></ErrorState> : <p role="status">{message}</p>}
|
|
22
|
+
{phase === 'pending' && (
|
|
23
|
+
<>
|
|
24
|
+
{progress !== undefined && Number.isFinite(progress) && <Progress aria-label={progressLabel} value={Math.min(100, Math.max(0, progress))} />}
|
|
25
|
+
<Button variant="outline" data-media-processing-action="cancel">{cancelLabel}</Button>
|
|
26
|
+
</>
|
|
27
|
+
)}
|
|
28
|
+
{phase !== 'pending' && phase !== 'error' && <Button data-media-processing-action="start">{startLabel}</Button>}
|
|
29
|
+
</Stack>
|
|
30
|
+
|
|
31
|
+
<script>
|
|
32
|
+
for (const panel of document.querySelectorAll<HTMLElement>('[data-media-processing]')) {
|
|
33
|
+
panel.addEventListener('click', event => {
|
|
34
|
+
if (!(event.target instanceof Element)) return
|
|
35
|
+
|
|
36
|
+
const button = event.target.closest<HTMLButtonElement>('button[data-media-processing-action]')
|
|
37
|
+
|
|
38
|
+
if (!button || button.disabled || !panel.contains(button)) return
|
|
39
|
+
|
|
40
|
+
const action = button.dataset.mediaProcessingAction
|
|
41
|
+
|
|
42
|
+
if (action !== 'start' && action !== 'cancel' && action !== 'retry') return
|
|
43
|
+
|
|
44
|
+
panel.dispatchEvent(new CustomEvent('ui:media-processing-request', { bubbles: true, detail: { action } }))
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
</script>
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Button, Card, Image, MediaFilmstrip, MediaThumbnail, Stack, Toolbar } from '@santi020k/lumen-astro'
|
|
3
|
+
import { resolveLumenMediaSelection } from '@santi020k/lumen-core'
|
|
4
|
+
|
|
5
|
+
interface MediaItem {
|
|
6
|
+
id: string
|
|
7
|
+
label: string
|
|
8
|
+
src: string
|
|
9
|
+
alt: string
|
|
10
|
+
width: number
|
|
11
|
+
height: number
|
|
12
|
+
disabled?: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
title: string
|
|
17
|
+
items: readonly MediaItem[]
|
|
18
|
+
selectedIds?: readonly string[]
|
|
19
|
+
collectionLabel: string
|
|
20
|
+
selectionLabel: string
|
|
21
|
+
toolsLabel: string
|
|
22
|
+
previewLabel: string
|
|
23
|
+
inspectorLabel: string
|
|
24
|
+
moveEarlierLabel: string
|
|
25
|
+
moveLaterLabel: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare const Astro: Readonly<{ props: Props, slots: { has: (name: string) => boolean } }>
|
|
29
|
+
|
|
30
|
+
const { title, items, selectedIds = [], collectionLabel, selectionLabel, toolsLabel, previewLabel, inspectorLabel, moveEarlierLabel, moveLaterLabel } = Astro.props
|
|
31
|
+
const selection = resolveLumenMediaSelection(items, selectedIds)
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
<section class="lumen-media-workspace" aria-label={title} data-media-workspace>
|
|
35
|
+
<h2>{title}</h2>
|
|
36
|
+
<div class="lumen-media-workspace__layout">
|
|
37
|
+
<div class="lumen-media-workspace__preview" role="group" aria-label={previewLabel}><slot name="preview" /></div>
|
|
38
|
+
<Card class="lumen-media-workspace__inspector" aria-label={inspectorLabel}><slot name="inspector" /></Card>
|
|
39
|
+
</div>
|
|
40
|
+
<Card glass="subtle" class="lumen-media-workspace__tools"><Toolbar aria-label={toolsLabel}><slot name="tools" /></Toolbar></Card>
|
|
41
|
+
<MediaFilmstrip label={collectionLabel} selectionLabel={selectionLabel}>
|
|
42
|
+
{items.map((item, index) => (
|
|
43
|
+
<li data-media-item={item.id}>
|
|
44
|
+
<MediaThumbnail label={item.label} mediaId={item.id} selected={selection.includes(item.id)} order={index + 1} disabled={item.disabled}>
|
|
45
|
+
<Image src={item.src} alt={item.alt} width={item.width} height={item.height} />
|
|
46
|
+
</MediaThumbnail>
|
|
47
|
+
<Stack gap="related">
|
|
48
|
+
<Button variant="outline" aria-label={`${moveEarlierLabel}: ${item.label}`} disabled={item.disabled === true || index === 0} data-media-move="earlier" data-media-id={item.id}>{moveEarlierLabel}</Button>
|
|
49
|
+
<Button variant="outline" aria-label={`${moveLaterLabel}: ${item.label}`} disabled={item.disabled === true || index === items.length - 1} data-media-move="later" data-media-id={item.id}>{moveLaterLabel}</Button>
|
|
50
|
+
</Stack>
|
|
51
|
+
</li>
|
|
52
|
+
))}
|
|
53
|
+
</MediaFilmstrip>
|
|
54
|
+
<Card class="lumen-media-workspace__bottom"><slot name="bottom-controls" /></Card>
|
|
55
|
+
</section>
|
|
56
|
+
|
|
57
|
+
<script>
|
|
58
|
+
// Import media-workspace.css once at the application's style boundary.
|
|
59
|
+
// Selection and move requests remain controlled by the host. Accept them only after
|
|
60
|
+
// validating permissions and updating canonical state; keep focus on the same stable ID.
|
|
61
|
+
for (const workspace of document.querySelectorAll<HTMLElement>('[data-media-workspace]')) {
|
|
62
|
+
workspace.addEventListener('click', event => {
|
|
63
|
+
if (!(event.target instanceof Element)) return
|
|
64
|
+
|
|
65
|
+
const button = event.target.closest<HTMLButtonElement>('button[data-media-move]')
|
|
66
|
+
|
|
67
|
+
if (!button || button.disabled || !workspace.contains(button)) return
|
|
68
|
+
|
|
69
|
+
const id = button.dataset.mediaId
|
|
70
|
+
const direction = button.dataset.mediaMove
|
|
71
|
+
|
|
72
|
+
if (!id || (direction !== 'earlier' && direction !== 'later')) return
|
|
73
|
+
|
|
74
|
+
workspace.dispatchEvent(new CustomEvent('ui:media-move-request', { bubbles: true, detail: { id, direction } }))
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
</script>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Badge, Breadcrumb, Link, Stack, Typography } from '@santi020k/lumen-astro'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
actionsLabel?: string
|
|
6
|
+
breadcrumbLabel?: string
|
|
7
|
+
breadcrumbs?: readonly { href: string, label: string }[]
|
|
8
|
+
description?: string
|
|
9
|
+
headingId: string
|
|
10
|
+
status?: string
|
|
11
|
+
title: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
declare const Astro: Readonly<{ props: Props, slots: { has: (name: string) => boolean } }>
|
|
15
|
+
|
|
16
|
+
const { actionsLabel = 'Page actions', breadcrumbLabel = 'Breadcrumb', breadcrumbs = [], description, headingId, status, title } = Astro.props
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
<header aria-labelledby={headingId}>
|
|
20
|
+
<Stack gap="group">
|
|
21
|
+
{breadcrumbs.length > 0 && (
|
|
22
|
+
<Breadcrumb aria-label={breadcrumbLabel}>
|
|
23
|
+
<ol>
|
|
24
|
+
{breadcrumbs.map(item => <li><Link href={item.href}>{item.label}</Link></li>)}
|
|
25
|
+
<li aria-current="page">{title}</li>
|
|
26
|
+
</ol>
|
|
27
|
+
</Breadcrumb>
|
|
28
|
+
)}
|
|
29
|
+
<Stack direction="horizontal" align="start" justify="between" gap="group" wrap>
|
|
30
|
+
<Stack class="header-identity" gap="related">
|
|
31
|
+
<Typography><h1 id={headingId}>{title}</h1>{description && <p>{description}</p>}</Typography>
|
|
32
|
+
{status && <Badge variant="outline" style="align-self: flex-start">{status}</Badge>}
|
|
33
|
+
</Stack>
|
|
34
|
+
{Astro.slots.has('actions') && <Stack direction="horizontal" align="center" gap="related" wrap role="group" aria-label={actionsLabel}><slot name="actions" /></Stack>}
|
|
35
|
+
</Stack>
|
|
36
|
+
</Stack>
|
|
37
|
+
</header>
|
|
38
|
+
|
|
39
|
+
<style>
|
|
40
|
+
.header-identity { flex: 1 1 20rem; min-width: 0; overflow-wrap: anywhere; }
|
|
41
|
+
</style>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
import './lumen-template.css'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
Badge,
|
|
6
|
+
Button,
|
|
7
|
+
Card,
|
|
8
|
+
Progress,
|
|
9
|
+
Sidebar,
|
|
10
|
+
Stat,
|
|
11
|
+
Table,
|
|
12
|
+
Timeline,
|
|
13
|
+
TimelineItem
|
|
14
|
+
} from '@santi020k/lumen-astro'
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<div class="lumen-template lumen-template__shell">
|
|
18
|
+
<Sidebar class="lumen-template__sidebar">
|
|
19
|
+
<strong>Relay Projects</strong>
|
|
20
|
+
<nav aria-label="Projects">
|
|
21
|
+
<a aria-current="page" href="#overview">Overview</a>
|
|
22
|
+
<a href="#projects">Projects</a>
|
|
23
|
+
<a href="#activity">Activity</a>
|
|
24
|
+
</nav>
|
|
25
|
+
</Sidebar>
|
|
26
|
+
<main class="lumen-template__main" id="overview">
|
|
27
|
+
<header class="lumen-template__header">
|
|
28
|
+
<div>
|
|
29
|
+
<Badge variant="outline">Team delivery</Badge>
|
|
30
|
+
<h1>Team workspace</h1>
|
|
31
|
+
<p>Priorities, delivery health, and next decisions.</p>
|
|
32
|
+
</div>
|
|
33
|
+
<Button>New project</Button>
|
|
34
|
+
</header>
|
|
35
|
+
<section class="lumen-template__metrics" aria-label="Delivery metrics">
|
|
36
|
+
<Card class="lumen-template__metric">
|
|
37
|
+
<Stat label="Open tasks" value="42" />
|
|
38
|
+
<Badge variant="warning">6 due soon</Badge>
|
|
39
|
+
</Card>
|
|
40
|
+
<Card class="lumen-template__metric">
|
|
41
|
+
<Stat label="Milestones reached" value="18" />
|
|
42
|
+
<Badge variant="success">+4</Badge>
|
|
43
|
+
</Card>
|
|
44
|
+
<Card class="lumen-template__metric">
|
|
45
|
+
<Stat label="At-risk projects" value="2" />
|
|
46
|
+
<Badge variant="destructive">Needs help</Badge>
|
|
47
|
+
</Card>
|
|
48
|
+
<Card class="lumen-template__metric">
|
|
49
|
+
<Stat label="Delivery velocity" value="46 pts" />
|
|
50
|
+
<Badge variant="success">+6.4%</Badge>
|
|
51
|
+
</Card>
|
|
52
|
+
</section>
|
|
53
|
+
<section class="lumen-template__grid">
|
|
54
|
+
<Card class="lumen-template__panel">
|
|
55
|
+
<h2>Active workstreams</h2>
|
|
56
|
+
<p>Mobile checkout · 72%</p>
|
|
57
|
+
<Progress aria-label="Mobile checkout is 72% complete" value={72} />
|
|
58
|
+
<p>Billing migration · 54%</p>
|
|
59
|
+
<Progress aria-label="Billing migration is 54% complete" value={54} />
|
|
60
|
+
</Card>
|
|
61
|
+
<Card class="lumen-template__panel" id="activity">
|
|
62
|
+
<h2>Recent activity</h2>
|
|
63
|
+
<Timeline>
|
|
64
|
+
<TimelineItem>Amina completed checkout validation</TimelineItem>
|
|
65
|
+
<TimelineItem>Jon reviewed billing retries</TimelineItem>
|
|
66
|
+
<TimelineItem>Nora moved tokens to review</TimelineItem>
|
|
67
|
+
</Timeline>
|
|
68
|
+
</Card>
|
|
69
|
+
</section>
|
|
70
|
+
<Card class="lumen-template__panel" id="projects">
|
|
71
|
+
<div class="lumen-template__section-header">
|
|
72
|
+
<h2>Priority projects</h2>
|
|
73
|
+
<Button variant="ghost">View all</Button>
|
|
74
|
+
</div>
|
|
75
|
+
<Table class="lumen-template__table">
|
|
76
|
+
<table>
|
|
77
|
+
<thead>
|
|
78
|
+
<tr>
|
|
79
|
+
<th>Project</th>
|
|
80
|
+
<th>Owner</th>
|
|
81
|
+
<th>Status</th>
|
|
82
|
+
<th>Progress</th>
|
|
83
|
+
</tr>
|
|
84
|
+
</thead>
|
|
85
|
+
<tbody>
|
|
86
|
+
<tr>
|
|
87
|
+
<td>Mobile checkout</td>
|
|
88
|
+
<td>Amina</td>
|
|
89
|
+
<td><Badge variant="success">Active</Badge></td>
|
|
90
|
+
<td>72%</td>
|
|
91
|
+
</tr>
|
|
92
|
+
<tr>
|
|
93
|
+
<td>Billing migration</td>
|
|
94
|
+
<td>Jon</td>
|
|
95
|
+
<td><Badge variant="destructive">At risk</Badge></td>
|
|
96
|
+
<td>54%</td>
|
|
97
|
+
</tr>
|
|
98
|
+
</tbody>
|
|
99
|
+
</table>
|
|
100
|
+
</Table>
|
|
101
|
+
</Card>
|
|
102
|
+
</main>
|
|
103
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
ButtonGroup,
|
|
5
|
+
RichTextEditor,
|
|
6
|
+
Textarea,
|
|
7
|
+
ToggleGroup
|
|
8
|
+
} from '@santi020k/lumen-astro'
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<RichTextEditor class="lumen-recipe lumen-recipe--rich-text-editor">
|
|
12
|
+
<div role="toolbar" aria-label="Editor toolbar">
|
|
13
|
+
<ButtonGroup>
|
|
14
|
+
<Button data-ui-editor-command="bold" type="button">Bold</Button>
|
|
15
|
+
<Button data-ui-editor-command="italic" type="button">Italic</Button>
|
|
16
|
+
</ButtonGroup>
|
|
17
|
+
<ToggleGroup><button data-ui-editor-command="insertUnorderedList" type="button">List</button></ToggleGroup>
|
|
18
|
+
</div>
|
|
19
|
+
<div contenteditable="true">Draft release notes...</div>
|
|
20
|
+
<Textarea name="fallback" placeholder="Plain text fallback" />
|
|
21
|
+
</RichTextEditor>
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
import './lumen-template.css'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
Alert,
|
|
6
|
+
Badge,
|
|
7
|
+
Button,
|
|
8
|
+
Card,
|
|
9
|
+
Progress,
|
|
10
|
+
SearchField,
|
|
11
|
+
Sidebar,
|
|
12
|
+
Stat,
|
|
13
|
+
Table
|
|
14
|
+
} from '@santi020k/lumen-astro'
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<div class="lumen-template lumen-template__shell">
|
|
18
|
+
<Sidebar class="lumen-template__sidebar">
|
|
19
|
+
<strong>Orbit Admin</strong>
|
|
20
|
+
<nav aria-label="Administration">
|
|
21
|
+
<a aria-current="page" href="#overview">Overview</a>
|
|
22
|
+
<a href="#members">Members</a>
|
|
23
|
+
<a href="#billing">Billing</a>
|
|
24
|
+
</nav>
|
|
25
|
+
</Sidebar>
|
|
26
|
+
<main class="lumen-template__main" id="overview">
|
|
27
|
+
<header class="lumen-template__header">
|
|
28
|
+
<div>
|
|
29
|
+
<Badge variant="outline">Workspace administration</Badge>
|
|
30
|
+
<h1>Good morning, Maya</h1>
|
|
31
|
+
<p>Access, billing, and operational health.</p>
|
|
32
|
+
</div>
|
|
33
|
+
<Button>Invite members</Button>
|
|
34
|
+
</header>
|
|
35
|
+
<Alert>
|
|
36
|
+
<strong>Quarterly access review is ready.</strong>
|
|
37
|
+
{' '}
|
|
38
|
+
Confirm eight elevated roles before July 12.
|
|
39
|
+
</Alert>
|
|
40
|
+
<section class="lumen-template__metrics" aria-label="Workspace metrics">
|
|
41
|
+
<Card class="lumen-template__metric">
|
|
42
|
+
<Stat label="Workspace members" value="248" />
|
|
43
|
+
<Badge variant="success">+24</Badge>
|
|
44
|
+
</Card>
|
|
45
|
+
<Card class="lumen-template__metric">
|
|
46
|
+
<Stat label="Seat activation" value="91%" />
|
|
47
|
+
<Badge variant="success">Healthy</Badge>
|
|
48
|
+
</Card>
|
|
49
|
+
<Card class="lumen-template__metric">
|
|
50
|
+
<Stat label="Access reviews" value="8" />
|
|
51
|
+
<Badge variant="warning">3 pending</Badge>
|
|
52
|
+
</Card>
|
|
53
|
+
<Card class="lumen-template__metric">
|
|
54
|
+
<Stat label="Availability" value="99.99%" />
|
|
55
|
+
<Badge variant="success">Normal</Badge>
|
|
56
|
+
</Card>
|
|
57
|
+
</section>
|
|
58
|
+
<section class="lumen-template__grid" id="billing">
|
|
59
|
+
<Card class="lumen-template__panel">
|
|
60
|
+
<h2>Plan utilization</h2>
|
|
61
|
+
<Stat label="Seats used" value="248 / 300" />
|
|
62
|
+
<Progress aria-label="248 of 300 seats used" max={300} value={248} />
|
|
63
|
+
<p class="lumen-template__muted">52 seats available</p>
|
|
64
|
+
</Card>
|
|
65
|
+
<Card class="lumen-template__panel">
|
|
66
|
+
<h2>Security posture</h2>
|
|
67
|
+
<ul class="lumen-template__list">
|
|
68
|
+
<li>Single sign-on enforced</li>
|
|
69
|
+
<li>Domain verification complete</li>
|
|
70
|
+
<li>3 recovery codes need rotation</li>
|
|
71
|
+
</ul>
|
|
72
|
+
</Card>
|
|
73
|
+
</section>
|
|
74
|
+
<Card class="lumen-template__panel" id="members">
|
|
75
|
+
<div class="lumen-template__section-header">
|
|
76
|
+
<div>
|
|
77
|
+
<h2>Recently active members</h2>
|
|
78
|
+
<p>Access changes from the last 30 days.</p>
|
|
79
|
+
</div>
|
|
80
|
+
<SearchField aria-label="Search members" placeholder="Search members" />
|
|
81
|
+
</div>
|
|
82
|
+
<Table class="lumen-template__table">
|
|
83
|
+
<table>
|
|
84
|
+
<thead>
|
|
85
|
+
<tr>
|
|
86
|
+
<th>Member</th>
|
|
87
|
+
<th>Team</th>
|
|
88
|
+
<th>Status</th>
|
|
89
|
+
<th>Role</th>
|
|
90
|
+
</tr>
|
|
91
|
+
</thead>
|
|
92
|
+
<tbody>
|
|
93
|
+
<tr>
|
|
94
|
+
<td>Amina Bello</td>
|
|
95
|
+
<td>Design</td>
|
|
96
|
+
<td><Badge variant="success">Active</Badge></td>
|
|
97
|
+
<td>Admin</td>
|
|
98
|
+
</tr>
|
|
99
|
+
<tr>
|
|
100
|
+
<td>Theo Martin</td>
|
|
101
|
+
<td>Success</td>
|
|
102
|
+
<td><Badge variant="warning">Pending</Badge></td>
|
|
103
|
+
<td>Member</td>
|
|
104
|
+
</tr>
|
|
105
|
+
</tbody>
|
|
106
|
+
</table>
|
|
107
|
+
</Table>
|
|
108
|
+
</Card>
|
|
109
|
+
</main>
|
|
110
|
+
</div>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
Agenda,
|
|
4
|
+
Calendar,
|
|
5
|
+
DatePicker,
|
|
6
|
+
Schedule
|
|
7
|
+
} from '@santi020k/lumen-astro'
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<section class="lumen-recipe lumen-recipe--scheduler">
|
|
11
|
+
<Calendar aria-label="Choose schedule date" />
|
|
12
|
+
<DatePicker aria-label="Jump to date" />
|
|
13
|
+
<Schedule>
|
|
14
|
+
<header><h2>Launch week</h2></header>
|
|
15
|
+
<div data-ui-schedule-grid>
|
|
16
|
+
<section data-ui-schedule-slot="monday">
|
|
17
|
+
<article id="schedule-planning" data-ui-draggable="true" data-ui-schedule-event>Planning</article>
|
|
18
|
+
</section>
|
|
19
|
+
<section data-ui-schedule-slot="friday">
|
|
20
|
+
<article id="schedule-ship" data-ui-draggable="true" data-ui-schedule-event>Ship</article>
|
|
21
|
+
</section>
|
|
22
|
+
</div>
|
|
23
|
+
</Schedule>
|
|
24
|
+
<Agenda>
|
|
25
|
+
<ol>
|
|
26
|
+
<li>
|
|
27
|
+
<strong>Design review</strong>
|
|
28
|
+
<span>10:00</span>
|
|
29
|
+
</li>
|
|
30
|
+
<li>
|
|
31
|
+
<strong>Release notes</strong>
|
|
32
|
+
<span>14:30</span>
|
|
33
|
+
</li>
|
|
34
|
+
</ol>
|
|
35
|
+
</Agenda>
|
|
36
|
+
</section>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Badge, Stack, Typography } from '@santi020k/lumen-astro'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
actionsLabel?: string
|
|
6
|
+
count?: string
|
|
7
|
+
description?: string
|
|
8
|
+
headingId: string
|
|
9
|
+
level?: 2 | 3 | 4 | 5 | 6
|
|
10
|
+
title: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
declare const Astro: Readonly<{ props: Props, slots: { has: (name: string) => boolean } }>
|
|
14
|
+
|
|
15
|
+
const { actionsLabel = 'Section actions', count, description, headingId, level = 2, title } = Astro.props
|
|
16
|
+
const headings = { 2: 'h2', 3: 'h3', 4: 'h4', 5: 'h5', 6: 'h6' } as const
|
|
17
|
+
const Heading = headings[level]
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<header aria-labelledby={headingId}>
|
|
21
|
+
<Stack direction="horizontal" align="start" justify="between" gap="group" wrap>
|
|
22
|
+
<Stack class="header-identity" gap="related">
|
|
23
|
+
<Stack direction="horizontal" align="center" gap="related" wrap>
|
|
24
|
+
<Typography><Heading id={headingId}>{title}</Heading></Typography>
|
|
25
|
+
{count !== undefined && <Badge variant="secondary">{count}</Badge>}
|
|
26
|
+
</Stack>
|
|
27
|
+
{description && <Typography><p>{description}</p></Typography>}
|
|
28
|
+
</Stack>
|
|
29
|
+
{Astro.slots.has('actions') && <Stack direction="horizontal" align="center" gap="related" wrap role="group" aria-label={actionsLabel}><slot name="actions" /></Stack>}
|
|
30
|
+
</Stack>
|
|
31
|
+
</header>
|
|
32
|
+
|
|
33
|
+
<style>
|
|
34
|
+
.header-identity { flex: 1 1 20rem; min-width: 0; overflow-wrap: anywhere; }
|
|
35
|
+
</style>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
Card,
|
|
5
|
+
ColorPicker,
|
|
6
|
+
Input,
|
|
7
|
+
ThemeBuilder
|
|
8
|
+
} from '@santi020k/lumen-astro'
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<ThemeBuilder class="lumen-recipe lumen-recipe--theme-builder" data-ui-theme-target="#lumen-theme-preview">
|
|
12
|
+
<header>
|
|
13
|
+
<h2>Brand theme</h2>
|
|
14
|
+
<Button data-ui-theme-export type="button">Copy CSS</Button>
|
|
15
|
+
</header>
|
|
16
|
+
<Card id="lumen-theme-preview" style="display: flex; gap: 0.5rem;">
|
|
17
|
+
<span data-ui-swatch style="--ui-swatch:hsl(var(--brand))"></span>
|
|
18
|
+
<span data-ui-swatch style="--ui-swatch:hsl(var(--accent))"></span>
|
|
19
|
+
</Card>
|
|
20
|
+
<Card>
|
|
21
|
+
<Button aria-pressed="true" data-ui-theme-mode="generated" type="button" variant="secondary">Generated</Button>
|
|
22
|
+
<Button aria-pressed="false" data-ui-theme-mode="manual" type="button" variant="outline">Manual</Button>
|
|
23
|
+
<Input aria-label="Brand hue" data-ui-theme-brand-hue max="359" min="0" type="range" value="264" />
|
|
24
|
+
<ColorPicker aria-label="Manual brand color" data-ui-theme-primary-color value="#6f20f0" />
|
|
25
|
+
<Input aria-label="Manual brand hex" data-ui-theme-primary-hex value="#6f20f0" />
|
|
26
|
+
</Card>
|
|
27
|
+
<textarea data-ui-theme-output aria-label="Theme CSS"></textarea>
|
|
28
|
+
</ThemeBuilder>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script type="module">
|
|
2
|
+
import { defineLumenElements } from '@santi020k/lumen-elements/define'
|
|
3
|
+
|
|
4
|
+
defineLumenElements()
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<form class="lumen-recipe lumen-recipe--advanced-fields">
|
|
8
|
+
<lumen-search-field name="q" placeholder="Search records"></lumen-search-field>
|
|
9
|
+
<lumen-autocomplete list="assignees" placeholder="Assign to..."></lumen-autocomplete>
|
|
10
|
+
<datalist id="assignees">
|
|
11
|
+
<option value="Design"></option>
|
|
12
|
+
<option value="Engineering"></option>
|
|
13
|
+
<option value="Operations"></option>
|
|
14
|
+
</datalist>
|
|
15
|
+
<lumen-number-field aria-label="Seats" min="1" value="3"></lumen-number-field>
|
|
16
|
+
<lumen-time-field aria-label="Start time" value="09:30"></lumen-time-field>
|
|
17
|
+
<lumen-date-range-picker>
|
|
18
|
+
<lumen-date-picker aria-label="Start date"></lumen-date-picker>
|
|
19
|
+
<lumen-date-picker aria-label="End date"></lumen-date-picker>
|
|
20
|
+
</lumen-date-range-picker>
|
|
21
|
+
<lumen-color-picker aria-label="Brand color" value="#2563eb"></lumen-color-picker>
|
|
22
|
+
<lumen-tag-group aria-label="Selected filters">
|
|
23
|
+
<span data-ui-tag role="listitem">Active <button data-ui-tag-remove type="button">Remove</button></span>
|
|
24
|
+
</lumen-tag-group>
|
|
25
|
+
</form>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<link rel="stylesheet" href="./lumen-template.css" />
|
|
2
|
+
|
|
3
|
+
<script type="module">
|
|
4
|
+
import { defineLumenElements } from '@santi020k/lumen-elements/define'
|
|
5
|
+
|
|
6
|
+
defineLumenElements()
|
|
7
|
+
|
|
8
|
+
const revenue = document.querySelector('#analytics-revenue')
|
|
9
|
+
const channels = document.querySelector('#analytics-channels')
|
|
10
|
+
|
|
11
|
+
if (revenue) revenue.series = [{ data: [{ x: 'Jan', y: 118 }, { x: 'Feb', y: 126 }, { x: 'Mar', y: 132 }, { x: 'Apr', y: 148 }, { x: 'May', y: 162 }, { x: 'Jun', y: 184 }], id: 'revenue', label: 'Revenue', tone: 'brand' }]
|
|
12
|
+
if (channels) channels.series = [{ data: [{ x: 'Organic', y: 4820 }, { x: 'Referral', y: 3180 }, { x: 'Paid', y: 2640 }], id: 'visitors', label: 'Visitors', tone: 'brand' }]
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<div class="lumen-template lumen-template__shell">
|
|
16
|
+
<lumen-sidebar class="lumen-template__sidebar"><strong>Pulse Analytics</strong><nav aria-label="Analytics"><a aria-current="page" href="#overview">Overview</a><a href="#acquisition">Acquisition</a><a href="#accounts">Accounts</a></nav></lumen-sidebar>
|
|
17
|
+
<main class="lumen-template__main" id="overview">
|
|
18
|
+
<header class="lumen-template__header"><div><lumen-badge variant="outline">Jun 1–30</lumen-badge><h1>Growth overview</h1><p>Revenue, retention, and account health.</p></div><lumen-button>Export report</lumen-button></header>
|
|
19
|
+
<section class="lumen-template__metrics" aria-label="Key metrics">
|
|
20
|
+
<lumen-card class="lumen-template__metric"><lumen-stat label="Monthly revenue" value="$184,320"></lumen-stat><lumen-badge variant="success">+12.4%</lumen-badge></lumen-card>
|
|
21
|
+
<lumen-card class="lumen-template__metric"><lumen-stat label="Active accounts" value="12,480"></lumen-stat><lumen-badge variant="success">+8.2%</lumen-badge></lumen-card>
|
|
22
|
+
<lumen-card class="lumen-template__metric"><lumen-stat label="Customer churn" value="2.8%"></lumen-stat><lumen-badge variant="success">-1.6%</lumen-badge></lumen-card>
|
|
23
|
+
<lumen-card class="lumen-template__metric"><lumen-stat label="Net retention" value="116%"></lumen-stat><lumen-badge variant="success">+3.1%</lumen-badge></lumen-card>
|
|
24
|
+
</section>
|
|
25
|
+
<section class="lumen-template__grid" id="acquisition"><lumen-line-chart area heading="Revenue trajectory" id="analytics-revenue"></lumen-line-chart><lumen-bar-chart heading="Channel performance" id="analytics-channels"></lumen-bar-chart></section>
|
|
26
|
+
<lumen-card class="lumen-template__panel" id="accounts"><div class="lumen-template__section-header"><h2>Accounts to watch</h2><lumen-button variant="ghost">View all</lumen-button></div><lumen-table class="lumen-template__table"><table><thead><tr><th>Account</th><th>Plan</th><th>Status</th><th>Value</th></tr></thead><tbody><tr><td>Northstar Labs</td><td>Enterprise</td><td><lumen-badge variant="success">Active</lumen-badge></td><td>$18,400</td></tr><tr><td>Arc & Field</td><td>Enterprise</td><td><lumen-badge variant="destructive">At risk</lumen-badge></td><td>$14,780</td></tr></tbody></table></lumen-table></lumen-card>
|
|
27
|
+
</main>
|
|
28
|
+
</div>
|