@janga/norna 0.7.22 → 0.7.23

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 (60) hide show
  1. package/astro.config.mjs +3 -0
  2. package/bin/norna-cli.mjs +2 -2
  3. package/package.json +17 -3
  4. package/schemas/category.schema.json +2 -2
  5. package/schemas/config.schema.json +22 -24
  6. package/schemas/content-frontmatter.schema.json +25 -5
  7. package/schemas/page-theme.schema.json +53 -25
  8. package/schemas/sitewide-content.schema.json +19 -18
  9. package/schemas/theme.schema.json +383 -250
  10. package/scripts/check-config.mjs +24 -4
  11. package/scripts/deploy-site.mjs +0 -1
  12. package/scripts/dev-local.mjs +175 -112
  13. package/scripts/lib/content-sync-apply.mjs +34 -0
  14. package/scripts/lib/content-sync-plan.mjs +179 -0
  15. package/scripts/lib/editor-language-service.mjs +128 -0
  16. package/scripts/lib/heading-ids.mjs +1 -1
  17. package/scripts/lib/image-presentation.mjs +2 -0
  18. package/scripts/lib/markdown-links.mjs +182 -0
  19. package/scripts/lib/navigation-model.mjs +25 -14
  20. package/scripts/lib/norna-markdown-blocks.mjs +1 -0
  21. package/scripts/lib/page-aliases.mjs +164 -0
  22. package/scripts/lib/page-markdown.mjs +56 -6
  23. package/scripts/lib/presentation.mjs +19 -37
  24. package/scripts/lib/project-config.mjs +50 -29
  25. package/scripts/lib/schema-definitions.mjs +24 -13
  26. package/scripts/lib/schema-editor-metadata.mjs +43 -30
  27. package/scripts/lib/schema-value-definitions.mjs +6 -2
  28. package/scripts/lib/site-content.mjs +26 -4
  29. package/scripts/lib/site-link-graph.mjs +326 -0
  30. package/scripts/lib/site-page-urls.mjs +10 -0
  31. package/scripts/lib/sitemap.mjs +34 -0
  32. package/scripts/lib/theme-presets.mjs +51 -23
  33. package/scripts/lib/theme-profiles.mjs +7 -5
  34. package/scripts/lib/yaml-config.mjs +6 -2
  35. package/scripts/sync-content-sections.mjs +116 -213
  36. package/scripts/sync-site-public.mjs +23 -2
  37. package/src/components/CodeBlockCopyScript.astro +92 -0
  38. package/src/components/DisplaySettings.astro +4 -4
  39. package/src/components/ImageCarousel.astro +7 -3
  40. package/src/components/NavigationPageTree.astro +44 -60
  41. package/src/components/PageAliasRedirect.astro +49 -0
  42. package/src/components/PageContentsNavigation.astro +21 -0
  43. package/src/components/SectionNavigationScript.astro +62 -6
  44. package/src/components/SiteNavigation.astro +15 -3
  45. package/src/components/SitePage.astro +42 -2
  46. package/src/components/SiteSection.astro +5 -0
  47. package/src/components/SiteTreeNavigation.astro +0 -1
  48. package/src/content.config.ts +5 -2
  49. package/src/layouts/BaseLayout.astro +14 -8
  50. package/src/lib/readerPreferencesScript.mjs +2 -2
  51. package/src/lib/sitePages.ts +3 -2
  52. package/src/pages/[...slug].astro +35 -8
  53. package/src/styles/content.css +494 -0
  54. package/src/styles/foundations.css +284 -0
  55. package/src/styles/global.css +6 -2510
  56. package/src/styles/media.css +523 -0
  57. package/src/styles/navigation.css +495 -0
  58. package/src/styles/page-layout.css +437 -0
  59. package/src/styles/responsive.css +525 -0
  60. package/starters/basic/README.md +1 -1
