@lukeashford/aurelius 4.5.0 → 4.6.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.
@@ -8,5 +8,6 @@
8
8
  @import './fonts.css';
9
9
  @import './theme.css';
10
10
  @import './prose.css';
11
+ @import './deliverable.css';
11
12
 
12
13
  @plugin "@tailwindcss/typography";
@@ -0,0 +1,476 @@
1
+ /* Deliverable renderer styles.
2
+ *
3
+ * Each visual class is defined as a Tailwind v4 `@utility` so the design-system
4
+ * ESLint rule recognises them. The same DOM serves both the on-screen view
5
+ * and the PDF print path; `@page` and `@media print` rules below replace the
6
+ * dark theme with a print-friendly version (black on white, page-sized
7
+ * sections, no actions). The accent color is a CSS variable scoped to the
8
+ * deliverable root and falls back to the design-system gold.
9
+ */
10
+
11
+ @utility deliverable {
12
+ --deliverable-accent: var(--color-gold);
13
+
14
+ display: flex;
15
+ flex-direction: column;
16
+ gap: var(--spacing-16);
17
+ width: 100%;
18
+ max-width: var(--container-xl);
19
+ margin-inline: auto;
20
+ padding-inline: var(--spacing-6);
21
+ padding-block: var(--spacing-12);
22
+ color: var(--color-white);
23
+ font-family: var(--font-body);
24
+ }
25
+
26
+ @utility deliverable-page {
27
+ width: 100%;
28
+ }
29
+
30
+ @utility deliverable-heading {
31
+ font-family: var(--font-heading);
32
+ font-size: var(--text-3xl);
33
+ line-height: var(--text-3xl--line-height);
34
+ color: var(--deliverable-accent);
35
+ margin-bottom: var(--spacing-6);
36
+ letter-spacing: var(--letter-spacing-tight);
37
+ }
38
+
39
+ /* === Cover === */
40
+
41
+ @utility deliverable-cover {
42
+ min-height: min(80vh, 900px);
43
+ display: flex;
44
+ align-items: center;
45
+ justify-content: center;
46
+ text-align: center;
47
+ border: 1px solid color-mix(in oklab, var(--deliverable-accent) 30%, transparent);
48
+ background-color: var(--color-charcoal);
49
+ padding: var(--spacing-16);
50
+ }
51
+
52
+ @utility deliverable-cover-inner {
53
+ display: flex;
54
+ flex-direction: column;
55
+ gap: var(--spacing-6);
56
+ max-width: 56ch;
57
+ }
58
+
59
+ @utility deliverable-cover-eyebrow {
60
+ text-transform: uppercase;
61
+ letter-spacing: var(--letter-spacing-widest);
62
+ color: var(--color-silver);
63
+ font-size: var(--text-xs);
64
+ }
65
+
66
+ @utility deliverable-cover-title {
67
+ font-family: var(--font-heading);
68
+ font-size: var(--text-6xl);
69
+ line-height: var(--text-6xl--line-height);
70
+ color: var(--deliverable-accent);
71
+ letter-spacing: var(--letter-spacing-tight);
72
+ }
73
+
74
+ @utility deliverable-cover-subtitle {
75
+ font-size: var(--text-xl);
76
+ line-height: var(--text-xl--line-height);
77
+ color: var(--color-silver);
78
+ }
79
+
80
+ @utility deliverable-cover-client {
81
+ margin-top: var(--spacing-12);
82
+ font-size: var(--text-sm);
83
+ letter-spacing: var(--letter-spacing-wider);
84
+ text-transform: uppercase;
85
+ color: var(--color-silver);
86
+ }
87
+
88
+ @utility deliverable-cover-client-name {
89
+ color: var(--color-white);
90
+ font-weight: var(--font-weight-semibold);
91
+ }
92
+
93
+ /* === Image grid === */
94
+
95
+ @utility deliverable-image-grid {
96
+ display: grid;
97
+ gap: var(--spacing-6);
98
+ }
99
+
100
+ @utility deliverable-image-grid-cols-1 {
101
+ grid-template-columns: 1fr;
102
+ }
103
+
104
+ @utility deliverable-image-grid-cols-2 {
105
+ grid-template-columns: repeat(2, minmax(0, 1fr));
106
+ }
107
+
108
+ @utility deliverable-image-grid-cols-3 {
109
+ grid-template-columns: repeat(3, minmax(0, 1fr));
110
+ }
111
+
112
+ @utility deliverable-image-item {
113
+ display: flex;
114
+ flex-direction: column;
115
+ gap: var(--spacing-2);
116
+ break-inside: avoid;
117
+ }
118
+
119
+ @utility deliverable-image-img {
120
+ width: 100%;
121
+ height: 100%;
122
+ aspect-ratio: 4 / 3;
123
+ object-fit: cover;
124
+ background-color: var(--color-graphite);
125
+ border: 1px solid var(--color-ash);
126
+ }
127
+
128
+ @utility deliverable-image-missing {
129
+ aspect-ratio: 4 / 3;
130
+ display: flex;
131
+ align-items: center;
132
+ justify-content: center;
133
+ border: 1px dashed var(--color-ash);
134
+ color: var(--color-silver);
135
+ font-size: var(--text-sm);
136
+ }
137
+
138
+ @utility deliverable-image-caption {
139
+ font-size: var(--text-sm);
140
+ color: var(--color-silver);
141
+ line-height: var(--line-height-snug);
142
+ }
143
+
144
+ /* === Spotlight === */
145
+
146
+ @utility deliverable-spotlight-media {
147
+ margin-bottom: var(--spacing-6);
148
+ }
149
+
150
+ @utility deliverable-spotlight-img {
151
+ width: 100%;
152
+ max-height: 70vh;
153
+ object-fit: contain;
154
+ background-color: var(--color-graphite);
155
+ border: 1px solid var(--color-ash);
156
+ }
157
+
158
+ @utility deliverable-spotlight-missing {
159
+ width: 100%;
160
+ height: 50vh;
161
+ display: flex;
162
+ align-items: center;
163
+ justify-content: center;
164
+ border: 1px dashed var(--color-ash);
165
+ color: var(--color-silver);
166
+ }
167
+
168
+ @utility deliverable-spotlight-body {
169
+ max-width: 72ch;
170
+ font-size: var(--text-base);
171
+ line-height: var(--line-height-relaxed);
172
+ }
173
+
174
+ /* === Text block === */
175
+
176
+ @utility deliverable-text-block {
177
+ max-width: 72ch;
178
+ font-size: var(--text-base);
179
+ line-height: var(--line-height-relaxed);
180
+ }
181
+
182
+ /* === Color palette === */
183
+
184
+ @utility deliverable-palette {
185
+ display: grid;
186
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
187
+ gap: var(--spacing-4);
188
+ }
189
+
190
+ @utility deliverable-palette-item {
191
+ display: flex;
192
+ flex-direction: column;
193
+ gap: var(--spacing-1);
194
+ align-items: center;
195
+ text-align: center;
196
+ break-inside: avoid;
197
+ }
198
+
199
+ @utility deliverable-palette-chip {
200
+ width: 100%;
201
+ aspect-ratio: 1 / 1;
202
+ border: 1px solid var(--color-ash);
203
+ }
204
+
205
+ @utility deliverable-palette-label {
206
+ font-size: var(--text-sm);
207
+ color: var(--color-white);
208
+ font-weight: var(--font-weight-medium);
209
+ }
210
+
211
+ @utility deliverable-palette-hex {
212
+ font-family: var(--font-mono);
213
+ font-size: var(--text-xs);
214
+ color: var(--color-silver);
215
+ }
216
+
217
+ /* === Quote === */
218
+
219
+ @utility deliverable-quote {
220
+ display: flex;
221
+ align-items: center;
222
+ justify-content: center;
223
+ min-height: 40vh;
224
+ }
225
+
226
+ @utility deliverable-quote-body {
227
+ max-width: 64ch;
228
+ font-family: var(--font-heading);
229
+ text-align: center;
230
+ }
231
+
232
+ @utility deliverable-quote-text {
233
+ font-size: var(--text-3xl);
234
+ line-height: var(--line-height-snug);
235
+ color: var(--color-white);
236
+ }
237
+
238
+ @utility deliverable-quote-attribution {
239
+ margin-top: var(--spacing-6);
240
+ font-family: var(--font-body);
241
+ font-size: var(--text-sm);
242
+ color: var(--color-silver);
243
+ letter-spacing: var(--letter-spacing-wider);
244
+ }
245
+
246
+ /* === Floating action bar === */
247
+
248
+ @utility deliverable-actions {
249
+ position: sticky;
250
+ bottom: var(--spacing-6);
251
+ display: flex;
252
+ justify-content: flex-end;
253
+ margin-top: var(--spacing-8);
254
+ pointer-events: none;
255
+ }
256
+
257
+ @utility deliverable-action-button {
258
+ pointer-events: auto;
259
+ }
260
+
261
+ /* === Print path ===
262
+ * Same React tree, different paint. The strategy:
263
+ * - Cover gets its own named page (`@page cover`) with no margins so it
264
+ * prints full-bleed, with the body running on default pages with
265
+ * normal margins.
266
+ * - Body sections flow naturally — only the cover forces a page break.
267
+ * `break-inside: avoid` on each block keeps headings with their content
268
+ * and stops grids from splitting awkwardly.
269
+ * - The palette and quote no longer claim a full page each — they were
270
+ * web-mode treatments, not print.
271
+ * - Running footer carries page numbers; the cover suppresses it via
272
+ * `@page :first`.
273
+ */
274
+
275
+ @page {
276
+ size: A4;
277
+ margin: 18mm 18mm 22mm;
278
+ @bottom-right {
279
+ content: counter(page);
280
+ font-family: var(--font-body);
281
+ font-size: 9pt;
282
+ color: var(--color-slate);
283
+ }
284
+ }
285
+
286
+ @page :first {
287
+ margin: 0;
288
+ @bottom-right {
289
+ content: none;
290
+ }
291
+ }
292
+
293
+ @media print {
294
+ .deliverable {
295
+ color: var(--color-obsidian);
296
+ padding: 0;
297
+ margin: 0;
298
+ max-width: none;
299
+ gap: 0;
300
+ font-size: 10.5pt;
301
+ line-height: var(--line-height-relaxed);
302
+ }
303
+
304
+ .deliverable-page {
305
+ /* Sections flow; break only when content needs more room. Avoid
306
+ splitting any single block across pages. */
307
+ page-break-inside: avoid;
308
+ break-inside: avoid;
309
+ margin-bottom: 14mm;
310
+ }
311
+
312
+ .deliverable-page + .deliverable-page {
313
+ margin-top: 0;
314
+ }
315
+
316
+ .deliverable-heading {
317
+ page-break-after: avoid;
318
+ break-after: avoid;
319
+ }
320
+
321
+ /* === Cover ===
322
+ * Full-bleed first page. The cover is always the first section, so
323
+ * `@page :first { margin: 0 }` lets it bleed; we still pad the content
324
+ * inside the cover so the type doesn't sit on the page edge.
325
+ */
326
+ .deliverable-cover {
327
+ page-break-after: always;
328
+ break-after: page;
329
+ background-color: var(--color-obsidian);
330
+ color: var(--color-white);
331
+ min-height: 297mm;
332
+ width: 210mm;
333
+ border: none;
334
+ padding: 36mm 28mm;
335
+ display: grid;
336
+ grid-template-rows: auto 1fr auto;
337
+ text-align: left;
338
+ }
339
+
340
+ .deliverable-cover-inner {
341
+ grid-row: 2;
342
+ align-self: end;
343
+ max-width: 28em;
344
+ }
345
+
346
+ .deliverable-cover-eyebrow {
347
+ color: var(--deliverable-accent);
348
+ font-size: 9pt;
349
+ }
350
+
351
+ .deliverable-cover-title {
352
+ font-size: 44pt;
353
+ line-height: 1.05;
354
+ color: var(--color-white);
355
+ }
356
+
357
+ .deliverable-cover-subtitle {
358
+ font-size: 13pt;
359
+ color: var(--color-silver);
360
+ margin-top: 2mm;
361
+ }
362
+
363
+ .deliverable-cover-client {
364
+ grid-row: 3;
365
+ margin-top: 0;
366
+ color: var(--color-silver);
367
+ }
368
+
369
+ .deliverable-cover-client-name {
370
+ color: var(--color-white);
371
+ }
372
+
373
+ /* === Body typography === */
374
+ .deliverable-heading {
375
+ font-size: 20pt;
376
+ margin-bottom: 4mm;
377
+ color: var(--deliverable-accent);
378
+ }
379
+
380
+ .deliverable-text-block,
381
+ .deliverable-spotlight-body {
382
+ font-size: 11pt;
383
+ line-height: 1.55;
384
+ max-width: 36em;
385
+ color: var(--color-obsidian);
386
+ }
387
+
388
+ /* === Image grid ===
389
+ * Tighter than on screen. Each item stays atomic; the grid can break
390
+ * between rows but not mid-cell.
391
+ */
392
+ .deliverable-image-grid {
393
+ gap: 4mm;
394
+ }
395
+
396
+ .deliverable-image-item {
397
+ page-break-inside: avoid;
398
+ break-inside: avoid;
399
+ }
400
+
401
+ .deliverable-image-img {
402
+ aspect-ratio: 4 / 3;
403
+ border: none;
404
+ }
405
+
406
+ .deliverable-image-caption {
407
+ color: var(--color-slate);
408
+ font-size: 9pt;
409
+ margin-top: 1.5mm;
410
+ }
411
+
412
+ /* === Spotlight === */
413
+ .deliverable-spotlight-img {
414
+ max-height: 140mm;
415
+ border: none;
416
+ background-color: transparent;
417
+ }
418
+
419
+ .deliverable-spotlight-media {
420
+ margin-bottom: 4mm;
421
+ }
422
+
423
+ /* === Palette ===
424
+ * Inline strip at body width — not a full-page chart. Smaller chips,
425
+ * label and hex below.
426
+ */
427
+ .deliverable-palette {
428
+ grid-template-columns: repeat(auto-fit, minmax(28mm, 1fr));
429
+ gap: 4mm;
430
+ max-width: 160mm;
431
+ }
432
+
433
+ .deliverable-palette-chip {
434
+ aspect-ratio: 1 / 1;
435
+ border: 1px solid var(--color-slate);
436
+ }
437
+
438
+ .deliverable-palette-label {
439
+ font-size: 10pt;
440
+ color: var(--color-obsidian);
441
+ margin-top: 2mm;
442
+ }
443
+
444
+ .deliverable-palette-hex {
445
+ font-size: 8pt;
446
+ color: var(--color-slate);
447
+ }
448
+
449
+ /* === Quote ===
450
+ * Editorial pull-quote, not a full page. Generous margins, no min-height
451
+ * heroics.
452
+ */
453
+ .deliverable-quote {
454
+ min-height: 0;
455
+ padding: 6mm 0 8mm;
456
+ }
457
+
458
+ .deliverable-quote-body {
459
+ max-width: 30em;
460
+ margin-inline: auto;
461
+ }
462
+
463
+ .deliverable-quote-text {
464
+ font-size: 18pt;
465
+ line-height: 1.3;
466
+ color: var(--color-obsidian);
467
+ }
468
+
469
+ .deliverable-quote-attribution {
470
+ color: var(--color-slate);
471
+ }
472
+
473
+ .deliverable-actions {
474
+ display: none;
475
+ }
476
+ }
package/llms.md CHANGED
@@ -166,6 +166,13 @@ Import from `@lukeashford/aurelius`:
166
166
  | TodosList | tasks, title, onStopAllTasks |
