@geekity/cms 0.11.0 → 0.12.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/README.md +7 -2
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +27 -12
- package/dist/web/render.js.map +1 -1
- package/package.json +7 -2
- package/themes/default/README.md +201 -110
- package/themes/default/layouts/404.njk +2 -0
- package/themes/default/layouts/500.njk +2 -0
- package/themes/default/layouts/503.njk +2 -0
- package/themes/default/layouts/author.njk +3 -1
- package/themes/default/layouts/base.njk +1 -1
- package/themes/default/layouts/category.njk +4 -2
- package/themes/default/layouts/front-page.njk +1 -1
- package/themes/default/layouts/page.njk +4 -2
- package/themes/default/layouts/post.njk +31 -22
- package/themes/default/layouts/search.njk +2 -5
- package/themes/default/layouts/tag.njk +7 -1
- package/themes/default/partials/comment-form.njk +8 -0
- package/themes/default/partials/contact-form.njk +3 -0
- package/themes/default/partials/conversation.njk +11 -4
- package/themes/default/partials/kicker.njk +34 -0
- package/themes/default/partials/post-list.njk +40 -46
- package/themes/default/partials/reply-context.njk +12 -5
- package/themes/default/src/style.css +1095 -0
- package/themes/default/static/style.css +2071 -1160
- package/themes/default/theme.json +1 -1
package/themes/default/README.md
CHANGED
|
@@ -23,6 +23,8 @@ themes/default/
|
|
|
23
23
|
post-list.njk the h-feed a listing is made of
|
|
24
24
|
pagination.njk previous/next pager
|
|
25
25
|
tags.njk macros for tag and category links
|
|
26
|
+
kicker.njk the line above an entry naming its kind and date
|
|
27
|
+
reply-context.njk the citation of what a reply answers
|
|
26
28
|
bio.njk who an entry is by, as an h-card
|
|
27
29
|
menu.njk one named menu, as a nav of links
|
|
28
30
|
feeds.njk macros for the feed links in <head>
|
|
@@ -39,12 +41,39 @@ themes/default/
|
|
|
39
41
|
comment-digest.*.njk the hourly or daily digest of what is waiting
|
|
40
42
|
comment-reply.*.njk the notice a commenter gets about a reply
|
|
41
43
|
contact-message.*.njk a message from a page's contact form
|
|
44
|
+
src/
|
|
45
|
+
style.css the stylesheet's source, compiled with Tailwind
|
|
42
46
|
static/
|
|
43
|
-
style.css served at /theme/style.css
|
|
47
|
+
style.css the compiled stylesheet, served at /theme/style.css
|
|
48
|
+
highlight.js the code highlighter
|
|
44
49
|
```
|
|
45
50
|
|
|
46
|
-
Plain Nunjucks and
|
|
47
|
-
|
|
51
|
+
Plain Nunjucks templates and one stylesheet. The stylesheet is written in
|
|
52
|
+
Tailwind v4 (`src/style.css`) and compiled when the package is built, so
|
|
53
|
+
`static/style.css` is a build product: gitignored in this repository, written
|
|
54
|
+
by `pnpm build` (which the root `prepare` runs after an install and before a
|
|
55
|
+
publish), and shipped in the package like every other file here. The compile
|
|
56
|
+
happens once, on the machine that builds the package. A reader gets one plain
|
|
57
|
+
CSS file and no script, web font or CDN request because of it.
|
|
58
|
+
|
|
59
|
+
The design is Paper (doc-9, decision-22): one warm column, serif throughout,
|
|
60
|
+
sans for small labels, and a kicker above every entry naming its kind.
|
|
61
|
+
|
|
62
|
+
**Rebuilding the stylesheet.** After editing `src/style.css`:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
pnpm --filter @geekity/cms build:theme
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Tailwind scans only this theme's `layouts/` and `partials/`, so a utility class
|
|
69
|
+
written in a template here is compiled in and nothing outside the theme is
|
|
70
|
+
read. The templates themselves use the semantic class names below and the look
|
|
71
|
+
lives in `src/style.css`, through `@apply`.
|
|
72
|
+
|
|
73
|
+
**A site theme owes Tailwind nothing.** Its own `static/style.css` replaces this
|
|
74
|
+
one wholesale, and any CSS that knows the class names in this README will do.
|
|
75
|
+
The demo theme's is plain CSS. A site that only wants different colours
|
|
76
|
+
overrides the `--color-*` custom properties instead; see [Colours](#colours).
|
|
48
77
|
|
|
49
78
|
## The manifest
|
|
50
79
|
|
|
@@ -145,9 +174,10 @@ words above the posts; `layouts/home.njk` already does.
|
|
|
145
174
|
|
|
146
175
|
## The page shell
|
|
147
176
|
|
|
148
|
-
`layouts/base.njk` is the
|
|
149
|
-
|
|
150
|
-
|
|
177
|
+
`layouts/base.njk` is the page shell: the skip link, one `.global-wrapper` at the
|
|
178
|
+
42rem measure, `.global-header`, `<main id="main">` and the footer, in that
|
|
179
|
+
order. The shape is the andrewshell.org design's (decision-16) and the look is
|
|
180
|
+
Paper's (doc-9).
|
|
151
181
|
|
|
152
182
|
**One home for each kind of link.** The header carries the site menu, on every
|
|
153
183
|
page. [The bio](#the-bio) carries the person whose page or post it is. The
|
|
@@ -156,7 +186,7 @@ nowhere else.
|
|
|
156
186
|
|
|
157
187
|
**The header has one rule, and the menu under it.** On the front page it is the
|
|
158
188
|
site title as `h1.main-heading`, linked home, with `site.tagline` in a
|
|
159
|
-
|
|
189
|
+
`p.site-tagline` under it; on every other page it is `a.header-link-home`, the site
|
|
160
190
|
title small and linked home, and no tagline. The wrapper carries
|
|
161
191
|
`data-is-root-path="true"` at `/` and nothing anywhere else, which is how the
|
|
162
192
|
stylesheet tells the two apart. `menus.primary` is printed inside the
|
|
@@ -260,13 +290,19 @@ html.geekity-admin-bar {
|
|
|
260
290
|
|
|
261
291
|
### An entry
|
|
262
292
|
|
|
263
|
-
`layouts/post.njk` and `layouts/page.njk` draw the same thing, the
|
|
264
|
-
|
|
293
|
+
`layouts/post.njk` and `layouts/page.njk` draw the same thing, the entry, and it
|
|
294
|
+
is a microformats2 `h-entry`. An article, and a page:
|
|
265
295
|
|
|
266
296
|
```html
|
|
267
297
|
<article class="blog-post h-entry">
|
|
268
|
-
<header>
|
|
298
|
+
<header class="post-header">
|
|
299
|
+
<p class="kicker">
|
|
300
|
+
<span class="kicker-kind">Article</span>
|
|
301
|
+
<span class="kicker-dot" aria-hidden="true">·</span>
|
|
302
|
+
<a href="/category/notes/" class="p-category" rel="category">notes</a>
|
|
303
|
+
</p>
|
|
269
304
|
<h1 class="p-name">Hello</h1>
|
|
305
|
+
<p class="post-deck p-summary">The description the author wrote.</p>
|
|
270
306
|
</header>
|
|
271
307
|
<section class="e-content">
|
|
272
308
|
<p>The rendered body.</p>
|
|
@@ -279,38 +315,47 @@ design's entry, and it is a microformats2 `h-entry`:
|
|
|
279
315
|
>Published 2 September 2026</time
|
|
280
316
|
></a
|
|
281
317
|
>
|
|
282
|
-
<
|
|
318
|
+
<span aria-hidden="true">·</span>
|
|
319
|
+
<time class="small dt-updated" datetime="2026-09-05T09:00:00.000Z"
|
|
283
320
|
>Updated 5 September 2026</time
|
|
284
321
|
>
|
|
285
322
|
</p>
|
|
286
323
|
</section>
|
|
287
|
-
<p class="post-categories">…categories…</p>
|
|
288
324
|
<p class="post-categories">…tags…</p>
|
|
289
325
|
<hr />
|
|
290
326
|
<footer>…the bio…</footer>
|
|
291
327
|
</article>
|
|
292
|
-
<nav class="blog-post-nav"
|
|
328
|
+
<nav class="blog-post-nav" aria-label="Neighbouring posts">…</nav>
|
|
293
329
|
```
|
|
294
330
|
|
|
331
|
+
**The kicker names the kind.** `p.kicker`, from `partials/kicker.njk`, opens
|
|
332
|
+
every entry: the kind word in `span.kicker-kind` (Article, Note or Reply for a
|
|
333
|
+
post, from its `postType`; Page for a page), then the categories it is filed
|
|
334
|
+
under as `p-category` links. It is the only place the kind is said, small and
|
|
335
|
+
once, and an article is additionally the only kind with a visible headline.
|
|
336
|
+
The deck is the front matter's `description` as a `p.post-deck.p-summary`,
|
|
337
|
+
printed only when the author wrote one.
|
|
338
|
+
|
|
295
339
|
**The Published line is inside the `e-content`**, which is the one thing about
|
|
296
340
|
this shape worth knowing. It is what the source theme does: the date and the
|
|
297
|
-
permalink are part of the words, so a reader
|
|
298
|
-
`e-content
|
|
299
|
-
time as a `u-url`, and a `dt-updated`
|
|
300
|
-
happened on a different day in the site's own timezone; a typo fixed
|
|
301
|
-
later is not news. A post tagged `indienews` opens the line with a
|
|
341
|
+
permalink are part of the words, so a reader, or a fediverse peer reading the
|
|
342
|
+
`e-content`, takes them with the post. The permalink wraps the `dt-published`
|
|
343
|
+
time as a `u-url`, and a `dt-updated` follows it after a middle dot only when
|
|
344
|
+
the update happened on a different day in the site's own timezone; a typo fixed
|
|
345
|
+
an hour later is not news. A post tagged `indienews` opens the line with a
|
|
302
346
|
`u-category` link to <https://news.indieweb.org/en>, which is how IndieNews is
|
|
303
347
|
told the post is for it; a page never prints one, and its line is a
|
|
304
348
|
`p.page-meta` rather than a `p.entry-meta`.
|
|
305
349
|
|
|
306
350
|
**Every post's page has one `h1`.** A post with a name of its own is headed by
|
|
307
351
|
it, as above. A note, or a reply without a title, opens on its words instead,
|
|
308
|
-
so it has no `header`; in its place is an `h1` a screen reader and
|
|
309
|
-
navigate by and a sighted reader never sees, saying what the post is,
|
|
310
|
-
it and when:
|
|
352
|
+
set larger, so it has no `header`; in its place is an `h1` a screen reader and
|
|
353
|
+
a crawler navigate by and a sighted reader never sees, saying what the post is,
|
|
354
|
+
who wrote it and when, and then the kicker:
|
|
311
355
|
|
|
312
356
|
```html
|
|
313
357
|
<h1 class="screen-reader-text">Note by Ada Lovelace, 11 September 2026</h1>
|
|
358
|
+
<p class="kicker"><span class="kicker-kind">Note</span></p>
|
|
314
359
|
```
|
|
315
360
|
|
|
316
361
|
It says `Reply` for a reply and leaves out the name or the date the post does
|
|
@@ -319,16 +364,24 @@ for an article. The headings under it step down one level at a time: the
|
|
|
319
364
|
conversation and the comment form are `h2`, and a refused form's error summary
|
|
320
365
|
is an `h3` inside the form's section.
|
|
321
366
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
367
|
+
**A reply cites what it answers** with `partials/reply-context.njk`, a
|
|
368
|
+
`div.reply-context.cite.u-in-reply-to.h-cite`: a rule on the start side, a
|
|
369
|
+
`p.cite-line` saying "In reply to" and the target's name, author and date as
|
|
370
|
+
far as they are known, and its excerpt as a `blockquote.cite-quote.p-content`.
|
|
371
|
+
An untitled reply prints it under the kicker; a titled reply prints it above
|
|
372
|
+
its header. The same partial cites a reply in a feed.
|
|
373
|
+
|
|
374
|
+
The tags are printed under the words and inside the article, so that each link
|
|
375
|
+
is a `p-category` of this entry, as one `p.post-categories` from
|
|
376
|
+
`partials/tags.njk`. The stylesheet draws the `#` in front of each, so the
|
|
377
|
+
category a parser reads is the tag and not the hash.
|
|
378
|
+
|
|
379
|
+
After the entry a post prints `nav.blog-post-nav`: the `previous` and `next`
|
|
380
|
+
posts as two cards, `rel="prev"` and `rel="next"`, each opening on a
|
|
381
|
+
`span.blog-post-nav-label`, and nothing at all at the ends of the archive; then
|
|
382
|
+
the conversation and the comment form. A page prints the contact form when its
|
|
383
|
+
front matter asked for one. A page has no neighbours, no tags and no IndieNews
|
|
384
|
+
link, because none of those are things a page has.
|
|
332
385
|
|
|
333
386
|
### The bio
|
|
334
387
|
|
|
@@ -387,49 +440,66 @@ byline under the title rather than a bio in the footer, so it writes one.
|
|
|
387
440
|
|
|
388
441
|
### A listing
|
|
389
442
|
|
|
390
|
-
`partials/post-list.njk` is the feed every listing is made of
|
|
391
|
-
the posts page, a tag, category or author archive
|
|
392
|
-
`h-feed
|
|
443
|
+
`partials/post-list.njk` is the feed every listing is made of (the home page,
|
|
444
|
+
the posts page, a tag, category or author archive, and the front page's recent
|
|
445
|
+
posts) and it is a microformats2 `h-feed` of `h-entry` items, each opening on
|
|
446
|
+
its kicker:
|
|
393
447
|
|
|
394
448
|
```html
|
|
395
449
|
<div class="feed h-feed">
|
|
396
450
|
<article class="feed-item h-entry">
|
|
397
|
-
<
|
|
398
|
-
<
|
|
399
|
-
|
|
400
|
-
</
|
|
401
|
-
<
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
<div class="feed-meta">
|
|
410
|
-
<p>
|
|
411
|
-
<time class="feed-date dt-published" datetime="…"
|
|
412
|
-
>2 September 2026</time
|
|
413
|
-
>
|
|
414
|
-
</p>
|
|
415
|
-
<p class="post-categories">
|
|
416
|
-
<a href="/category/notes/" class="p-category" rel="category">notes</a>
|
|
417
|
-
</p>
|
|
418
|
-
</div>
|
|
451
|
+
<p class="kicker">
|
|
452
|
+
<span class="kicker-kind">Article</span>
|
|
453
|
+
<span class="kicker-dot" aria-hidden="true">·</span>
|
|
454
|
+
<time class="feed-date dt-published" datetime="…">2 September 2026</time>
|
|
455
|
+
<span class="kicker-dot" aria-hidden="true">·</span>
|
|
456
|
+
<a href="/category/notes/" class="p-category" rel="category">notes</a>
|
|
457
|
+
</p>
|
|
458
|
+
<h2 class="feed-title p-name">
|
|
459
|
+
<a href="/2026/09/hello/" class="u-url">Hello</a>
|
|
460
|
+
</h2>
|
|
461
|
+
<div class="feed-excerpt p-summary">
|
|
462
|
+
<p>What the post is about, in about 280 characters...</p>
|
|
419
463
|
</div>
|
|
464
|
+
<p class="feed-more">
|
|
465
|
+
<a href="/2026/09/hello/" aria-label="Continue reading: Hello">
|
|
466
|
+
Continue reading<span aria-hidden="true"> →</span>
|
|
467
|
+
</a>
|
|
468
|
+
</p>
|
|
420
469
|
</article>
|
|
421
470
|
<hr class="feed-separator" />
|
|
422
|
-
<article class="feed-item h-entry"
|
|
471
|
+
<article class="feed-item h-entry">
|
|
472
|
+
<p class="kicker">
|
|
473
|
+
<span class="kicker-kind">Note</span>
|
|
474
|
+
<span class="kicker-dot" aria-hidden="true">·</span>
|
|
475
|
+
<a href="/2026/09/coffee/" class="u-url"
|
|
476
|
+
><time class="feed-date dt-published" datetime="…"
|
|
477
|
+
>3 September 2026</time
|
|
478
|
+
></a
|
|
479
|
+
>
|
|
480
|
+
</p>
|
|
481
|
+
<div class="feed-excerpt e-content"><p>The whole note.</p></div>
|
|
482
|
+
</article>
|
|
423
483
|
</div>
|
|
424
484
|
```
|
|
425
485
|
|
|
426
|
-
|
|
427
|
-
|
|
486
|
+
**Only an article has a headline.** A note, which has no title, is printed
|
|
487
|
+
whole as its `e-content`, and the date in its kicker is its `u-url`. A reply is
|
|
488
|
+
a note that first cites what it answers with `partials/reply-context.njk`, and
|
|
489
|
+
a reply with a title is an article that does. An article's categories are in
|
|
490
|
+
its kicker; a note's are on its own page.
|
|
491
|
+
|
|
492
|
+
The excerpt is the entry's `summary`, the very line the feeds publish, so a
|
|
493
|
+
reader and a feed cannot be told two different things, through Nunjucks'
|
|
428
494
|
`truncate(280)`, which cuts at the last space before 280 characters and adds an
|
|
429
495
|
ellipsis. A `description` shorter than that is printed whole. It is plain text
|
|
430
496
|
rather than markup, deliberately: an excerpt with half a code block in it is
|
|
431
497
|
not an excerpt.
|
|
432
498
|
|
|
499
|
+
Each entry of a listing carries `replyContext` beside `inReplyTo` when it is a
|
|
500
|
+
reply whose target has been fetched, the same object a reply's own page gets,
|
|
501
|
+
so the feed can cite it in full.
|
|
502
|
+
|
|
433
503
|
An entry's tags are not in a feed item. They belong under the entry, where
|
|
434
504
|
there is one post's worth of them rather than twenty.
|
|
435
505
|
|
|
@@ -445,21 +515,24 @@ before including it, so the outline never skips a level:
|
|
|
445
515
|
|
|
446
516
|
A listing with nothing on it says `No posts found.` in `p.empty`.
|
|
447
517
|
|
|
448
|
-
`partials/pagination.njk` prints two
|
|
518
|
+
`partials/pagination.njk` prints two links in `nav.pagination`, `← Previous`
|
|
449
519
|
to the page before this one and `Next →` to the page after it, with `rel="prev"`
|
|
450
|
-
and `rel="next"
|
|
520
|
+
and `rel="next"`, and nothing at all on a listing of one page. The arrows
|
|
451
521
|
themselves are `aria-hidden`, because a screen reader that announced them would
|
|
452
522
|
read the decoration and then the word.
|
|
453
523
|
|
|
454
524
|
Each listing layout heads its own page: `layouts/home.njk` with the listing's
|
|
455
|
-
title,
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
525
|
+
title, and the three archives with a `header.archive-header` whose kicker says
|
|
526
|
+
what kind of archive it is (Tag, Category, Author) over an `h1.page-title`
|
|
527
|
+
naming whose: the term, or the person, followed by their `h-card`. The
|
|
528
|
+
category archive's header is also a `header.category-header` and prints a
|
|
529
|
+
`div.category-description` under the name when the context carries a
|
|
530
|
+
`categoryDescription`; the CMS has no store of term descriptions, so nothing
|
|
531
|
+
writes one today and the header is the heading alone.
|
|
532
|
+
|
|
533
|
+
`layouts/404.njk` says `Content not found.` under a `Not found` kicker and
|
|
534
|
+
links home and to the search. The 500 and 503 pages below open on a kicker the
|
|
535
|
+
same way.
|
|
463
536
|
|
|
464
537
|
`layouts/500.njk` is the page a request gets when the server fails while
|
|
465
538
|
answering it (TASK-129). It says `Something went wrong.` in an
|
|
@@ -682,38 +755,48 @@ to its own stylesheet.
|
|
|
682
755
|
|
|
683
756
|
### Colours
|
|
684
757
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
a
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
|
709
|
-
|
|
|
710
|
-
| `--color-
|
|
711
|
-
| `--color-
|
|
712
|
-
| `--color-
|
|
713
|
-
| `--color-
|
|
714
|
-
| `--color-
|
|
715
|
-
| `--color-
|
|
716
|
-
| `--color-
|
|
758
|
+
Every colour is a custom property on `:root`, and these tokens are the
|
|
759
|
+
override contract: a site that only wants different colours redefines them in
|
|
760
|
+
its own stylesheet rather than replacing this one. Tailwind's own palette is
|
|
761
|
+
cleared in `src/style.css`, and its utilities (`text-ink`, `bg-paper`,
|
|
762
|
+
`border-edge` and the rest) are mapped onto these properties with
|
|
763
|
+
`@theme inline`, so redefining a token recolours every rule that uses it.
|
|
764
|
+
|
|
765
|
+
A second scheme under `@media (prefers-color-scheme: dark)` redefines the same
|
|
766
|
+
tokens on dark paper, and `color-scheme: light dark` lets a browser paint its
|
|
767
|
+
own form controls and scrollbars to match. There is no toggle: the reader's
|
|
768
|
+
system setting is the setting.
|
|
769
|
+
|
|
770
|
+
Both schemes meet the Colour contrast rule of the
|
|
771
|
+
[specification.website checklist](https://specification.website/checklist.md):
|
|
772
|
+
every run of text, the small kickers, dates and meta lines included, at 7:1
|
|
773
|
+
(WCAG 1.4.6, AAA) on whatever it sits on, and every border a reader relies on
|
|
774
|
+
(a field, a card, a code block, the focus outline, the citation and blockquote
|
|
775
|
+
rules) at 3:1 (1.4.11). Nothing a reader needs is drawn at reduced opacity.
|
|
776
|
+
That is a test rather than a claim: `src/web/theme-colors.test.ts` reads the
|
|
777
|
+
tokens out of the compiled stylesheet and computes the ratio of every pair the
|
|
778
|
+
design puts on screen, so a colour changed in `src/style.css` that breaks one
|
|
779
|
+
fails the build.
|
|
780
|
+
|
|
781
|
+
| Token | Utility | What it colours |
|
|
782
|
+
| ------------------------- | ---------- | ---------------------------------------------------------------------- |
|
|
783
|
+
| `--color-body` | `paper` | The paper, and the words on a submit button. |
|
|
784
|
+
| `--color-text` | `ink` | Body text and headlines. |
|
|
785
|
+
| `--color-muted` | `muted` | Kickers, dates, meta lines, decks, quotes, the bio note, the footer. |
|
|
786
|
+
| `--color-primary` | `accent` | Links, a kicker's kind word, the citation rule, the submit button. |
|
|
787
|
+
| `--color-secondary` | `accent-2` | Tag links and the focus outline. |
|
|
788
|
+
| `--color-rule` | `rule` | Decorative hairlines only: between entries, above the footer. |
|
|
789
|
+
| `--color-edge` | `edge` | Borders a reader relies on: fields, the previous and next cards, code. |
|
|
790
|
+
| `--color-base` | `surface` | A sunk surface: fields, notices, a face with no avatar. |
|
|
791
|
+
| `--color-base-2` | — | A cooler sunk surface. |
|
|
792
|
+
| `--color-base-3` | — | The raised surface: the focused skip link. |
|
|
793
|
+
| `--color-code-background` | `code` | Behind `code` and a fenced block. |
|
|
794
|
+
| `--color-code-text` | — | Code with no highlighting on it. |
|
|
795
|
+
| `--color-error` | `error` | A field that will not do, and what the form says about it. |
|
|
796
|
+
|
|
797
|
+
`--color-rule` is the one token in no contrast pair, because it is decoration:
|
|
798
|
+
a site that recolours it may make it as faint as it likes. Anything drawn with
|
|
799
|
+
`--color-edge` has to stay at 3:1 against the paper and the surface.
|
|
717
800
|
|
|
718
801
|
### Code highlighting
|
|
719
802
|
|
|
@@ -750,11 +833,12 @@ a different version of highlight.js than the one installed.
|
|
|
750
833
|
**The palette is Tomorrow**, the one both of the sites this design comes from
|
|
751
834
|
used: Chris Kempson's Tomorrow on light paper and Tomorrow Night on dark, from
|
|
752
835
|
highlight.js's own base16 themes, which is also what decides which `hljs-`
|
|
753
|
-
scope takes which slot.
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
further
|
|
836
|
+
scope takes which slot. None of the light colours is the stock one: a syntax
|
|
837
|
+
theme is drawn for an editor, where a faint comment is a feature, and here code
|
|
838
|
+
is text like any other and meets 7:1 on its block, the bar every run of text
|
|
839
|
+
on the page meets. Each light colour was darkened along its own hue until it
|
|
840
|
+
did and no further, and four of the dark ones (the comment grey, the red, the
|
|
841
|
+
blue and the `base0F` brown) were lightened toward white the same way. Every one
|
|
758
842
|
of them is in the contrast test beside the rest of the palette.
|
|
759
843
|
|
|
760
844
|
| Token | base16 | What it colours |
|
|
@@ -1275,8 +1359,11 @@ The packaged partial draws each entry as the source design does: an
|
|
|
1275
1359
|
`li.comment.h-entry` carrying `id="comment-{{ reply.id }}"` and a
|
|
1276
1360
|
`comment-{{ reply.source }}` class, holding an `article.comment-body` whose
|
|
1277
1361
|
`footer.comment-meta` is the author as a `.comment-author.vcard.p-author.h-card`
|
|
1278
|
-
|
|
1279
|
-
|
|
1362
|
+
(their avatar, or the first letter of their name in a `span.comment-avatar-empty`
|
|
1363
|
+
when there is none) and the permalink as a `.comment-metadata` link around a
|
|
1364
|
+
`time.dt-published`, with a `span.comment-source` saying "via webmention" or
|
|
1365
|
+
"via the fediverse" when it came that way, then the words in
|
|
1366
|
+
`div.comment-content.e-content`. Answers nest in an
|
|
1280
1367
|
`ol.children` inside what they answer. A Reply link in a `div.reply` goes on the
|
|
1281
1368
|
ones written here — `source == "comment"` — when the post is still open; it
|
|
1282
1369
|
carries the comment's id to the form as `?reply_to=`, so threading needs no
|
|
@@ -1285,7 +1372,8 @@ webmention on the page that sent it, so neither gets one.
|
|
|
1285
1372
|
|
|
1286
1373
|
Above the thread, `group()` draws one `div.reaction-group` per kind that has
|
|
1287
1374
|
anything — `p-like`, `p-repost` and `p-mention`, the source theme's classes — as
|
|
1288
|
-
an `h2.reaction-title` of the label and the count
|
|
1375
|
+
an `h2.reaction-title` of the label and the count, in a `span.reaction-count`,
|
|
1376
|
+
beside a `div.facepile` of
|
|
1289
1377
|
`a.u-url` faces. A face is a round `u-photo` avatar; a reaction whose author the
|
|
1290
1378
|
site knows no picture of is the emoji badge of its kind and a `.reaction-name`
|
|
1291
1379
|
instead. Likes and boosts link to the person, and a mention to the page it came
|
|
@@ -1352,7 +1440,10 @@ The packaged partial is a `section#respond.comment-respond` with an
|
|
|
1352
1440
|
`h2.comment-reply-title`, one paragraph per field and the button in a
|
|
1353
1441
|
`p.form-submit` — the source design's names, so the stylesheet styles every
|
|
1354
1442
|
label, field and button of both forms through `.comment-respond` and a site
|
|
1355
|
-
that has CSS for the WordPress theme can bring it.
|
|
1443
|
+
that has CSS for the WordPress theme can bring it. The name and email fields sit
|
|
1444
|
+
in a `div.field-row`, side by side on a wide screen, in both forms. On a site
|
|
1445
|
+
that takes webmentions a `p.comment-help` under the heading says a reader can
|
|
1446
|
+
reply from their own site instead.
|
|
1356
1447
|
|
|
1357
1448
|
| Key | What it holds |
|
|
1358
1449
|
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
{% extends "layouts/base.njk" %}
|
|
2
|
+
{% import "partials/kicker.njk" as kicker with context %}
|
|
2
3
|
|
|
3
4
|
{% block content %}
|
|
4
5
|
<article class="not-found">
|
|
6
|
+
{{ kicker.line("Not found") }}
|
|
5
7
|
<h1 class="page-title">Content not found.</h1>
|
|
6
8
|
<p>Go <a href="{{ "/" | url }}">home</a>, or <a href="{{ "/search/" | url }}">search the site</a>.</p>
|
|
7
9
|
</article>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
{% extends "layouts/base.njk" %}
|
|
2
|
+
{% import "partials/kicker.njk" as kicker with context %}
|
|
2
3
|
|
|
3
4
|
{% block content %}
|
|
4
5
|
<article class="server-error">
|
|
6
|
+
{{ kicker.line("Server error") }}
|
|
5
7
|
<h1 class="page-title">Something went wrong.</h1>
|
|
6
8
|
<p>This page could not be shown because of a problem on the server. Try again in a moment, or go <a href="{{ "/" | url }}">home</a>.</p>
|
|
7
9
|
</article>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
{% extends "layouts/base.njk" %}
|
|
2
|
+
{% import "partials/kicker.njk" as kicker with context %}
|
|
2
3
|
|
|
3
4
|
{% block content %}
|
|
4
5
|
<article class="maintenance">
|
|
6
|
+
{{ kicker.line("Maintenance") }}
|
|
5
7
|
<h1 class="page-title">Down for maintenance.</h1>
|
|
6
8
|
<p>This site is down for maintenance and will be back shortly.{% if until %} It should be back by <time datetime="{{ until }}">{{ untilText }}</time>.{% endif %} Please try again then.</p>
|
|
7
9
|
</article>
|
|
@@ -26,8 +26,10 @@
|
|
|
26
26
|
{{ feeds.feedLinks(author.url, site.title + ": " + author.name) }}
|
|
27
27
|
{% endblock %}
|
|
28
28
|
|
|
29
|
+
{% import "partials/kicker.njk" as kicker with context %}
|
|
29
30
|
{% block content %}
|
|
30
|
-
<header class="author-header">
|
|
31
|
+
<header class="author-header archive-header">
|
|
32
|
+
{{ kicker.line("Author") }}
|
|
31
33
|
<h1 class="page-title">{{ author.name }}</h1>
|
|
32
34
|
</header>
|
|
33
35
|
{% include "partials/bio.njk" %}
|
|
@@ -167,7 +167,7 @@
|
|
|
167
167
|
<a href="{{ "/" | url }}">{{ site.title }}</a>
|
|
168
168
|
</h1>
|
|
169
169
|
{% if site.tagline %}
|
|
170
|
-
<p>{{ site.tagline }}</p>
|
|
170
|
+
<p class="site-tagline">{{ site.tagline }}</p>
|
|
171
171
|
{% endif %}
|
|
172
172
|
{% else %}
|
|
173
173
|
<a class="header-link-home" href="{{ "/" | url }}">{{ site.title }}</a>
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
{{ feeds.feedLinks(categoryRoot, site.title + ": " + category) }}
|
|
10
10
|
{% endblock %}
|
|
11
11
|
|
|
12
|
+
{% import "partials/kicker.njk" as kicker with context %}
|
|
12
13
|
{% block content %}
|
|
13
14
|
{#
|
|
14
15
|
The archive's header. `categoryDescription` is what the design prints under
|
|
@@ -16,8 +17,9 @@
|
|
|
16
17
|
alone until something does — a site whose own context carries one gets it
|
|
17
18
|
printed without overriding this layout.
|
|
18
19
|
#}
|
|
19
|
-
<header class="category-header">
|
|
20
|
-
|
|
20
|
+
<header class="category-header archive-header">
|
|
21
|
+
{{ kicker.line("Category") }}
|
|
22
|
+
<h1 class="page-title">{{ category }}</h1>
|
|
21
23
|
{% if categoryDescription %}
|
|
22
24
|
<div class="category-description">{{ categoryDescription }}</div>
|
|
23
25
|
{% endif %}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
{{ content | safe }}
|
|
24
24
|
</div>
|
|
25
25
|
|
|
26
|
-
<h2>Recent Posts</h2>
|
|
26
|
+
<h2 class="section-title">Recent Posts</h2>
|
|
27
27
|
{#- The feed a listing prints, over the posts the CMS decided were recent:
|
|
28
28
|
this month's writing when there is enough of it and the five newest
|
|
29
29
|
otherwise. `feedHeading` is 3 because the `h2` above is what they sit
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
whoever the site is by, not by the person a front matter line names.
|
|
14
14
|
#}
|
|
15
15
|
{% extends "layouts/base.njk" %}
|
|
16
|
+
{% import "partials/kicker.njk" as kicker with context %}
|
|
16
17
|
|
|
17
18
|
{#- Who the bio credits, and what tells `layouts/base.njk` the site menu is in
|
|
18
19
|
the bio rather than in the page footer. -#}
|
|
@@ -21,7 +22,8 @@
|
|
|
21
22
|
{% block content %}
|
|
22
23
|
{% set entryUrl = page.url or url %}
|
|
23
24
|
<article class="blog-post h-entry">
|
|
24
|
-
<header>
|
|
25
|
+
<header class="post-header">
|
|
26
|
+
{{ kicker.line("Page") }}
|
|
25
27
|
<h1 class="p-name">{{ title }}</h1>
|
|
26
28
|
</header>
|
|
27
29
|
|
|
@@ -36,7 +38,7 @@
|
|
|
36
38
|
<a href="{{ entryUrl | url }}" class="u-url"><time class="small dt-published" datetime="{{ date | date("iso") }}">Published {{ date | date }}</time></a>
|
|
37
39
|
{%- endif %}
|
|
38
40
|
{%- if updated and (not date or (updated | date("html")) != (date | date("html"))) %}
|
|
39
|
-
{% if date %}<
|
|
41
|
+
{% if date %}<span aria-hidden="true">·</span> {% endif %}<time class="small dt-updated" datetime="{{ updated | date("iso") }}">Updated {{ updated | date }}</time>
|
|
40
42
|
{%- endif -%}
|
|
41
43
|
</p>
|
|
42
44
|
</section>
|