@janga/norna 0.7.22 → 0.7.24

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 (88) hide show
  1. package/README.md +14 -18
  2. package/astro.config.mjs +15 -0
  3. package/bin/norna-cli.mjs +8 -2
  4. package/package.json +28 -3
  5. package/schemas/category.schema.json +2 -2
  6. package/schemas/config.schema.json +52 -24
  7. package/schemas/content-frontmatter.schema.json +25 -5
  8. package/schemas/page-theme.schema.json +53 -25
  9. package/schemas/sitewide-content.schema.json +19 -18
  10. package/schemas/theme.schema.json +385 -252
  11. package/scripts/build-site.mjs +1 -0
  12. package/scripts/check-config.mjs +36 -5
  13. package/scripts/deploy-site.mjs +0 -1
  14. package/scripts/dev-local.mjs +175 -112
  15. package/scripts/generate-search-index.mjs +57 -0
  16. package/scripts/init-site.mjs +1 -0
  17. package/scripts/lib/code-fence-metadata.mjs +223 -0
  18. package/scripts/lib/content-sync-apply.mjs +34 -0
  19. package/scripts/lib/content-sync-plan.mjs +179 -0
  20. package/scripts/lib/edit-source-link.mjs +49 -0
  21. package/scripts/lib/editor-language-service.mjs +160 -12
  22. package/scripts/lib/heading-ids.mjs +1 -1
  23. package/scripts/lib/image-presentation.mjs +6 -0
  24. package/scripts/lib/markdown-links.mjs +182 -0
  25. package/scripts/lib/navigation-model.mjs +44 -12
  26. package/scripts/lib/navigation-review.mjs +396 -0
  27. package/scripts/lib/norna-markdown-blocks.mjs +74 -26
  28. package/scripts/lib/norna-markdown-render-plugin.mjs +64 -1
  29. package/scripts/lib/page-aliases.mjs +184 -0
  30. package/scripts/lib/page-markdown.mjs +88 -7
  31. package/scripts/lib/page-move-plan.mjs +659 -0
  32. package/scripts/lib/presentation-palette-metadata.mjs +1 -1
  33. package/scripts/lib/presentation.mjs +10 -37
  34. package/scripts/lib/project-config.mjs +146 -19
  35. package/scripts/lib/public-asset-conventions.mjs +36 -2
  36. package/scripts/lib/schema-definitions.mjs +43 -15
  37. package/scripts/lib/schema-editor-metadata.mjs +60 -32
  38. package/scripts/lib/schema-value-definitions.mjs +6 -2
  39. package/scripts/lib/semantic-callouts.mjs +128 -0
  40. package/scripts/lib/site-content.mjs +28 -5
  41. package/scripts/lib/site-link-graph.mjs +357 -0
  42. package/scripts/lib/site-navigation-tree.mjs +85 -0
  43. package/scripts/lib/site-page-urls.mjs +10 -0
  44. package/scripts/lib/sitemap.mjs +34 -0
  45. package/scripts/lib/social-image-assets.mjs +30 -0
  46. package/scripts/lib/theme-presets.mjs +53 -25
  47. package/scripts/lib/theme-profiles.mjs +6 -8
  48. package/scripts/lib/yaml-config.mjs +6 -2
  49. package/scripts/move-site-page.mjs +256 -0
  50. package/scripts/review-navigation.mjs +32 -0
  51. package/scripts/sync-content-sections.mjs +182 -216
  52. package/scripts/sync-site-public.mjs +43 -3
  53. package/src/components/CodeBlockCopyScript.astro +97 -0
  54. package/src/components/DisplaySettings.astro +4 -4
  55. package/src/components/EditSourceLink.astro +17 -0
  56. package/src/components/ImageCarousel.astro +6 -3
  57. package/src/components/NavigationPageTree.astro +81 -86
  58. package/src/components/NavigationTreeControls.astro +77 -0
  59. package/src/components/PageAliasRedirect.astro +49 -0
  60. package/src/components/PageContentsNavigation.astro +21 -0
  61. package/src/components/PageList.astro +33 -0
  62. package/src/components/PageSequenceNavigation.astro +37 -0
  63. package/src/components/SearchPage.astro +151 -0
  64. package/src/components/SectionNavigationScript.astro +62 -6
  65. package/src/components/SiteNavigation.astro +50 -11
  66. package/src/components/SitePage.astro +113 -20
  67. package/src/components/SiteSection.astro +16 -3
  68. package/src/components/SiteTreeNavigation.astro +8 -2
  69. package/src/components/TreeNavigationScript.astro +207 -26
  70. package/src/content.config.ts +5 -2
  71. package/src/layouts/BaseLayout.astro +71 -10
  72. package/src/lib/readerPreferencesScript.mjs +2 -2
  73. package/src/lib/sectionContent.ts +32 -3
  74. package/src/lib/siteNavigation.ts +31 -52
  75. package/src/lib/sitePages.ts +3 -2
  76. package/src/lib/sitePublicAssets.ts +1 -0
  77. package/src/pages/404.astro +110 -0
  78. package/src/pages/[...slug].astro +45 -8
  79. package/src/styles/content.css +718 -0
  80. package/src/styles/foundations.css +284 -0
  81. package/src/styles/global.css +6 -2510
  82. package/src/styles/media.css +518 -0
  83. package/src/styles/navigation.css +526 -0
  84. package/src/styles/page-layout.css +786 -0
  85. package/src/styles/responsive.css +594 -0
  86. package/starters/basic/README.md +6 -19
  87. package/starters/basic/package.json +1 -0
  88. package/starters/basic/site/pages/000-home/content.md +13 -50
