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