@janga/norna 0.7.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.
- package/LICENSE +674 -0
- package/README.md +109 -0
- package/astro.config.mjs +17 -0
- package/bin/norna.mjs +170 -0
- package/docs/README.md +48 -0
- package/docs/command-organization.md +402 -0
- package/docs/commands.md +152 -0
- package/docs/configuration.md +376 -0
- package/docs/content.md +384 -0
- package/docs/engine-development.md +164 -0
- package/docs/getting-started.md +96 -0
- package/docs/images-and-metadata.md +88 -0
- package/docs/local-development.md +61 -0
- package/docs/publishing.md +81 -0
- package/docs/site-examples-structure-note.md +105 -0
- package/docs/site-structure.md +81 -0
- package/fixtures/basic/site/.norna/generated-images.json +1 -0
- package/fixtures/basic/site/config.mjs +59 -0
- package/fixtures/basic/site/content.md +17 -0
- package/fixtures/basic/site/images/work/.gitkeep +1 -0
- package/fixtures/basic/site/public/robots.txt +2 -0
- package/fixtures/basic/site/theme.md +7 -0
- package/package.json +90 -0
- package/scripts/build-site.mjs +16 -0
- package/scripts/check-config.mjs +37 -0
- package/scripts/deploy-site.mjs +389 -0
- package/scripts/dev-local.mjs +313 -0
- package/scripts/doctor.mjs +38 -0
- package/scripts/engine-version.mjs +137 -0
- package/scripts/generate-images.mjs +369 -0
- package/scripts/init-site.mjs +249 -0
- package/scripts/lib/astro-command.mjs +34 -0
- package/scripts/lib/ci-lockfile.mjs +34 -0
- package/scripts/lib/image-dimensions.mjs +78 -0
- package/scripts/lib/presentation.mjs +72 -0
- package/scripts/lib/project-config.mjs +322 -0
- package/scripts/lib/run-command.mjs +21 -0
- package/scripts/lib/site-content.mjs +392 -0
- package/scripts/lib/site-paths.mjs +127 -0
- package/scripts/lib/typography.mjs +166 -0
- package/scripts/release.mjs +77 -0
- package/scripts/show-typography.mjs +210 -0
- package/scripts/sync-content-sections.mjs +610 -0
- package/scripts/sync-site-public.mjs +42 -0
- package/scripts/test-ci-lockfile.mjs +65 -0
- package/scripts/test-content-check.mjs +364 -0
- package/scripts/test-engine-commands.mjs +128 -0
- package/scripts/test-navigation-preview.mjs +108 -0
- package/scripts/test-navigation.mjs +116 -0
- package/scripts/test-package-check.mjs +394 -0
- package/scripts/test-site-public.mjs +85 -0
- package/scripts/test-temporary-visibility.mjs +99 -0
- package/scripts/update-engine.mjs +127 -0
- package/scripts/watch-pages-deploy.mjs +430 -0
- package/src/components/GalleryGrid.astro +221 -0
- package/src/components/SiteNavigation.astro +410 -0
- package/src/components/SitePage.astro +69 -0
- package/src/components/SiteSection.astro +174 -0
- package/src/content.config.ts +171 -0
- package/src/layouts/BaseLayout.astro +90 -0
- package/src/lib/generatedImages.ts +63 -0
- package/src/lib/sectionContent.ts +125 -0
- package/src/lib/sitePages.ts +80 -0
- package/src/lib/sitePublicAssets.ts +39 -0
- package/src/lib/visibility.ts +35 -0
- package/src/pages/[slug].astro +31 -0
- package/src/pages/index.astro +16 -0
- package/src/styles/global.css +872 -0
- package/starters/basic/.github/workflows/deploy.yml +65 -0
- package/starters/basic/README.md +55 -0
- package/starters/basic/package.json +35 -0
- package/starters/basic/site/config.mjs +60 -0
- package/starters/basic/site/content.md +21 -0
- package/starters/basic/site/images/work/.gitkeep +1 -0
- package/starters/basic/site/public/robots.txt +2 -0
- package/starters/basic/site/theme.md +53 -0
- package/tsconfig.json +5 -0
package/docs/content.md
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
# Content
|
|
2
|
+
|
|
3
|
+
`site/content.md` is the editable page file for the homepage of a
|
|
4
|
+
`norna` site. Optional route pages use
|
|
5
|
+
`site/routes/<route-folder>/route-content.md` with the same page frontmatter and
|
|
6
|
+
Markdown section model.
|
|
7
|
+
|
|
8
|
+
Site-wide visual defaults may live in `site/theme.md`. Technical site
|
|
9
|
+
configuration lives in `site/config.mjs`.
|
|
10
|
+
|
|
11
|
+
## Frontmatter Schema
|
|
12
|
+
|
|
13
|
+
The Astro content schema validates these top-level fields in page files:
|
|
14
|
+
|
|
15
|
+
- `title`: required string. Rendered as the document title.
|
|
16
|
+
- `description`: required string. Rendered as the meta description.
|
|
17
|
+
- `slug`: optional route URL slug. It is ignored on the homepage. If omitted on
|
|
18
|
+
a route page, the route folder name is used.
|
|
19
|
+
- `navigation`: optional page navigation metadata.
|
|
20
|
+
- `presentation`: optional page-level presentation overrides.
|
|
21
|
+
- `frame`: optional page-level frame color source.
|
|
22
|
+
- `sections`: required non-empty array. Defines section order, ids,
|
|
23
|
+
presentation overrides, and gallery rows.
|
|
24
|
+
|
|
25
|
+
`navigation` may contain:
|
|
26
|
+
|
|
27
|
+
- `include`: optional boolean. Defaults to `true`.
|
|
28
|
+
- `label`: optional string. Defaults to `title`.
|
|
29
|
+
- `order`: optional integer. Defaults to `0` for the homepage and `100` for
|
|
30
|
+
route pages.
|
|
31
|
+
|
|
32
|
+
Each `sections[]` item has:
|
|
33
|
+
|
|
34
|
+
- `id`: required string matching `^[a-z0-9-]+$`. Used for anchors, navigation,
|
|
35
|
+
image directories, and Markdown heading ids.
|
|
36
|
+
- `visible`: optional date window that controls whether the section is rendered.
|
|
37
|
+
- `presentation`: optional object with `backgroundColor`, `textColor`, and/or
|
|
38
|
+
`typography` overrides.
|
|
39
|
+
- `gallery`: optional array, defaulting to `[]`.
|
|
40
|
+
|
|
41
|
+
Each gallery row has:
|
|
42
|
+
|
|
43
|
+
- `image`: required filename matching `^[a-z0-9][a-z0-9.-]*\.(jpe?g|png)$`.
|
|
44
|
+
It must be a filename, not a path.
|
|
45
|
+
- `alt`: required string.
|
|
46
|
+
- `caption`: optional string.
|
|
47
|
+
|
|
48
|
+
## Routes
|
|
49
|
+
|
|
50
|
+
The homepage is always `site/content.md` and builds to `/`.
|
|
51
|
+
|
|
52
|
+
Add a first-level route by creating:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
site/routes/about/route-content.md
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Minimal route page:
|
|
59
|
+
|
|
60
|
+
```md
|
|
61
|
+
---
|
|
62
|
+
title: About
|
|
63
|
+
description: About this gallery.
|
|
64
|
+
navigation:
|
|
65
|
+
label: About
|
|
66
|
+
order: 20
|
|
67
|
+
sections:
|
|
68
|
+
- id: intro
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Intro {#intro}
|
|
72
|
+
|
|
73
|
+
Text...
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The example above builds to `/about/`. If `slug` is omitted, the route folder
|
|
77
|
+
name is used. If `slug` is set, it must use lowercase letters, numbers, and
|
|
78
|
+
hyphens. Keep the route folder and `slug` aligned unless you intentionally need
|
|
79
|
+
a different URL.
|
|
80
|
+
|
|
81
|
+
Route images live under the route:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
site/routes/about/images/intro/image.jpg
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Image references in route frontmatter still use only the filename.
|
|
88
|
+
|
|
89
|
+
### Navigation Scope
|
|
90
|
+
|
|
91
|
+
Current route navigation is intended for small sites. This guidance may change
|
|
92
|
+
as route support matures, but the present model is:
|
|
93
|
+
|
|
94
|
+
- A single-page site should normally use only page navigation between sections.
|
|
95
|
+
- A small multi-page site may use site navigation between routes plus page
|
|
96
|
+
navigation between sections on the current page.
|
|
97
|
+
- If a site needs many routes, deeply nested routes, or several navigation
|
|
98
|
+
levels, it has probably outgrown the current sticky-navigation model and may
|
|
99
|
+
need a different site structure or navigation system.
|
|
100
|
+
|
|
101
|
+
## Site Theme
|
|
102
|
+
|
|
103
|
+
`site/theme.md` optionally defines site-wide visual defaults. It uses
|
|
104
|
+
frontmatter and does not need a Markdown body. If the file is missing, built-in
|
|
105
|
+
engine defaults are used.
|
|
106
|
+
|
|
107
|
+
Starter sites include a marked comment block such as
|
|
108
|
+
`norna:start theme-help` / `norna:end theme-help`. The block is
|
|
109
|
+
only explorable help text; YAML comments do not affect rendering. The active
|
|
110
|
+
configuration is the uncommented YAML below it.
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
---
|
|
114
|
+
# norna:start theme-help
|
|
115
|
+
# Site-wide visual defaults. Remove a value to use the engine default.
|
|
116
|
+
# norna:end theme-help
|
|
117
|
+
|
|
118
|
+
presentation:
|
|
119
|
+
backgroundColor: "#000000"
|
|
120
|
+
textColor: "#f7f4ee"
|
|
121
|
+
inlineStyles:
|
|
122
|
+
highlight:
|
|
123
|
+
color: "#ffd84d"
|
|
124
|
+
typography:
|
|
125
|
+
preset: quiet-gallery
|
|
126
|
+
frame:
|
|
127
|
+
colors: presentation
|
|
128
|
+
---
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`presentation.backgroundColor` and `presentation.textColor` are optional quoted
|
|
132
|
+
hex colors in `#rgb`, `#rrggbb`, or `#rrggbbaa` form.
|
|
133
|
+
|
|
134
|
+
`presentation.inlineStyles` defines named inline text styles that can be used
|
|
135
|
+
from Markdown. Inline style names must match `^[a-z][a-z0-9-]*$`. Each style
|
|
136
|
+
currently supports a required `color` field using the same quoted hex color
|
|
137
|
+
format as `textColor`.
|
|
138
|
+
|
|
139
|
+
`frame.colors` controls the sticky navigation and footer colors:
|
|
140
|
+
|
|
141
|
+
- `presentation`: use the resolved presentation colors for this level.
|
|
142
|
+
- `theme`: use the site theme frame colors. This is useful in page-level
|
|
143
|
+
frontmatter.
|
|
144
|
+
- explicit colors:
|
|
145
|
+
|
|
146
|
+
```yaml
|
|
147
|
+
frame:
|
|
148
|
+
colors:
|
|
149
|
+
backgroundColor: "#111111"
|
|
150
|
+
textColor: "#eeeeee"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Temporary Sections
|
|
154
|
+
|
|
155
|
+
Use `sections[].visible` for sections that should be rendered only during a
|
|
156
|
+
date window:
|
|
157
|
+
|
|
158
|
+
```yaml
|
|
159
|
+
sections:
|
|
160
|
+
- id: exhibition
|
|
161
|
+
visible:
|
|
162
|
+
from: "2026-08-01"
|
|
163
|
+
until: "2026-09-16"
|
|
164
|
+
gallery: []
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`from` is inclusive. `until` is exclusive. With the example above, the section
|
|
168
|
+
is visible from 2026-08-01 through 2026-09-15 and hidden again on 2026-09-16.
|
|
169
|
+
|
|
170
|
+
Both `from` and `until` use `YYYY-MM-DD`. Either value may be omitted, but a
|
|
171
|
+
`visible` object must contain at least one of them.
|
|
172
|
+
|
|
173
|
+
Hidden sections are omitted from the rendered HTML and sticky navigation. They
|
|
174
|
+
remain in `content.md`, and `content:check` still validates their matching
|
|
175
|
+
Markdown headings and gallery image references.
|
|
176
|
+
|
|
177
|
+
The current date is evaluated at dev/build time. Set `NORNA_TODAY` to
|
|
178
|
+
preview or test a specific date:
|
|
179
|
+
|
|
180
|
+
```sh
|
|
181
|
+
NORNA_TODAY=2026-08-15 npm run norna:build
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Presentation
|
|
185
|
+
|
|
186
|
+
Site-wide presentation belongs in `site/theme.md`. Page-level presentation in
|
|
187
|
+
`site/content.md` is always an override on top of the theme. Section-specific
|
|
188
|
+
presentation belongs under `sections[].presentation`.
|
|
189
|
+
|
|
190
|
+
If a page omits `presentation`, it uses the theme presentation unchanged. If a
|
|
191
|
+
section omits `presentation`, it uses the resolved page presentation.
|
|
192
|
+
|
|
193
|
+
```yaml
|
|
194
|
+
presentation:
|
|
195
|
+
typography:
|
|
196
|
+
overrides:
|
|
197
|
+
body:
|
|
198
|
+
paragraphSpacing: 1em
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Typography Presets
|
|
202
|
+
|
|
203
|
+
Typographic presentation is configured through presets with optional overrides:
|
|
204
|
+
|
|
205
|
+
```yaml
|
|
206
|
+
presentation:
|
|
207
|
+
typography:
|
|
208
|
+
preset: quiet-gallery
|
|
209
|
+
overrides:
|
|
210
|
+
body:
|
|
211
|
+
paragraphSpacing: 0.8em
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Available presets:
|
|
215
|
+
|
|
216
|
+
- `quiet-gallery`: the default for image-led art and portfolio sites. Text is
|
|
217
|
+
restrained and supports the images without dominating the page.
|
|
218
|
+
- `compact-gallery`: tighter typography for many sections, many images, or
|
|
219
|
+
short information blocks.
|
|
220
|
+
- `text-forward`: more generous body text for pages where longer text carries
|
|
221
|
+
more of the experience.
|
|
222
|
+
- `statement`: stronger type for introductions, first sections, and short
|
|
223
|
+
programmatic statements. Use it sparingly, usually as a section override.
|
|
224
|
+
|
|
225
|
+
The normal place to choose a site-wide preset is `site/theme.md`. If theme
|
|
226
|
+
typography is omitted, `quiet-gallery` is used. A page-level
|
|
227
|
+
`presentation.typography.preset` changes the typographic base for the page. A
|
|
228
|
+
section-level `sections[].presentation.typography.preset` changes the
|
|
229
|
+
typographic base for that section.
|
|
230
|
+
|
|
231
|
+
Use this command to inspect the exact preset values shipped with the installed
|
|
232
|
+
engine:
|
|
233
|
+
|
|
234
|
+
```sh
|
|
235
|
+
norna typography:presets
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Use this command to inspect the effective values for the selected site after
|
|
239
|
+
presets and overrides have been applied:
|
|
240
|
+
|
|
241
|
+
```sh
|
|
242
|
+
norna typography:show
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
The typographic roles are:
|
|
246
|
+
|
|
247
|
+
- `heading`: section headings.
|
|
248
|
+
- `body`: Markdown body text inside sections.
|
|
249
|
+
- `caption`: gallery captions.
|
|
250
|
+
|
|
251
|
+
Allowed alignment values are `left`, `center`, and `right`. Alignment can be
|
|
252
|
+
responsive:
|
|
253
|
+
|
|
254
|
+
```yaml
|
|
255
|
+
align:
|
|
256
|
+
desktop: left
|
|
257
|
+
mobile: center
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Allowed size values are `small`, `medium`, `large`, and `xlarge`.
|
|
261
|
+
`lineHeight` is a unitless number from `1` through `3`. `spacing` and
|
|
262
|
+
`paragraphSpacing` are CSS lengths such as `0`, `0.8em`, `1rem`, or `12px`.
|
|
263
|
+
|
|
264
|
+
Supported override fields:
|
|
265
|
+
|
|
266
|
+
- `heading.align`, `heading.size`, `heading.lineHeight`, `heading.spacing`
|
|
267
|
+
- `body.align`, `body.size`, `body.lineHeight`, `body.paragraphSpacing`
|
|
268
|
+
- `caption.align`, `caption.size`, `caption.lineHeight`, `caption.spacing`
|
|
269
|
+
|
|
270
|
+
Use `site/theme.md` `presentation.inlineStyles` for named inline text styles
|
|
271
|
+
that can be applied inside Markdown:
|
|
272
|
+
|
|
273
|
+
```yaml
|
|
274
|
+
presentation:
|
|
275
|
+
inlineStyles:
|
|
276
|
+
highlight:
|
|
277
|
+
color: "#ffd84d"
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Apply an inline style in Markdown with `[text]{.style-name}`:
|
|
281
|
+
|
|
282
|
+
```md
|
|
283
|
+
This sentence contains [highlighted text]{.highlight}.
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
`content:check` fails if Markdown uses an inline style that is not defined in
|
|
287
|
+
`site/theme.md` `presentation.inlineStyles`.
|
|
288
|
+
|
|
289
|
+
`sections[].presentation` contains only section-specific differences:
|
|
290
|
+
|
|
291
|
+
```yaml
|
|
292
|
+
sections:
|
|
293
|
+
- id: intro
|
|
294
|
+
presentation:
|
|
295
|
+
backgroundColor: "#161616"
|
|
296
|
+
textColor: "#ffffff"
|
|
297
|
+
typography:
|
|
298
|
+
preset: statement
|
|
299
|
+
overrides:
|
|
300
|
+
body:
|
|
301
|
+
paragraphSpacing: 0.7em
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
If a section sets `typography.preset`, that section starts from that preset. If
|
|
305
|
+
a section only sets `typography.overrides`, it keeps the resolved page preset
|
|
306
|
+
and changes only the specified values.
|
|
307
|
+
|
|
308
|
+
Centered text uses narrower text widths. Left- or right-aligned heading and body
|
|
309
|
+
text use the calculated gallery layout width so text edges line up with gallery
|
|
310
|
+
images after layout gutters and gallery limits are applied.
|
|
311
|
+
Configured section backgrounds render as full-width horizontal bands while the
|
|
312
|
+
section content keeps the normal page and gallery widths. The top spacing
|
|
313
|
+
before the first heading, the spacing between sections, and the spacing after
|
|
314
|
+
the final section are part of the section background. The sticky section
|
|
315
|
+
navigation row and footer use the resolved frame colors, not section-specific
|
|
316
|
+
presentation.
|
|
317
|
+
Configured section text colors apply to section headings, Markdown text,
|
|
318
|
+
Markdown subheadings, and gallery captions. Links keep the global accent color.
|
|
319
|
+
|
|
320
|
+
## Markdown Sections
|
|
321
|
+
|
|
322
|
+
Every frontmatter section must have a matching level 2 Markdown heading with an
|
|
323
|
+
explicit id:
|
|
324
|
+
|
|
325
|
+
```md
|
|
326
|
+
## Work {#work}
|
|
327
|
+
|
|
328
|
+
Introductory text.
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Keep these values aligned:
|
|
332
|
+
|
|
333
|
+
- the frontmatter `sections[].id`
|
|
334
|
+
- the Markdown heading id
|
|
335
|
+
- the source image directory `site/images/<section-id>/`
|
|
336
|
+
|
|
337
|
+
The visible navigation label comes from the Markdown heading text, not from the
|
|
338
|
+
frontmatter id.
|
|
339
|
+
|
|
340
|
+
## Validation And Sync
|
|
341
|
+
|
|
342
|
+
Run:
|
|
343
|
+
|
|
344
|
+
```sh
|
|
345
|
+
npm run norna:content:check
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
This checks section order and heading ids, duplicate image names, missing image
|
|
349
|
+
files, misplaced referenced images, duplicate gallery references, invalid image
|
|
350
|
+
references, unreferenced images, undefined inline styles, and common
|
|
351
|
+
frontmatter indentation and structure mistakes.
|
|
352
|
+
|
|
353
|
+
Frontmatter uses YAML indentation. Use ordinary spaces, not tabs or
|
|
354
|
+
non-breaking spaces. `content:check` reports a focused error when indentation is
|
|
355
|
+
invalid, when a key is indented under a line that already has a value, or when
|
|
356
|
+
a known nested key such as `gallery` appears at the top level:
|
|
357
|
+
|
|
358
|
+
```yaml
|
|
359
|
+
typography:
|
|
360
|
+
preset: quiet-gallery
|
|
361
|
+
overrides:
|
|
362
|
+
body:
|
|
363
|
+
paragraphSpacing: 0.8em
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Top-level page frontmatter may contain only `title`, `description`,
|
|
367
|
+
`presentation`, `frame`, and `sections`. A `gallery` key belongs under one
|
|
368
|
+
`sections[]` item:
|
|
369
|
+
|
|
370
|
+
```yaml
|
|
371
|
+
sections:
|
|
372
|
+
- id: work
|
|
373
|
+
gallery: []
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Run:
|
|
377
|
+
|
|
378
|
+
```sh
|
|
379
|
+
npm run norna:sync
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
This rewrites Markdown sections into frontmatter order and moves referenced
|
|
383
|
+
image files into the directory matching their section. It prompts before
|
|
384
|
+
writing unless `--yes` is passed.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Engine Development
|
|
2
|
+
|
|
3
|
+
This document is for work on the reusable `norna` package itself.
|
|
4
|
+
|
|
5
|
+
## Main Areas
|
|
6
|
+
|
|
7
|
+
- `bin/norna.mjs`: public CLI dispatcher.
|
|
8
|
+
- `scripts/lib/site-paths.mjs`: engine/site path resolution.
|
|
9
|
+
- `scripts/lib/project-config.mjs`: `site/config.mjs` validation and defaults.
|
|
10
|
+
- `scripts/sync-content-sections.mjs`: content validation and sync behavior.
|
|
11
|
+
- `scripts/generate-images.mjs`: WebP image pipeline and manifest.
|
|
12
|
+
- `scripts/sync-site-public.mjs`: static public file sync.
|
|
13
|
+
- `scripts/deploy-site.mjs`: deploy and deploy:commit behavior.
|
|
14
|
+
- `scripts/watch-pages-deploy.mjs`: GitHub Pages workflow monitor.
|
|
15
|
+
- `src/content.config.ts`: Astro content schema.
|
|
16
|
+
- `src/components/` and `src/layouts/`: rendered page, navigation, gallery, and
|
|
17
|
+
layout.
|
|
18
|
+
- `tests/`: Playwright navigation diagnostics.
|
|
19
|
+
- `fixtures/basic/site/`: minimal site used for engine checks.
|
|
20
|
+
- `starters/basic/`: copyable site starter.
|
|
21
|
+
|
|
22
|
+
The repository-local `site/` directory is a dog-gallery demo. It is useful for
|
|
23
|
+
manual engine checks, but it is not a published site.
|
|
24
|
+
|
|
25
|
+
## Common Checks
|
|
26
|
+
|
|
27
|
+
Run focused checks while developing:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
npm run test:content-check
|
|
31
|
+
npm run test:site-public
|
|
32
|
+
npm run test:fixture:build
|
|
33
|
+
npm run demo:build
|
|
34
|
+
npm run package:check
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`npm run test` runs the same set in sequence.
|
|
38
|
+
|
|
39
|
+
Navigation diagnostics are separate because they use Playwright:
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
npm run test:navigation
|
|
43
|
+
npm run test:navigation:stress
|
|
44
|
+
npm run test:navigation:preview
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
If Chromium is missing:
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
npx playwright install chromium
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Package Check
|
|
54
|
+
|
|
55
|
+
`npm run package:check` packs this repository, extracts the package, copies the
|
|
56
|
+
packaged starter into a temporary site project, installs dependencies, runs
|
|
57
|
+
`norna doctor` from a site subdirectory, runs config/content checks,
|
|
58
|
+
builds the installed site, and verifies selected rendered output and validation
|
|
59
|
+
failures.
|
|
60
|
+
|
|
61
|
+
It needs network access when npm dependencies are not already cached.
|
|
62
|
+
The check uses a reusable npm cache at
|
|
63
|
+
`node_modules/.cache/norna-package-check-npm` and runs npm with
|
|
64
|
+
`--prefer-offline` so repeat runs do not redownload dependencies. Set
|
|
65
|
+
`NORNA_PACKAGE_CHECK_CACHE=/path/to/cache` to use another cache.
|
|
66
|
+
|
|
67
|
+
## CI Lockfiles
|
|
68
|
+
|
|
69
|
+
Site repositories are developed on different operating systems but deployed on
|
|
70
|
+
GitHub Actions Linux. `engine:update` therefore normalizes `package-lock.json`
|
|
71
|
+
with npm 11.16.0 for Linux x64 glibc and verifies a clean install before it runs
|
|
72
|
+
the site checks. The starter workflow pins Node 24.18.0, which provides the
|
|
73
|
+
same npm version.
|
|
74
|
+
|
|
75
|
+
`npm run test:ci-lockfile` recreates and repairs the optional npm peer-dependency
|
|
76
|
+
case that previously caused GitHub Actions `npm ci` failures.
|
|
77
|
+
|
|
78
|
+
## Test The Package In A Site Repository
|
|
79
|
+
|
|
80
|
+
> **Warning:** `npm link` is not supported for `norna`. Astro resolves
|
|
81
|
+
> renderer modules and runtime dependencies differently when the package is a
|
|
82
|
+
> symlink, so a linked site can fail to start even though the published package
|
|
83
|
+
> works. Do not use `npm link @janga/norna` to test a site.
|
|
84
|
+
|
|
85
|
+
Use `npm run package:check` to test the package before release. To test a
|
|
86
|
+
specific published engine version in a real site, update it with:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
npm run norna:engine:update -- <version>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Commit the resulting `package.json` and `package-lock.json` changes in the
|
|
93
|
+
site repository after the site's normal checks pass.
|
|
94
|
+
|
|
95
|
+
## npm Release
|
|
96
|
+
|
|
97
|
+
The npm package is published under the `@janga` scope. Choose the release type
|
|
98
|
+
when starting a release; the command requires a clean working tree, verifies npm
|
|
99
|
+
registry authentication for the same registry/cache used by `release:publish`,
|
|
100
|
+
runs `npm test`, requires a clean working tree after the checks, updates
|
|
101
|
+
`package.json` and `package-lock.json`, creates the release commit and Git tag,
|
|
102
|
+
publishes to npm, then pushes the commit and tag.
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
npm run release:patch
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Use `patch` for backwards-compatible fixes and maintenance changes. Use `minor`
|
|
109
|
+
for backwards-compatible features and `major` for incompatible changes:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
npm run release:minor
|
|
113
|
+
npm run release:major
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The release command deliberately does not run GitHub Pages deployment monitoring.
|
|
117
|
+
If npm publication fails, it stops before pushing; the local version commit and
|
|
118
|
+
tag remain available for inspection or recovery.
|
|
119
|
+
|
|
120
|
+
If the npm authentication preflight fails, no version commit or tag has been
|
|
121
|
+
created yet. Run the printed login command:
|
|
122
|
+
|
|
123
|
+
```sh
|
|
124
|
+
npm login --registry=https://registry.npmjs.org/ --auth-type=web --cache /private/tmp/norna-npm-cache
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Then start the release command again.
|
|
128
|
+
|
|
129
|
+
After publication, update site repositories to the exact published npm version
|
|
130
|
+
and commit their updated `package-lock.json`.
|
|
131
|
+
|
|
132
|
+
## Rendering Notes
|
|
133
|
+
|
|
134
|
+
The renderer builds the homepage at `/` and optional first-level routes from
|
|
135
|
+
`site/routes/<route-folder>/route-content.md`.
|
|
136
|
+
|
|
137
|
+
Navigation has two separate levels:
|
|
138
|
+
|
|
139
|
+
- Site navigation moves between pages and routes. It uses normal page URLs and
|
|
140
|
+
browser history.
|
|
141
|
+
- Page navigation moves between sections on the current page. It uses real
|
|
142
|
+
`href="#section-id"` links so anchors work without JavaScript.
|
|
143
|
+
|
|
144
|
+
The current navigation model is deliberately scoped to single-page and small
|
|
145
|
+
multi-page sites. That scope may change as route support matures. For now,
|
|
146
|
+
single-page sites should rely on page navigation only; small route-based sites
|
|
147
|
+
may combine site navigation and page navigation; larger information
|
|
148
|
+
architectures should not be forced into the sticky-navigation model without a
|
|
149
|
+
separate design decision.
|
|
150
|
+
|
|
151
|
+
The JavaScript enhancement keeps the URL hash as the source of truth for active
|
|
152
|
+
page-navigation state. A section-link click pushes one hash entry into browser
|
|
153
|
+
history, back/forward moves between hash entries, and returning to the same page
|
|
154
|
+
without a hash restores the first section as active. The enhancement does not
|
|
155
|
+
derive active section state from free manual scrolling.
|
|
156
|
+
|
|
157
|
+
The sticky navigation updates root scroll offset variables so direct hash links
|
|
158
|
+
and clicked links land below the fixed header. Hash targets may be corrected
|
|
159
|
+
again after layout shifts such as image loading, but that correction must not
|
|
160
|
+
add history entries or change the active section independently of the URL hash.
|
|
161
|
+
|
|
162
|
+
The shared layout reads UI language and labels from `site/config.mjs`
|
|
163
|
+
`locale`. Keep editorial content in page Markdown and non-editorial engine UI
|
|
164
|
+
labels in config.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
This guide creates a new site repository from the included starter. It describes
|
|
4
|
+
the generic `norna` setup; site-specific content belongs in the new site
|
|
5
|
+
repository.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node.js `>=22.12.0`
|
|
10
|
+
- ImageMagick for image generation
|
|
11
|
+
- GitHub CLI (`gh`) for deploy checks and deploy monitoring
|
|
12
|
+
|
|
13
|
+
Install Playwright Chromium only when you plan to run navigation diagnostics:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npx playwright install chromium
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Create A Site Repository
|
|
20
|
+
|
|
21
|
+
Create the site from the starter first, then install dependencies inside the
|
|
22
|
+
new site directory:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
cd path/to/your/projects
|
|
26
|
+
npx @janga/norna@latest init my-gallery
|
|
27
|
+
cd my-gallery
|
|
28
|
+
npm install
|
|
29
|
+
npm run norna:dev
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
A freshly created empty directory is not a `norna` site yet. It becomes a
|
|
33
|
+
site when `init` copies the starter files, including `package.json`. If you run
|
|
34
|
+
`npm install` in an empty directory, npm may walk up to a parent directory and
|
|
35
|
+
install dependencies for another project instead.
|
|
36
|
+
|
|
37
|
+
For normal site work, keep site repositories as siblings of the `norna`
|
|
38
|
+
engine repository. For example:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
Projects/
|
|
42
|
+
norna/
|
|
43
|
+
my-gallery/
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The starter contains:
|
|
47
|
+
|
|
48
|
+
- `package.json` with npm scripts that call `norna`
|
|
49
|
+
- `.github/workflows/deploy.yml` for GitHub Pages
|
|
50
|
+
- `site/config.mjs`
|
|
51
|
+
- `site/theme.md`
|
|
52
|
+
- `site/content.md`
|
|
53
|
+
- `site/images/work/.gitkeep`
|
|
54
|
+
- `site/public/robots.txt`
|
|
55
|
+
|
|
56
|
+
Commit the generated `package-lock.json` after the first install.
|
|
57
|
+
|
|
58
|
+
## First Edits
|
|
59
|
+
|
|
60
|
+
1. Edit `site/config.mjs` for the site's URL, layout, font, language labels,
|
|
61
|
+
GitHub repository, footer, and deploy settings.
|
|
62
|
+
2. Edit `site/theme.md` for site-wide colors, typography preset, inline styles,
|
|
63
|
+
and frame colors, or omit it to use engine defaults.
|
|
64
|
+
3. Edit `site/content.md` for homepage title, description, sections, text,
|
|
65
|
+
gallery rows, page/section presentation overrides, alt text, and captions.
|
|
66
|
+
4. Put source images under `site/images/<section-id>/`.
|
|
67
|
+
5. Add optional route pages under
|
|
68
|
+
`site/routes/<route-folder>/route-content.md`.
|
|
69
|
+
6. Put static files such as `robots.txt`, `CNAME`, and favicons under
|
|
70
|
+
`site/public/`.
|
|
71
|
+
7. Run:
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
npm run norna:check
|
|
75
|
+
npm run build
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Read [Site Structure](site-structure.md), [Content](content.md), and
|
|
79
|
+
[Configuration](configuration.md) before publishing a real site.
|
|
80
|
+
|
|
81
|
+
To change the site's maximum page width, set `layout.pageWidth` in
|
|
82
|
+
`site/config.mjs`. To change side margins, set `layout.gutter`. To change the
|
|
83
|
+
maximum gallery width inside that page area, set `gallery.width`. To keep
|
|
84
|
+
images within a comfortable viewport height, set
|
|
85
|
+
`gallery.maxAvailableHeightPercent`. See [Configuration](configuration.md) for
|
|
86
|
+
the accepted formats and default values.
|
|
87
|
+
|
|
88
|
+
To change the site's font, set `typography.fontFamily` in `site/config.mjs`.
|
|
89
|
+
See [`typography.fontFamily`](configuration.md#typographyfontfamily) for the
|
|
90
|
+
accepted format and default value.
|
|
91
|
+
|
|
92
|
+
To change the site-wide typography preset, edit `site/theme.md`. To change one
|
|
93
|
+
page or section, add a focused `presentation.typography` override in
|
|
94
|
+
`site/content.md`. Use `npm run norna:typography:presets` to inspect the
|
|
95
|
+
installed preset values and `npm run norna:typography:show` to inspect the
|
|
96
|
+
resolved typography for the selected site.
|