@@ -0,0 +1,525 @@
1
+ /* Responsive and forced-colors adaptations, kept last in the cascade. */
2
+
3
+ @media (max-width: 700px) {
4
+ :root {
5
+ --space-nav-to-first-section: var(--space-nav-to-first-section-mobile);
6
+ --space-content-block-gap: var(--space-content-block-gap-mobile);
7
+ --space-heading-to-block: var(--space-heading-to-block-mobile);
8
+ --space-image-item: var(--space-image-item-mobile);
9
+ --space-section-to-section: var(--space-section-to-section-mobile);
10
+ --space-page-title-to-first-section: var(--space-page-title-to-first-section-mobile);
11
+ --space-final-section-bottom: var(--space-final-section-bottom-mobile);
12
+ --content-gutter: var(--content-gutter-mobile);
13
+ --image-max-available-width: var(--image-max-available-width-mobile);
14
+ --image-max-height: var(--image-max-height-mobile);
15
+ --site-top-anchor-offset: 6.25rem;
16
+ }
17
+
18
+ .image-carousel {
19
+ --image-carousel-width-from-height: var(--image-carousel-width-from-height-mobile, var(--image-layout-width));
20
+ }
21
+
22
+ .site-nav-row {
23
+ width: min(calc(100% - (var(--content-gutter) * 2)), var(--page-width));
24
+ padding: 0.75rem 0;
25
+ }
26
+
27
+ .site-nav-row-mobile-only {
28
+ display: flex;
29
+ }
30
+
31
+ .site-brand {
32
+ max-width: min(70vw, 26rem);
33
+ font-size: 0.76rem;
34
+ overflow-wrap: anywhere;
35
+ }
36
+
37
+ .site-brand-logo {
38
+ height: min(var(--site-brand-logo-height, 2.6rem), 2.15rem);
39
+ max-width: min(48vw, 13rem);
40
+ }
41
+
42
+ .site-nav {
43
+ display: none;
44
+ }
45
+
46
+ .display-settings {
47
+ position: static;
48
+ }
49
+
50
+ .display-settings-panel {
51
+ top: calc(100% + 0.35rem);
52
+ right: max(var(--content-gutter), env(safe-area-inset-right, 0px));
53
+ left: max(var(--content-gutter), env(safe-area-inset-left, 0px));
54
+ width: auto;
55
+ max-height: calc(
56
+ 100dvh - 100% - max(var(--content-gutter), env(safe-area-inset-bottom, 0px)) - 0.35rem
57
+ );
58
+ }
59
+
60
+ .mobile-nav-menu {
61
+ display: block;
62
+ position: relative;
63
+ flex: 0 0 auto;
64
+ margin-left: auto;
65
+ }
66
+
67
+ .page-nav {
68
+ display: none;
69
+ }
70
+
71
+ .page-nav.page-nav-title-only {
72
+ display: block;
73
+ }
74
+
75
+ .mobile-nav-menu > summary {
76
+ display: flex;
77
+ align-items: center;
78
+ gap: 0.5rem;
79
+ min-height: 2.75rem;
80
+ border: 1px solid currentColor;
81
+ padding: 0.55rem 0.75rem;
82
+ font-size: 0.72rem;
83
+ font-weight: 700;
84
+ letter-spacing: 0.1em;
85
+ line-height: 1;
86
+ list-style: none;
87
+ color: var(--site-top-text-color, var(--color-primary-text));
88
+ text-transform: uppercase;
89
+ }
90
+
91
+ .mobile-nav-menu > summary::after {
92
+ content: "☰";
93
+ font-size: 1rem;
94
+ line-height: 1;
95
+ opacity: 0.86;
96
+ }
97
+
98
+ .mobile-nav-menu[open] > summary::after {
99
+ content: "×";
100
+ font-size: 1.25rem;
101
+ }
102
+
103
+ .mobile-nav-menu > summary::-webkit-details-marker {
104
+ display: none;
105
+ }
106
+
107
+ .mobile-nav-panel {
108
+ position: fixed;
109
+ top: var(--site-top-anchor-offset);
110
+ right: 0;
111
+ bottom: 0;
112
+ left: 0;
113
+ width: 100%;
114
+ max-height: none;
115
+ border-top: 1px solid color-mix(in srgb, currentColor 24%, transparent);
116
+ padding: clamp(1.25rem, 5vw, 2rem) var(--content-gutter) max(1.5rem, env(safe-area-inset-bottom));
117
+ background: var(--site-top-background-color, var(--color-page));
118
+ box-shadow: 0 1.5rem 3.5rem rgb(0 0 0 / 0.32);
119
+ color: var(--site-top-text-color, var(--color-text));
120
+ overflow-y: auto;
121
+ overscroll-behavior: contain;
122
+ }
123
+
124
+ .mobile-site-nav {
125
+ width: min(100%, 32rem);
126
+ margin: 0 auto;
127
+ }
128
+
129
+ .mobile-nav-panel h2 {
130
+ margin: 0 0 1.25rem;
131
+ font-size: clamp(1.25rem, 5vw, 1.55rem);
132
+ font-weight: 650;
133
+ letter-spacing: 0;
134
+ line-height: 1.2;
135
+ text-transform: none;
136
+ }
137
+
138
+ .mobile-nav-panel :is(ul, ol) {
139
+ display: grid;
140
+ gap: 0;
141
+ margin: 0;
142
+ padding: 0;
143
+ list-style: none;
144
+ }
145
+
146
+ .navigation-page-tree-mobile > .navigation-page-node {
147
+ border-top: 1px solid color-mix(in srgb, currentColor 14%, transparent);
148
+ }
149
+
150
+ .navigation-page-tree-mobile > .navigation-page-node:first-child {
151
+ border-top: 0;
152
+ }
153
+
154
+ .navigation-page-tree-mobile .navigation-page-link {
155
+ display: flex;
156
+ align-items: center;
157
+ width: 100%;
158
+ min-height: 3.25rem;
159
+ padding: 0.75rem 2.5rem 0.75rem 0;
160
+ color: var(--color-secondary-text);
161
+ font-size: 0.94rem;
162
+ letter-spacing: 0;
163
+ line-height: 1.35;
164
+ text-decoration: none;
165
+ text-transform: none;
166
+ }
167
+
168
+ .navigation-page-tree-mobile .navigation-page-disclosure > .navigation-page-summary {
169
+ position: static;
170
+ display: flex;
171
+ align-items: center;
172
+ justify-content: space-between;
173
+ width: 100%;
174
+ height: auto;
175
+ min-height: 3.25rem;
176
+ padding: 0.75rem 0;
177
+ font-size: 0.94rem;
178
+ line-height: 1.35;
179
+ color: var(--color-secondary-text);
180
+ }
181
+
182
+ .navigation-page-tree-mobile .navigation-page-disclosure > .navigation-page-open-link {
183
+ display: none;
184
+ align-items: center;
185
+ min-height: 3.25rem;
186
+ width: calc(100% - 2.5rem);
187
+ padding: 0.75rem 0;
188
+ font-size: 0.94rem;
189
+ line-height: 1.35;
190
+ color: var(--color-secondary-text);
191
+ overflow-wrap: anywhere;
192
+ }
193
+
194
+ .navigation-page-tree-mobile .navigation-page-disclosure[open] > .navigation-page-open-link {
195
+ display: flex;
196
+ }
197
+
198
+ .navigation-page-tree-mobile .navigation-page-disclosure > .navigation-page-summary:hover,
199
+ .navigation-page-tree-mobile .navigation-page-disclosure > .navigation-page-summary:focus-visible,
200
+ .navigation-page-node-current > .navigation-page-disclosure > .navigation-page-summary {
201
+ background: transparent;
202
+ color: var(--color-primary-text);
203
+ }
204
+
205
+ .navigation-page-tree-mobile .navigation-page-disclosure > .navigation-page-summary:hover > :first-child,
206
+ .navigation-page-tree-mobile .navigation-page-disclosure > .navigation-page-summary:focus-visible > :first-child,
207
+ .navigation-page-node-current > .navigation-page-disclosure > .navigation-page-summary > :first-child {
208
+ text-decoration: underline;
209
+ text-decoration-thickness: 1px;
210
+ text-underline-offset: 0.3em;
211
+ }
212
+
213
+ .navigation-page-chevron::before {
214
+ display: block;
215
+ content: "›";
216
+ font-size: 1.25rem;
217
+ line-height: 1;
218
+ transition: transform 140ms ease;
219
+ }
220
+
221
+ .navigation-page-disclosure[open] > .navigation-page-summary .navigation-page-chevron::before {
222
+ transform: rotate(90deg);
223
+ }
224
+
225
+ .navigation-page-tree-mobile .navigation-page-disclosure > .navigation-page-summary > [aria-hidden='true']::before,
226
+ .navigation-page-tree-mobile .navigation-page-disclosure[open] > .navigation-page-summary > [aria-hidden='true']::before {
227
+ content: "›";
228
+ }
229
+
230
+ .navigation-page-tree-mobile .navigation-page-branch-content {
231
+ margin-left: 0.35rem;
232
+ border-left: 1px solid color-mix(in srgb, currentColor 20%, transparent);
233
+ padding-left: 1rem;
234
+ }
235
+
236
+ .navigation-page-tree-mobile .navigation-page-sections {
237
+ margin: 0 0 0.45rem;
238
+ }
239
+
240
+ .navigation-page-branch-content > .navigation-page-tree-mobile > .navigation-page-node {
241
+ border-top: 1px solid color-mix(in srgb, currentColor 10%, transparent);
242
+ }
243
+
244
+ .navigation-page-tree-mobile .navigation-page-link:hover,
245
+ .navigation-page-tree-mobile .navigation-page-link:focus-visible,
246
+ .navigation-page-tree-mobile .navigation-page-link[aria-current='page'] {
247
+ color: var(--color-primary-text);
248
+ text-decoration: underline;
249
+ text-decoration-thickness: 1px;
250
+ text-underline-offset: 0.3em;
251
+ }
252
+
253
+ .page-contents-links-mobile {
254
+ margin-top: 0.25rem;
255
+ }
256
+
257
+ .page-contents-links-mobile > li {
258
+ border-bottom: 1px solid color-mix(in srgb, currentColor 12%, transparent);
259
+ }
260
+
261
+ .page-contents-links-mobile li + li {
262
+ margin-top: 0;
263
+ }
264
+
265
+ .page-contents-links-mobile ol {
266
+ border-left: 1px solid color-mix(in srgb, currentColor 16%, transparent);
267
+ padding-left: 1rem;
268
+ }
269
+
270
+ .page-contents-links-mobile a {
271
+ min-height: 3.2rem;
272
+ padding: 0.85rem 0;
273
+ font-size: 0.92rem;
274
+ color: var(--color-secondary-text);
275
+ }
276
+
277
+ .mobile-nav-panel a {
278
+ font-family: inherit;
279
+ font-size: 0.94rem;
280
+ letter-spacing: 0;
281
+ line-height: 1.35;
282
+ text-transform: none;
283
+ }
284
+
285
+ .mobile-nav-view + .mobile-nav-view {
286
+ margin-top: 2rem;
287
+ }
288
+
289
+ .mobile-nav-sections {
290
+ border-top: 1px solid color-mix(in srgb, currentColor 16%, transparent);
291
+ }
292
+
293
+ .mobile-nav-sections li {
294
+ border-bottom: 1px solid color-mix(in srgb, currentColor 12%, transparent);
295
+ }
296
+
297
+ .mobile-nav-sections a {
298
+ min-height: 3.2rem;
299
+ padding: 0.85rem 0;
300
+ font-size: 0.92rem;
301
+ color: var(--color-secondary-text);
302
+ }
303
+
304
+ .mobile-nav-sections .mobile-nav-page-top {
305
+ font-weight: 650;
306
+ }
307
+
308
+ .mobile-nav-sections li:not(.mobile-nav-page-top-item) a {
309
+ padding-left: 1rem;
310
+ }
311
+
312
+ .mobile-nav-sections a:hover,
313
+ .mobile-nav-sections a:focus-visible,
314
+ .mobile-nav-sections a[aria-current='location'] {
315
+ color: var(--color-primary-text);
316
+ text-decoration: underline;
317
+ text-decoration-thickness: 1px;
318
+ text-underline-offset: 0.25em;
319
+ }
320
+
321
+ .mobile-navigation-open {
322
+ overflow: hidden;
323
+ }
324
+
325
+ .site-content {
326
+ width: min(calc(100% - (var(--content-gutter) * 2)), var(--page-width));
327
+ }
328
+
329
+ .site-page-layout-tree {
330
+ display: block;
331
+ width: 100%;
332
+ }
333
+
334
+ .site-page-layout-tree > .site-content {
335
+ width: min(calc(100% - (var(--content-gutter) * 2)), var(--page-width));
336
+ }
337
+
338
+ .site-page-layout-tree .site-section::before {
339
+ left: calc(50% - 50vw);
340
+ right: calc(50% - 50vw);
341
+ }
342
+
343
+ .tree-local-navigation {
344
+ display: none;
345
+ }
346
+
347
+ .page-contents-navigation {
348
+ display: none;
349
+ }
350
+
351
+ .site-banners {
352
+ width: min(calc(100% - 2rem), var(--page-width));
353
+ padding-top: 0.75rem;
354
+ }
355
+
356
+ .site-footer {
357
+ width: min(calc(100% - 2rem), 34rem);
358
+ }
359
+
360
+ .site-section + .site-section {
361
+ margin-top: 0;
362
+ }
363
+
364
+ .section-body {
365
+ width: 100%;
366
+ line-height: 1.72;
367
+ }
368
+
369
+ .section-header h1,
370
+ .section-header h2 {
371
+ font-size: var(
372
+ --section-heading-font-size-mobile,
373
+ var(--section-heading-font-size-desktop, clamp(1.3rem, 1.05rem + 1.35vw, 1.75rem))
374
+ );
375
+ }
376
+
377
+ .section-header {
378
+ width: min(
379
+ 100%,
380
+ var(
381
+ --reader-text-width,
382
+ var(--section-heading-width-mobile, var(--section-heading-width-desktop, 760px))
383
+ )
384
+ );
385
+ text-align: var(--section-heading-align-mobile, var(--section-heading-align-desktop, center));
386
+ }
387
+
388
+ .section-markdown {
389
+ width: min(
390
+ 100%,
391
+ var(--reader-text-width, var(--section-body-width-mobile, var(--section-body-width-desktop, var(--text-width))))
392
+ );
393
+ font-size: var(
394
+ --section-body-font-size-mobile,
395
+ var(--section-body-font-size-desktop, clamp(0.96rem, 0.94rem + 0.08vw, 1rem))
396
+ );
397
+ text-align: var(--section-body-align-mobile, var(--section-body-align-desktop, left));
398
+ }
399
+
400
+ .image-meta {
401
+ font-size: var(--section-caption-font-size-mobile, var(--section-caption-font-size-desktop, 0.95rem));
402
+ text-align: var(--section-caption-align-mobile, var(--section-caption-align-desktop, center));
403
+ }
404
+
405
+ .image-details {
406
+ justify-content: var(--section-caption-justify-mobile, var(--section-caption-justify-desktop, center));
407
+ }
408
+
409
+ .section-markdown h3 {
410
+ font-size: var(--section-markdown-h3-font-size-mobile, var(--section-markdown-h3-font-size-desktop, 0.82rem));
411
+ text-align: var(--section-markdown-h3-align-mobile, var(--section-markdown-h3-align-desktop, left));
412
+ }
413
+
414
+ .section-markdown h4 {
415
+ font-size: var(--section-markdown-h4-font-size-mobile, var(--section-markdown-h4-font-size-desktop, clamp(0.96rem, 0.94rem + 0.08vw, 1rem)));
416
+ text-align: var(--section-markdown-h4-align-mobile, var(--section-markdown-h4-align-desktop, left));
417
+ }
418
+
419
+ .card-list-layout-image-left .card-list-item-has-image,
420
+ .card-list-layout-image-right .card-list-item-has-image,
421
+ .card-list-layout-image-left .card-list-item-has-image .card-list-link,
422
+ .card-list-layout-image-right .card-list-item-has-image .card-list-link {
423
+ grid-template-columns: 1fr;
424
+ }
425
+
426
+ .card-list-layout-image-right .card-list-image-frame {
427
+ order: 0;
428
+ }
429
+
430
+ .section-markdown ul,
431
+ .section-markdown ol {
432
+ display: block;
433
+ }
434
+
435
+ .managed-image-item img {
436
+ max-height: var(--image-max-height);
437
+ }
438
+
439
+ .image-carousel-position {
440
+ position: absolute;
441
+ right: 0.5rem;
442
+ bottom: 0.5rem;
443
+ min-width: 3rem;
444
+ min-height: 1.75rem;
445
+ padding: 0.3rem 0.55rem;
446
+ font-size: 0.75rem;
447
+ }
448
+
449
+ :is(.image-stack, .managed-images) {
450
+ gap: var(--space-image-item);
451
+ }
452
+
453
+ .image-details {
454
+ padding: 0 0.25rem;
455
+ font-size: 1rem;
456
+ }
457
+ }
458
+
459
+ @media (forced-colors: active) {
460
+ :root,
461
+ :root[data-appearance='dark'],
462
+ :root[data-appearance='system'] {
463
+ --color-page: Canvas;
464
+ --color-primary-text: CanvasText;
465
+ --color-secondary-text: CanvasText;
466
+ --color-link-text: LinkText;
467
+ --color-text: CanvasText;
468
+ --color-muted: CanvasText;
469
+ --color-accent: LinkText;
470
+ --color-surface: Canvas;
471
+ --color-soft: CanvasText;
472
+ --color-border: CanvasText;
473
+ --color-nav-separator: CanvasText;
474
+ --color-frame-background: Canvas;
475
+ --color-frame-text: CanvasText;
476
+ --color-surface-base-background: Canvas;
477
+ --color-surface-base-text: CanvasText;
478
+ --color-surface-base-secondary-text: CanvasText;
479
+ --color-surface-soft-background: Canvas;
480
+ --color-surface-soft-text: CanvasText;
481
+ --color-surface-soft-secondary-text: CanvasText;
482
+ --color-surface-emphasis-background: Canvas;
483
+ --color-surface-emphasis-text: CanvasText;
484
+ --color-surface-emphasis-secondary-text: CanvasText;
485
+ --color-focus-ring: Highlight;
486
+ --color-focus-ring-contrast: Canvas;
487
+ --color-selection-background: Highlight;
488
+ --color-selection-text: HighlightText;
489
+ --color-control-background: ButtonFace;
490
+ --color-control-background-active: Highlight;
491
+ --color-control-text: ButtonText;
492
+ --color-code-background: Canvas;
493
+ --color-code-text: CanvasText;
494
+ --color-warning-accent: Highlight;
495
+ --color-warning-surface: Canvas;
496
+ --color-warning-text: CanvasText;
497
+ --color-error-accent: Highlight;
498
+ --color-error-surface: Canvas;
499
+ --color-error-text: CanvasText;
500
+ --color-success-accent: Highlight;
501
+ --color-success-surface: Canvas;
502
+ --color-success-text: CanvasText;
503
+ }
504
+
505
+ .display-settings-panel,
506
+ .mobile-nav-panel,
507
+ .site-nav-submenu > nav,
508
+ .card-list-item,
509
+ .image-carousel-button,
510
+ .image-carousel-position {
511
+ border: 1px solid CanvasText;
512
+ box-shadow: none;
513
+ }
514
+
515
+ :is(.display-settings button, .display-settings-segmented span, .mobile-nav-menu > summary, .site-banner-dismiss) {
516
+ border-color: ButtonText;
517
+ background: ButtonFace;
518
+ color: ButtonText;
519
+ }
520
+
521
+ :is(.display-settings-segmented input:checked + span, .image-carousel-button:hover:not(:disabled)) {
522
+ background: Highlight;
523
+ color: HighlightText;
524
+ }
525
+ }
@@ -12,7 +12,7 @@ npm run norna:dev
12
12
  If the standard local port is blocked, start with:
13
13
 
14
14
  ```sh
15
- npm run norna:dev -- --kill
15
+ npm run norna:dev
16
16
  ```
17
17
 
18
18
  Edit shared logo settings, banners, and footer in