@@ -0,0 +1,526 @@
1
+ /* Site-wide navigation and reader controls. */
2
+
3
+ .site-top {
4
+ position: sticky;
5
+ top: 0;
6
+ z-index: 10;
7
+ padding-top: var(--nav-top-safety-inset);
8
+ padding-top: max(env(safe-area-inset-top, 0px), var(--nav-top-safety-inset));
9
+ border-bottom: 1px solid var(--color-border);
10
+ background-color: var(--site-top-background-color, var(--color-page));
11
+ color: var(--site-top-text-color, var(--color-text));
12
+ transition: background-color 0.18s ease, color 0.18s ease;
13
+ }
14
+
15
+ .site-nav-row {
16
+ display: flex;
17
+ align-items: center;
18
+ justify-content: space-between;
19
+ gap: 1rem;
20
+ width: min(calc(100% - (var(--content-gutter) * 2)), var(--page-width));
21
+ margin: 0 auto;
22
+ padding: 0.8rem 0 0.7rem;
23
+ }
24
+
25
+ .site-nav-row-mobile-only {
26
+ display: none;
27
+ }
28
+
29
+ .site-nav-actions {
30
+ display: flex;
31
+ align-items: center;
32
+ justify-content: flex-end;
33
+ gap: clamp(0.65rem, 1.5vw, 1rem);
34
+ min-width: 0;
35
+ margin-left: auto;
36
+ }
37
+
38
+ .site-search-link {
39
+ display: grid;
40
+ place-items: center;
41
+ flex: 0 0 auto;
42
+ width: 2.25rem;
43
+ height: 2.25rem;
44
+ border: 1px solid color-mix(in srgb, currentColor 38%, transparent);
45
+ border-radius: 50%;
46
+ color: currentColor;
47
+ text-decoration: none;
48
+ transition: border-color 0.18s ease, background-color 0.18s ease;
49
+ }
50
+
51
+ .site-search-link:hover,
52
+ .site-search-link[aria-current='page'] {
53
+ border-color: currentColor;
54
+ background: color-mix(in srgb, currentColor 9%, transparent);
55
+ }
56
+
57
+ .site-search-link:focus-visible {
58
+ outline: var(--focus-indicator-width) solid var(--color-focus-ring);
59
+ outline-offset: 2px;
60
+ }
61
+
62
+ .site-search-link svg {
63
+ display: block;
64
+ width: 1.05rem;
65
+ height: 1.05rem;
66
+ stroke-width: 2;
67
+ }
68
+
69
+ .site-nav-leading {
70
+ display: flex;
71
+ align-items: center;
72
+ gap: 0.35rem;
73
+ min-width: 0;
74
+ flex: 0 0 auto;
75
+ }
76
+
77
+ :root:not([data-reader-preferences-ready='true']) .display-settings {
78
+ display: none;
79
+ }
80
+
81
+ .display-settings {
82
+ position: relative;
83
+ display: block;
84
+ flex: 0 0 auto;
85
+ font-family: var(--font-sans);
86
+ }
87
+
88
+ .display-settings summary {
89
+ display: grid;
90
+ place-items: center;
91
+ width: 2.25rem;
92
+ height: 2.25rem;
93
+ border: 1px solid color-mix(in srgb, currentColor 38%, transparent);
94
+ border-radius: 50%;
95
+ background-color: transparent;
96
+ color: currentColor;
97
+ cursor: pointer;
98
+ list-style: none;
99
+ transition: border-color 0.18s ease, background-color 0.18s ease;
100
+ }
101
+
102
+ :root[data-focus-reading='on'] .display-settings summary {
103
+ grid-template-columns: auto auto;
104
+ gap: 0.4rem;
105
+ width: auto;
106
+ padding: 0 0.65rem;
107
+ border-color: currentColor;
108
+ background: color-mix(in srgb, currentColor 9%, transparent);
109
+ }
110
+
111
+ .display-settings summary::-webkit-details-marker {
112
+ display: none;
113
+ }
114
+
115
+ .display-settings summary:hover,
116
+ .display-settings[open] summary {
117
+ border-color: currentColor;
118
+ background: color-mix(in srgb, currentColor 9%, transparent);
119
+ }
120
+
121
+ .display-settings summary:focus-visible,
122
+ .display-settings button:focus-visible,
123
+ .display-settings input:focus-visible + span {
124
+ outline-color: var(--color-focus-ring);
125
+ }
126
+
127
+ .display-settings-trigger-icon {
128
+ display: block;
129
+ width: 1.05rem;
130
+ height: 1.05rem;
131
+ fill: none;
132
+ stroke: currentColor;
133
+ stroke-width: 2;
134
+ stroke-linecap: round;
135
+ stroke-linejoin: round;
136
+ }
137
+
138
+ .display-settings-focus-status {
139
+ display: none;
140
+ font-size: 0.72rem;
141
+ font-weight: 650;
142
+ white-space: nowrap;
143
+ }
144
+
145
+ :root[data-focus-reading='on'] .display-settings-focus-status {
146
+ display: block;
147
+ }
148
+
149
+ .display-settings-panel {
150
+ position: absolute;
151
+ top: calc(100% + 0.45rem);
152
+ right: 0;
153
+ z-index: 30;
154
+ display: grid;
155
+ gap: 0.9rem;
156
+ width: min(20rem, calc(100vw - (var(--content-gutter) * 2)));
157
+ max-height: calc(100svh - var(--site-top-anchor-offset) - 1rem);
158
+ margin: 0;
159
+ padding: 0.85rem;
160
+ border: 1px solid color-mix(in srgb, var(--color-surface-soft-text) 28%, transparent);
161
+ border-radius: var(--corner-radius-medium, 4px);
162
+ background: var(--color-surface-soft-background);
163
+ color: var(--color-surface-soft-text);
164
+ font-size: 0.82rem;
165
+ box-shadow: 0 0.75rem 2rem rgb(0 0 0 / 26%);
166
+ overflow-y: auto;
167
+ overscroll-behavior: contain;
168
+ }
169
+
170
+ .display-settings-title {
171
+ margin: 0;
172
+ font-size: 0.78rem;
173
+ font-weight: 700;
174
+ text-transform: uppercase;
175
+ }
176
+
177
+ .display-settings fieldset {
178
+ display: grid;
179
+ gap: 0.4rem;
180
+ margin: 0;
181
+ padding: 0;
182
+ border: 0;
183
+ }
184
+
185
+ .display-settings legend {
186
+ margin: 0 0 0.4rem;
187
+ padding: 0;
188
+ color: var(--color-surface-soft-secondary-text);
189
+ font-size: 0.72rem;
190
+ font-weight: 650;
191
+ }
192
+
193
+ .display-settings-segmented {
194
+ display: grid;
195
+ grid-template-columns: repeat(3, minmax(0, 1fr));
196
+ gap: 1px;
197
+ width: 100%;
198
+ border: 1px solid var(--color-border);
199
+ border-radius: var(--corner-radius-small, 2px);
200
+ background: var(--color-border);
201
+ overflow: hidden;
202
+ }
203
+
204
+ .display-settings-segmented label {
205
+ position: relative;
206
+ min-width: 0;
207
+ cursor: pointer;
208
+ }
209
+
210
+ .display-settings-segmented input {
211
+ position: absolute;
212
+ width: 1px;
213
+ height: 1px;
214
+ opacity: 0;
215
+ }
216
+
217
+ .display-settings-segmented span {
218
+ display: grid;
219
+ place-items: center;
220
+ min-height: var(--target-size-comfortable);
221
+ padding: 0.35rem 0.45rem;
222
+ background: var(--color-surface-base-background);
223
+ color: var(--color-surface-base-text);
224
+ font-size: 0.75rem;
225
+ font-weight: 600;
226
+ text-align: center;
227
+ transition: background-color 0.18s ease, color 0.18s ease;
228
+ }
229
+
230
+ .display-settings-segmented label:hover span {
231
+ background: color-mix(in srgb, currentColor 8%, var(--color-surface-base-background));
232
+ }
233
+
234
+ .display-settings-segmented input:checked + span {
235
+ background: color-mix(in srgb, var(--color-accent) 18%, var(--color-surface-soft-background));
236
+ color: var(--color-surface-soft-text);
237
+ }
238
+
239
+ .display-settings-segmented input:focus-visible + span {
240
+ position: relative;
241
+ z-index: 1;
242
+ outline: var(--focus-indicator-width) solid var(--color-focus-ring);
243
+ outline-offset: calc(0px - var(--focus-indicator-width));
244
+ box-shadow: inset 0 0 0 var(--focus-indicator-width) var(--color-focus-ring-contrast);
245
+ }
246
+
247
+ .display-settings-toggle {
248
+ display: flex;
249
+ align-items: center;
250
+ gap: 0.55rem;
251
+ min-height: var(--target-size-minimum);
252
+ font-weight: 600;
253
+ cursor: pointer;
254
+ }
255
+
256
+ .display-settings-toggle input {
257
+ width: 1rem;
258
+ height: 1rem;
259
+ margin: 0;
260
+ accent-color: var(--color-accent);
261
+ }
262
+
263
+ .display-settings-reset {
264
+ justify-self: start;
265
+ min-height: var(--target-size-minimum);
266
+ border: 0;
267
+ padding: 0;
268
+ background: transparent;
269
+ color: var(--color-accent);
270
+ font: inherit;
271
+ font-weight: 650;
272
+ text-decoration: underline;
273
+ text-underline-offset: 0.2em;
274
+ cursor: pointer;
275
+ }
276
+
277
+ .site-brand,
278
+ .site-nav a,
279
+ .mobile-nav-menu summary,
280
+ .mobile-nav-panel a,
281
+ .site-nav-submenu a {
282
+ color: currentColor;
283
+ text-decoration: none;
284
+ }
285
+
286
+ .site-brand {
287
+ display: flex;
288
+ align-items: center;
289
+ flex: 0 0 auto;
290
+ font-size: 0.82rem;
291
+ font-weight: 700;
292
+ letter-spacing: 0.08em;
293
+ line-height: 1.1;
294
+ text-transform: uppercase;
295
+ }
296
+
297
+ .site-brand-logo {
298
+ display: block;
299
+ width: auto;
300
+ height: var(--site-brand-logo-height, 2.6rem);
301
+ max-width: min(30vw, 18rem);
302
+ }
303
+
304
+ .site-top-has-navigation-rail-frame .site-nav-row {
305
+ width: min(calc(100% - (var(--content-gutter) * 2)), max(var(--page-width), 86rem));
306
+ }
307
+
308
+ .site-nav ul,
309
+ .mobile-nav-panel ul {
310
+ margin: 0;
311
+ padding: 0;
312
+ list-style: none;
313
+ }
314
+
315
+ .site-nav > ul {
316
+ display: flex;
317
+ flex-wrap: wrap;
318
+ justify-content: flex-end;
319
+ gap: 0.35rem clamp(0.9rem, 2.6vw, 2rem);
320
+ }
321
+
322
+ .site-nav-item {
323
+ position: relative;
324
+ }
325
+
326
+ .site-nav a,
327
+ .mobile-nav-panel a {
328
+ display: block;
329
+ min-height: var(--target-size-minimum);
330
+ color: var(--color-secondary-text);
331
+ font-size: 0.78rem;
332
+ font-weight: 500;
333
+ letter-spacing: 0.08em;
334
+ line-height: 1.2;
335
+ text-transform: uppercase;
336
+ }
337
+
338
+ .site-nav a:hover,
339
+ .site-nav a:focus-visible,
340
+ .site-nav a[aria-current='page'],
341
+ .mobile-nav-panel a:hover,
342
+ .mobile-nav-panel a:focus-visible,
343
+ .mobile-nav-panel a[aria-current='page'] {
344
+ color: var(--site-top-text-color, var(--color-primary-text));
345
+ }
346
+
347
+ .site-nav > ul > .site-nav-item > a:hover,
348
+ .site-nav > ul > .site-nav-item > a:focus-visible,
349
+ .site-nav > ul > .site-nav-item > a[aria-current='page'],
350
+ .site-nav > ul > .site-nav-item-current-branch > a {
351
+ text-decoration: underline;
352
+ text-decoration-thickness: 1px;
353
+ text-underline-offset: 0.35em;
354
+ }
355
+
356
+ .site-nav-submenu {
357
+ position: absolute;
358
+ top: 100%;
359
+ left: 50%;
360
+ z-index: 10;
361
+ width: max-content;
362
+ max-width: min(24rem, calc(100vw - (var(--content-gutter) * 2)));
363
+ min-width: 12rem;
364
+ padding-top: 0.7rem;
365
+ opacity: 0;
366
+ visibility: hidden;
367
+ pointer-events: none;
368
+ transform: translate(-50%, -0.35rem);
369
+ transition: opacity 0.16s ease, transform 0.16s ease, visibility 0.16s ease;
370
+ }
371
+
372
+ .site-nav-submenu > nav {
373
+ border: 1px solid color-mix(in srgb, currentColor 30%, transparent);
374
+ padding: 0.8rem 1rem;
375
+ background: var(--site-top-background-color, var(--color-page));
376
+ box-shadow: 0 1rem 2.5rem rgb(0 0 0 / 0.22);
377
+ }
378
+
379
+ .site-nav-submenu ul {
380
+ display: grid;
381
+ gap: 0.65rem;
382
+ }
383
+
384
+ .site-nav-submenu .navigation-page-tree-submenu {
385
+ gap: 0.75rem;
386
+ }
387
+
388
+ .site-nav-submenu .navigation-page-tree-submenu .navigation-page-tree-submenu {
389
+ margin: 0.15rem 0 0 0.35rem;
390
+ border-left: 1px solid color-mix(in srgb, currentColor 24%, transparent);
391
+ padding-left: 0.75rem;
392
+ }
393
+
394
+ .site-nav-submenu .navigation-page-link {
395
+ font-weight: 650;
396
+ }
397
+
398
+ .site-nav-submenu a {
399
+ font-size: 0.76rem;
400
+ letter-spacing: 0.03em;
401
+ line-height: 1.3;
402
+ text-transform: none;
403
+ white-space: normal;
404
+ }
405
+
406
+ .site-nav-submenu a:hover,
407
+ .site-nav-submenu a:focus-visible,
408
+ .site-nav-submenu a[aria-current='location'] {
409
+ color: var(--site-top-text-color, var(--color-primary-text));
410
+ text-decoration: underline;
411
+ text-underline-offset: 0.25em;
412
+ }
413
+
414
+ .site-nav-item:hover .site-nav-submenu,
415
+ .site-nav-item:focus-within .site-nav-submenu {
416
+ opacity: 1;
417
+ visibility: visible;
418
+ pointer-events: auto;
419
+ transform: translate(-50%, 0);
420
+ }
421
+
422
+ .site-nav-item[data-submenu-dismissed='true'] .site-nav-submenu {
423
+ opacity: 0;
424
+ visibility: hidden;
425
+ pointer-events: none;
426
+ transform: translate(-50%, -0.35rem);
427
+ }
428
+
429
+ .mobile-nav-menu {
430
+ display: none;
431
+ }
432
+
433
+ .page-nav {
434
+ border-top: 1px solid color-mix(in srgb, currentColor 14%, transparent);
435
+ }
436
+
437
+ .site-top:not(.site-top-has-navigation-row) .page-nav {
438
+ border-top: 0;
439
+ }
440
+
441
+ .page-nav-inner {
442
+ display: flex;
443
+ align-items: center;
444
+ justify-content: center;
445
+ gap: clamp(1.1rem, 2.5vw, 2rem);
446
+ width: min(calc(100% - (var(--content-gutter) * 2)), var(--page-width));
447
+ margin: 0 auto;
448
+ }
449
+
450
+ .page-nav-label {
451
+ flex: 0 0 auto;
452
+ font-size: 0.7rem;
453
+ font-weight: 650;
454
+ letter-spacing: 0.08em;
455
+ color: var(--color-secondary-text);
456
+ text-transform: uppercase;
457
+ white-space: nowrap;
458
+ }
459
+
460
+ .page-nav ul {
461
+ display: flex;
462
+ flex-wrap: wrap;
463
+ justify-content: flex-start;
464
+ gap: 0 clamp(1.4rem, 4vw, 3.25rem);
465
+ margin: 0;
466
+ padding: 0;
467
+ list-style: none;
468
+ }
469
+
470
+ .page-nav li {
471
+ position: relative;
472
+ }
473
+
474
+ .page-nav li + li::before {
475
+ position: absolute;
476
+ top: 50%;
477
+ left: calc(clamp(1.4rem, 4vw, 3.25rem) / -2 - 0.1rem);
478
+ transform: translateY(-50%);
479
+ content: "·";
480
+ font-size: 0.75rem;
481
+ opacity: 0.28;
482
+ }
483
+
484
+ .page-nav a {
485
+ display: block;
486
+ min-height: var(--target-size-minimum);
487
+ padding: 1.05rem 0 0.95rem;
488
+ color: var(--color-secondary-text);
489
+ font-size: 0.76rem;
490
+ font-weight: 500;
491
+ letter-spacing: 0.08em;
492
+ line-height: 1.2;
493
+ text-decoration: none;
494
+ text-transform: uppercase;
495
+ }
496
+
497
+ .page-nav a:hover,
498
+ .page-nav a:focus-visible,
499
+ .page-nav a[aria-current='location'] {
500
+ color: var(--site-top-text-color, var(--color-primary-text));
501
+ text-decoration: underline;
502
+ text-decoration-thickness: 1px;
503
+ text-underline-offset: 0.35em;
504
+ }
505
+
506
+ .page-nav .page-nav-page-top {
507
+ font-size: 0.82rem;
508
+ font-weight: 700;
509
+ }
510
+
511
+ .page-nav-page-top-item:not(:last-child) {
512
+ margin-right: clamp(0.3rem, 1vw, 0.7rem);
513
+ }
514
+
515
+ .mobile-nav-sections a[aria-current='location'] {
516
+ opacity: 1;
517
+ text-decoration: underline;
518
+ text-decoration-thickness: 1px;
519
+ text-underline-offset: 0.35em;
520
+ }
521
+
522
+ @media (hover: hover) and (pointer: fine) {
523
+ :root {
524
+ --nav-top-safety-inset: 0.625rem;
525
+ }
526
+ }