@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.
Files changed (125) hide show
  1. package/README.md +211 -3
  2. package/dist/cli.js +49 -5
  3. package/dist/consumer-upgrade-audit.d.ts +10 -0
  4. package/dist/consumer-upgrade-audit.d.ts.map +1 -0
  5. package/dist/consumer-upgrade-audit.js +52 -0
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +3 -0
  9. package/dist/installer.d.ts.map +1 -1
  10. package/dist/installer.js +16 -0
  11. package/dist/integration-diagnostics.d.ts.map +1 -1
  12. package/dist/integration-diagnostics.js +199 -3
  13. package/dist/registry-component-name.d.ts +2 -0
  14. package/dist/registry-component-name.d.ts.map +1 -0
  15. package/dist/registry-component-name.js +53 -0
  16. package/dist/registry-data.d.ts +339 -18
  17. package/dist/registry-data.d.ts.map +1 -1
  18. package/dist/registry-data.js +789 -3
  19. package/dist/registry.d.ts.map +1 -1
  20. package/dist/registry.js +11 -9
  21. package/dist/source-script-ranges.d.ts +3 -0
  22. package/dist/source-script-ranges.d.ts.map +1 -0
  23. package/dist/source-script-ranges.js +41 -0
  24. package/dist/v2-migration.d.ts +38 -0
  25. package/dist/v2-migration.d.ts.map +1 -1
  26. package/dist/v2-migration.js +26 -14
  27. package/dist/v4-migration.d.ts +26 -0
  28. package/dist/v4-migration.d.ts.map +1 -0
  29. package/dist/v4-migration.js +272 -0
  30. package/dist/version-migration-dependencies.d.ts +8 -0
  31. package/dist/version-migration-dependencies.d.ts.map +1 -0
  32. package/dist/version-migration-dependencies.js +10 -0
  33. package/dist/version-migration-source.d.ts +4 -0
  34. package/dist/version-migration-source.d.ts.map +1 -0
  35. package/dist/version-migration-source.js +281 -0
  36. package/dist/version-migration.d.ts +34 -0
  37. package/dist/version-migration.d.ts.map +1 -0
  38. package/dist/version-migration.js +158 -0
  39. package/native-components.json +564 -17
  40. package/package.json +26 -11
  41. package/release-manifest.json +22 -17
  42. package/styles/critical.css +696 -66
  43. package/styles/motion.css +61 -0
  44. package/styles/world-map.css +30 -0
  45. package/styles.css +1756 -409
  46. package/templates/astro/advanced-fields/src/lumen/advanced-fields.astro +35 -0
  47. package/templates/astro/ai-docs/llms.txt +3 -0
  48. package/templates/astro/analytics-dashboard/src/lumen/analytics-dashboard.astro +110 -0
  49. package/templates/astro/auth-onboarding/src/lumen/auth-onboarding.astro +107 -0
  50. package/templates/astro/command-center/src/lumen/command-center.astro +34 -0
  51. package/templates/astro/commerce-dashboard/src/lumen/commerce-dashboard.astro +108 -0
  52. package/templates/astro/content-flow-actions/src/lumen/content-flow-actions.astro +10 -0
  53. package/templates/astro/content-flow-header/src/lumen/content-flow-header.astro +14 -0
  54. package/templates/astro/content-flow-list/src/lumen/content-flow-list.astro +13 -0
  55. package/templates/astro/content-flow-settings/src/lumen/content-flow-settings.astro +17 -0
  56. package/templates/astro/data-collections/src/lumen/data-collections.astro +52 -0
  57. package/templates/astro/feature-preview/src/lumen/feature-preview.astro +32 -0
  58. package/templates/astro/guided-onboarding/src/lumen/guided-onboarding.astro +35 -0
  59. package/templates/astro/interactive-pricing/src/lumen/interactive-pricing.astro +32 -0
  60. package/templates/astro/media-workspace/src/lumen/adjustment-controls.astro +89 -0
  61. package/templates/astro/media-workspace/src/lumen/media-processing.astro +47 -0
  62. package/templates/astro/media-workspace/src/lumen/media-workspace.astro +77 -0
  63. package/templates/astro/page-header/src/lumen/page-header.astro +41 -0
  64. package/templates/astro/project-workspace/src/lumen/project-workspace.astro +103 -0
  65. package/templates/astro/rich-text-editor/src/lumen/rich-text-editor.astro +21 -0
  66. package/templates/astro/saas-admin/src/lumen/saas-admin.astro +110 -0
  67. package/templates/astro/scheduler/src/lumen/scheduler.astro +36 -0
  68. package/templates/astro/section-header/src/lumen/section-header.astro +35 -0
  69. package/templates/astro/theme-builder/src/lumen/theme-builder.astro +28 -0
  70. package/templates/elements/advanced-fields/src/lumen/advanced-fields.html +25 -0
  71. package/templates/elements/analytics-dashboard/src/lumen/analytics-dashboard.html +28 -0
  72. package/templates/elements/auth-onboarding/src/lumen/auth-onboarding.html +79 -0
  73. package/templates/elements/command-center/src/lumen/command-center.html +15 -0
  74. package/templates/elements/commerce-dashboard/src/lumen/commerce-dashboard.html +24 -0
  75. package/templates/elements/content-flow-actions/src/lumen/content-flow-actions.html +11 -0
  76. package/templates/elements/content-flow-header/src/lumen/content-flow-header.html +15 -0
  77. package/templates/elements/content-flow-list/src/lumen/content-flow-list.html +14 -0
  78. package/templates/elements/content-flow-settings/src/lumen/content-flow-settings.html +18 -0
  79. package/templates/elements/data-collections/src/lumen/data-collections.html +31 -0
  80. package/templates/elements/feature-preview/src/lumen/feature-preview.html +13 -0
  81. package/templates/elements/guided-onboarding/src/lumen/guided-onboarding.html +16 -0
  82. package/templates/elements/interactive-pricing/src/lumen/interactive-pricing.html +13 -0
  83. package/templates/elements/media-workspace/src/lumen/media-workspace.html +57 -0
  84. package/templates/elements/media-workspace/src/lumen/media-workspace.ts +163 -0
  85. package/templates/elements/page-header/src/lumen/page-header.html +20 -0
  86. package/templates/elements/project-workspace/src/lumen/project-workspace.html +17 -0
  87. package/templates/elements/rich-text-editor/src/lumen/rich-text-editor.html +17 -0
  88. package/templates/elements/saas-admin/src/lumen/saas-admin.html +18 -0
  89. package/templates/elements/scheduler/src/lumen/scheduler.html +27 -0
  90. package/templates/elements/section-header/src/lumen/section-header.html +21 -0
  91. package/templates/elements/theme-builder/src/lumen/theme-builder.html +59 -0
  92. package/templates/react/advanced-fields/src/lumen/advanced-fields.tsx +37 -0
  93. package/templates/react/analytics-dashboard/src/lumen/analytics-dashboard.tsx +143 -0
  94. package/templates/react/auth-onboarding/src/lumen/auth-onboarding.tsx +129 -0
  95. package/templates/react/command-center/src/lumen/command-center.tsx +85 -0
  96. package/templates/react/commerce-dashboard/src/lumen/commerce-dashboard.tsx +148 -0
  97. package/templates/react/content-flow-actions/src/lumen/content-flow-actions.tsx +11 -0
  98. package/templates/react/content-flow-header/src/lumen/content-flow-header.tsx +14 -0
  99. package/templates/react/content-flow-list/src/lumen/content-flow-list.tsx +19 -0
  100. package/templates/react/content-flow-settings/src/lumen/content-flow-settings.tsx +26 -0
  101. package/templates/react/data-collections/src/lumen/data-collections.tsx +60 -0
  102. package/templates/react/feature-preview/src/lumen/feature-preview.tsx +42 -0
  103. package/templates/react/guided-onboarding/src/lumen/guided-onboarding.tsx +100 -0
  104. package/templates/react/import-review/src/lumen/import-review.tsx +150 -0
  105. package/templates/react/interactive-pricing/src/lumen/interactive-pricing.tsx +60 -0
  106. package/templates/react/media-workspace/src/lumen/adjustment-controls.tsx +61 -0
  107. package/templates/react/media-workspace/src/lumen/media-processing.tsx +43 -0
  108. package/templates/react/media-workspace/src/lumen/media-workspace.tsx +100 -0
  109. package/templates/react/operational-records/src/lumen/operational-records.tsx +92 -0
  110. package/templates/react/page-header/src/lumen/page-header.tsx +41 -0
  111. package/templates/react/project-workspace/src/lumen/project-workspace.tsx +112 -0
  112. package/templates/react/record-workspace/src/lumen/record-workspace.tsx +67 -0
  113. package/templates/react/review-workflow/src/lumen/review-workflow.tsx +202 -0
  114. package/templates/react/rich-text-editor/src/lumen/rich-text-editor.tsx +33 -0
  115. package/templates/react/saas-admin/src/lumen/saas-admin.tsx +119 -0
  116. package/templates/react/scheduler/src/lumen/scheduler.tsx +45 -0
  117. package/templates/react/section-header/src/lumen/section-header.tsx +33 -0
  118. package/templates/react/styles.d.ts +1 -0
  119. package/templates/react/theme-builder/src/lumen/theme-builder.tsx +57 -0
  120. package/templates/react/tsconfig.json +14 -0
  121. package/templates/react/validated-form/src/lumen/validated-form.tsx +166 -0
  122. package/templates/shared/common/src/lumen/lumen-template.css +247 -0
  123. package/templates/shared/media-workspace/src/lumen/media-workspace.css +14 -0
  124. package/templates/shared/visual-blocks/src/lumen/product-blocks.ts +224 -0
  125. 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>