167
167
  | ToolPanelContainer | topContent, bottomContent, width, initialTopPercent, onResizeStart, side |
168
168
  | ToolSidebar | tools, activeTools, onToggleTool, side |
169
+ | ArtifactImageGridSection | data |
170
+ | ArtifactSpotlightSection | data |
171
+ | ColorPaletteSection | data |
172
+ | CoverSection | data |
173
+ | DeliverableRenderer | deliverable, onDownloadPdf, hideActions, className |
174
+ | QuoteBlockSection | data |
175
+ | TextBlockSection | data |
169
176
  | ChatBubbleIcon | children |
170
177
  | CheckSquareIcon | children |
171
178
  | ChevronLeftIcon | children |
@@ -601,6 +608,50 @@ side of the chat interface. It follows the IntelliJ pattern:
601
608
  - **onToggleTool**: * Called when a tool button is clicked (toggle)
602
609
  - **side**: * Which side this sidebar is on — controls border direction
603
610
 
611
+ **ArtifactImageGridSection**
612
+ Grid of project artifact images with optional captions. The number of
613
+ columns is fixed by the spec (1–3); the renderer enforces a sensible aspect
614
+ ratio per item and lets the browser flow rows.
615
+
616
+
617
+ **ArtifactSpotlightSection**
618
+ A single hero artifact image with optional prose alongside. Reads at full
619
+ page width on screen and prints to a single page.
620
+
621
+
622
+ **ColorPaletteSection**
623
+ Color palette presented as labelled swatches with hex values.
624
+
625
+
626
+ **CoverSection**
627
+ Title page for a deliverable. Always rendered as the first section.
628
+
629
+
630
+ **DeliverableRenderer**
631
+ Render a presentable deliverable (moodboard, pitch deck) from a structured
632
+ spec. The same component drives the on-screen view and the print/PDF
633
+ version — `@media print` styles in `aurelius/styles/base.css` keep them in
634
+ sync. To produce a PDF, drive the page with headless Chromium and let the
635
+ print stylesheet do the work.
636
+
637
+ The renderer is purely presentational: it takes a fully resolved spec
638
+ (artifact URLs already inflated by the caller) and dispatches each section
639
+ to its typed sub-renderer. Unknown section types are skipped silently
640
+ forward-compat for new section variants added by the backend.
641
+
642
+ - **deliverable**: Resolved deliverable spec — every artifact reference already inflated.
643
+ - **onDownloadPdf**: * Called when the viewer requests a PDF download. The host application is responsible for fetching and triggering the file save (the URL knows about share tokens and credentials we don't). When omitted, the download affordance is hidden.
644
+ - **hideActions**: Hide the floating action bar entirely. Used when rendering for print.
645
+
646
+ **QuoteBlockSection**
647
+ Pulled quote with optional attribution. The renderer adds the surrounding
648
+ quotation marks.
649
+
650
+
651
+ **TextBlockSection**
652
+ Prose section. Body is rendered as Markdown.
653
+
654
+
604
655
  **CrossSquareIcon**
605
656
  - **variant**: * Visual variant for different states - 'cancelled': subtle ash coloring - 'failed': error red coloring
606
657
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lukeashford/aurelius",
3
- "version": "4.5.0",
3
+ "version": "4.6.0",
4
4
  "description": "Design system for Aurelius applications — A cohesive visual language for creative technologists",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -107,10 +107,12 @@ export function createAureliusESLintConfig(options = {}) {
107
107
  },
108
108
  },
109
109
 
110
- // CSS files: enforce Tailwind v4 CSS usage and tokens (exclude fonts.css and theme.css)
110
+ // CSS files: enforce Tailwind v4 CSS usage and tokens (exclude foundation
111
+ // sheets — fonts/theme/deliverable — which define the primitives the
112
+ // tokens rule would otherwise flag as hard-coded).
111
113
  {
112
114
  files: ['**/*.css'],
113
- ignores: ['**/fonts.css', '**/theme.css'],
115
+ ignores: ['**/fonts.css', '**/theme.css', '**/deliverable.css'],
114
116
  language: 'css/css',
115
117
  languageOptions: {
116
118
  customSyntax: tailwind4,