@geekity/cms 0.4.0 → 0.6.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.
Files changed (156) hide show
  1. package/README.md +246 -110
  2. package/admin/pages/documents/editor.njk +0 -13
  3. package/admin/pages/{settings/federation.njk → federation/settings.njk} +7 -5
  4. package/admin/pages/navigation/menus.njk +132 -0
  5. package/admin/pages/settings/reading.njk +2 -10
  6. package/admin/pages/tools/content-index.njk +89 -0
  7. package/admin/pages/users/edit.njk +25 -2
  8. package/admin/pages/users/list.njk +5 -2
  9. package/admin/static/admin.css +78 -3
  10. package/dist/access-log.d.ts +44 -0
  11. package/dist/access-log.d.ts.map +1 -0
  12. package/dist/access-log.js +71 -0
  13. package/dist/access-log.js.map +1 -0
  14. package/dist/admin/accounts.d.ts +10 -0
  15. package/dist/admin/accounts.d.ts.map +1 -1
  16. package/dist/admin/accounts.js +15 -3
  17. package/dist/admin/accounts.js.map +1 -1
  18. package/dist/admin/documents.d.ts +3 -13
  19. package/dist/admin/documents.d.ts.map +1 -1
  20. package/dist/admin/documents.js +2 -34
  21. package/dist/admin/documents.js.map +1 -1
  22. package/dist/admin/federation.d.ts +10 -0
  23. package/dist/admin/federation.d.ts.map +1 -1
  24. package/dist/admin/federation.js +10 -0
  25. package/dist/admin/federation.js.map +1 -1
  26. package/dist/admin/index.d.ts +3 -3
  27. package/dist/admin/index.d.ts.map +1 -1
  28. package/dist/admin/index.js +2 -2
  29. package/dist/admin/index.js.map +1 -1
  30. package/dist/admin/menu.d.ts.map +1 -1
  31. package/dist/admin/menu.js +19 -2
  32. package/dist/admin/menu.js.map +1 -1
  33. package/dist/admin/navigation.d.ts +155 -0
  34. package/dist/admin/navigation.d.ts.map +1 -0
  35. package/dist/admin/navigation.js +292 -0
  36. package/dist/admin/navigation.js.map +1 -0
  37. package/dist/admin/routes.d.ts.map +1 -1
  38. package/dist/admin/routes.js +9 -0
  39. package/dist/admin/routes.js.map +1 -1
  40. package/dist/admin/session.d.ts +17 -3
  41. package/dist/admin/session.d.ts.map +1 -1
  42. package/dist/admin/session.js +19 -5
  43. package/dist/admin/session.js.map +1 -1
  44. package/dist/admin/settings-federation.d.ts +10 -1
  45. package/dist/admin/settings-federation.d.ts.map +1 -1
  46. package/dist/admin/settings-federation.js +26 -6
  47. package/dist/admin/settings-federation.js.map +1 -1
  48. package/dist/admin/settings-page.d.ts +26 -9
  49. package/dist/admin/settings-page.d.ts.map +1 -1
  50. package/dist/admin/settings-page.js +18 -12
  51. package/dist/admin/settings-page.js.map +1 -1
  52. package/dist/admin/settings-pages.d.ts +14 -3
  53. package/dist/admin/settings-pages.d.ts.map +1 -1
  54. package/dist/admin/settings-pages.js +15 -5
  55. package/dist/admin/settings-pages.js.map +1 -1
  56. package/dist/admin/settings-reading.d.ts +5 -4
  57. package/dist/admin/settings-reading.d.ts.map +1 -1
  58. package/dist/admin/settings-reading.js +6 -5
  59. package/dist/admin/settings-reading.js.map +1 -1
  60. package/dist/admin/settings.d.ts +29 -15
  61. package/dist/admin/settings.d.ts.map +1 -1
  62. package/dist/admin/settings.js +28 -78
  63. package/dist/admin/settings.js.map +1 -1
  64. package/dist/admin/templates.d.ts +3 -1
  65. package/dist/admin/templates.d.ts.map +1 -1
  66. package/dist/admin/templates.js +3 -1
  67. package/dist/admin/templates.js.map +1 -1
  68. package/dist/admin/tools.d.ts +111 -0
  69. package/dist/admin/tools.d.ts.map +1 -0
  70. package/dist/admin/tools.js +182 -0
  71. package/dist/admin/tools.js.map +1 -0
  72. package/dist/admin/users.d.ts +24 -0
  73. package/dist/admin/users.d.ts.map +1 -1
  74. package/dist/admin/users.js +102 -30
  75. package/dist/admin/users.js.map +1 -1
  76. package/dist/cli.d.ts.map +1 -1
  77. package/dist/cli.js +6 -1
  78. package/dist/cli.js.map +1 -1
  79. package/dist/comments/form.d.ts +48 -0
  80. package/dist/comments/form.d.ts.map +1 -1
  81. package/dist/comments/form.js +15 -0
  82. package/dist/comments/form.js.map +1 -1
  83. package/dist/comments/index.d.ts +4 -3
  84. package/dist/comments/index.d.ts.map +1 -1
  85. package/dist/comments/index.js +2 -1
  86. package/dist/comments/index.js.map +1 -1
  87. package/dist/comments/routes.d.ts +3 -1
  88. package/dist/comments/routes.d.ts.map +1 -1
  89. package/dist/comments/routes.js +46 -11
  90. package/dist/comments/routes.js.map +1 -1
  91. package/dist/comments/submission.d.ts +37 -3
  92. package/dist/comments/submission.d.ts.map +1 -1
  93. package/dist/comments/submission.js +59 -20
  94. package/dist/comments/submission.js.map +1 -1
  95. package/dist/comments/viewer.d.ts +21 -0
  96. package/dist/comments/viewer.d.ts.map +1 -0
  97. package/dist/comments/viewer.js +45 -0
  98. package/dist/comments/viewer.js.map +1 -0
  99. package/dist/config.d.ts +35 -0
  100. package/dist/config.d.ts.map +1 -1
  101. package/dist/config.js +3 -0
  102. package/dist/config.js.map +1 -1
  103. package/dist/content/store.d.ts +18 -0
  104. package/dist/content/store.d.ts.map +1 -1
  105. package/dist/content/store.js +18 -0
  106. package/dist/content/store.js.map +1 -1
  107. package/dist/env.d.ts +12 -1
  108. package/dist/env.d.ts.map +1 -1
  109. package/dist/federation/mount.d.ts +4 -0
  110. package/dist/federation/mount.d.ts.map +1 -1
  111. package/dist/federation/mount.js +60 -15
  112. package/dist/federation/mount.js.map +1 -1
  113. package/dist/index.d.ts +5 -5
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.js +21 -4
  116. package/dist/index.js.map +1 -1
  117. package/dist/web/authors.d.ts +15 -1
  118. package/dist/web/authors.d.ts.map +1 -1
  119. package/dist/web/authors.js +9 -1
  120. package/dist/web/authors.js.map +1 -1
  121. package/dist/web/index.d.ts +4 -4
  122. package/dist/web/index.d.ts.map +1 -1
  123. package/dist/web/index.js +1 -1
  124. package/dist/web/index.js.map +1 -1
  125. package/dist/web/navigation.d.ts +235 -35
  126. package/dist/web/navigation.d.ts.map +1 -1
  127. package/dist/web/navigation.js +333 -57
  128. package/dist/web/navigation.js.map +1 -1
  129. package/dist/web/negotiate.d.ts +22 -0
  130. package/dist/web/negotiate.d.ts.map +1 -1
  131. package/dist/web/negotiate.js +25 -10
  132. package/dist/web/negotiate.js.map +1 -1
  133. package/dist/web/render.d.ts +16 -10
  134. package/dist/web/render.d.ts.map +1 -1
  135. package/dist/web/render.js +21 -14
  136. package/dist/web/render.js.map +1 -1
  137. package/dist/web/routes.d.ts.map +1 -1
  138. package/dist/web/routes.js +11 -2
  139. package/dist/web/routes.js.map +1 -1
  140. package/dist/web/themes.d.ts +21 -0
  141. package/dist/web/themes.d.ts.map +1 -1
  142. package/dist/web/themes.js +37 -0
  143. package/dist/web/themes.js.map +1 -1
  144. package/package.json +1 -1
  145. package/templates/site/content/_data/site.json +7 -0
  146. package/templates/site/content/pages/about.md +7 -0
  147. package/themes/default/README.md +215 -80
  148. package/themes/default/layouts/author.njk +3 -4
  149. package/themes/default/layouts/base.njk +38 -49
  150. package/themes/default/layouts/front-page.njk +1 -2
  151. package/themes/default/partials/bio.njk +20 -22
  152. package/themes/default/partials/comment-form.njk +31 -3
  153. package/themes/default/partials/menu.njk +34 -0
  154. package/themes/default/partials/search-form.njk +5 -0
  155. package/themes/default/static/style.css +54 -13
  156. package/themes/default/theme.json +5 -1
@@ -4,10 +4,14 @@
4
4
 
5
5
  It replaces `partials/byline.njk`, which printed a name in a meta line. This
6
6
  is the whole credit — a round photo, "Written by" linked to their archive
7
- with `rel="author me"`, what they do, where they are — and under it the site
8
- menu, because the design has no navigation in the header and this is where it
9
- reads it. The menu is here and not in the page footer whenever a page has a
10
- bio; `layouts/base.njk` prints it in the footer on the pages that have none.
7
+ with `rel="author me"`, what they do, where they are, what they wrote about
8
+ themselves and the links they call their own.
9
+
10
+ The person and only the person (TASK-105). The site menu used to be printed
11
+ here as well, because the design had no header navigation; it is in
12
+ `header.global-header` on every page now, so this card says nothing about
13
+ the site and a reader looking for the way around never has to find the bio
14
+ first.
11
15
 
12
16
  Set `bioAuthor` before including it and nothing renders when that is absent:
13
17
 
@@ -25,11 +29,15 @@
25
29
  otherwise. An author archive sets "Posts by", because the card there heads a
26
30
  list of somebody's writing rather than crediting one piece of it.
27
31
 
28
- `bioProfile` is the second switch. Set it and the bio also prints their
29
- `p-note` and their `rel="me"` links, which is what an author archive wants —
30
- the page is about them. An entry leaves it unset: the page footer already
31
- prints the site's identity links, and the `rel="author me"` link above leads
32
- to the archive where this person's own are.
32
+ A link's `rel` always holds `me` — the CMS puts it there whether or not the
33
+ Links box typed it — followed by whatever else that line carried, so this
34
+ prints one attribute rather than one of its own beside one of theirs.
35
+
36
+ The `p-note` and the `rel="me"` links are printed wherever the card is, which
37
+ is what `bioProfile` used to ask for on an author archive alone. An entry
38
+ left that switch unset because the page footer carried the site's identity
39
+ links; it carries nobody's now, so somebody's links belong under what they
40
+ wrote rather than one page further on.
33
41
  #}
34
42
  {% if bioAuthor %}
35
43
  <div class="bio p-author h-card">
@@ -51,24 +59,14 @@
51
59
  {%- if bioAuthor.location %} from <span class="p-locality">{{ bioAuthor.location }}</span>{% endif %}.
52
60
  </p>
53
61
 
54
- {%- if bioProfile and bioAuthor.bio %}
62
+ {%- if bioAuthor.bio %}
55
63
  <p class="bio-note p-note">{{ bioAuthor.bio }}</p>
56
64
  {%- endif %}
57
65
 
58
- {%- if menu.length %}
59
- <nav class="site-nav" aria-label="Site">
60
- <ul class="hlist">
61
- {%- for item in menu %}
62
- <li><a href="{{ item.url | url }}"{% if item.current %} class="is-current" aria-current="page"{% endif %}>{{ item.label }}</a></li>
63
- {%- endfor %}
64
- </ul>
65
- </nav>
66
- {%- endif %}
67
-
68
- {%- if bioProfile and bioAuthor.links.length %}
66
+ {%- if bioAuthor.links.length %}
69
67
  <ul class="hlist bio-links">
70
68
  {%- for link in bioAuthor.links %}
71
- <li><a class="u-url" rel="me" href="{{ link.href }}">{{ link.label }}</a></li>
69
+ <li><a class="u-url" rel="{{ link.rel }}" href="{{ link.href }}">{{ link.label }}</a></li>
72
70
  {%- endfor %}
73
71
  </ul>
74
72
  {%- endif %}
@@ -13,6 +13,13 @@
13
13
  every label, field and button through them — so the contact form wears the
14
14
  same class rather than repeating the rules.
15
15
 
16
+ It draws two forms. For a stranger: the name, email and website boxes, the
17
+ honeypot and the loaded-at stamp. For somebody signed in to this site's
18
+ admin — `commentForm.signedInAs` — none of those, because the site already
19
+ knows all three and a session is better evidence than a honeypot, and a
20
+ hidden CSRF token instead, because this form posts under somebody's name.
21
+ A theme that replaces this partial has to draw both.
22
+
16
23
  It works with JavaScript switched off, and there is no script on it.
17
24
  #}
18
25
  <section class="comment-respond" id="respond">
@@ -28,7 +35,6 @@
28
35
 
29
36
  <form method="post" action="{{ commentForm.action }}">
30
37
  <input type="hidden" name="{{ commentForm.fields.post }}" value="{{ commentForm.post }}" />
31
- <input type="hidden" name="{{ commentForm.fields.loaded }}" value="{{ commentForm.loaded }}" />
32
38
  {#
33
39
  What this comment answers. `commentReplyTo` is the `?reply_to=` on the
34
40
  URL, which a Reply link put there and the CMS has already checked names
@@ -45,6 +51,26 @@
45
51
  </p>
46
52
  {% endif %}
47
53
 
54
+ {% if commentForm.signedInAs %}
55
+ {#
56
+ Signed in to this site. The comment is attributed from the account, so
57
+ there is nothing to type and nothing to get wrong; the token is what
58
+ stops a page on another site posting under this name without them
59
+ knowing.
60
+ #}
61
+ <input type="hidden" name="{{ commentForm.fields.csrf }}" value="{{ commentForm.csrfToken }}" />
62
+
63
+ <p class="comment-signed-in">
64
+ Commenting as <a href="{{ commentForm.signedInAs.url }}">{{ commentForm.signedInAs.name }}</a>.
65
+ </p>
66
+ {% else %}
67
+ {#
68
+ When this form was drawn, which is what the minimum submit time is
69
+ measured against. A signed-in form carries none: a session says more
70
+ about whether this is a person than a stopwatch does.
71
+ #}
72
+ <input type="hidden" name="{{ commentForm.fields.loaded }}" value="{{ commentForm.loaded }}" />
73
+
48
74
  {#
49
75
  The honeypot. Hidden from sight and from assistive technology, out of the
50
76
  tab order, and told not to autofill: a person never sees it and never
@@ -78,6 +104,7 @@
78
104
  <span class="comment-field-error">{{ commentForm.problems.url }}</span>
79
105
  {% endif %}
80
106
  </p>
107
+ {% endif %}
81
108
 
82
109
  <p class="comment-field">
83
110
  <label for="comment-body">Comment</label>
@@ -92,8 +119,9 @@
92
119
  "Tell me about replies". Only on a site that can actually send mail —
93
120
  `notifiable` is false otherwise — because a box that promised a message
94
121
  nothing would ever send would be a lie on a form. The address is the one
95
- typed above, is never shown anywhere, and every message it sends carries
96
- a one-click unsubscribe link.
122
+ typed above — or the account's, for somebody signed in — is never shown
123
+ anywhere, and every message it sends carries a one-click unsubscribe
124
+ link.
97
125
  #}
98
126
  {% if commentForm.notifiable %}
99
127
  <p class="comment-check">
@@ -0,0 +1,34 @@
1
+ {#
2
+ One menu, drawn.
3
+
4
+ The CMS puts every menu the site stores on the context as `menus`, keyed by
5
+ the name it is stored under, each item already knowing whether it is the page
6
+ being looked at (TASK-107). This theme declares two of those names in its
7
+ `theme.json` — `primary` and `footer` — and draws each through this macro, so
8
+ the markup of a menu is written once:
9
+
10
+ {% import "partials/menu.njk" as nav %}
11
+ {{ nav.list(menus.footer, "Footer") }}
12
+
13
+ Nothing is printed for a menu with nothing in it: an area a site has not
14
+ filled in is an area with no nav element, not an empty list.
15
+
16
+ `label` is the `aria-label`, which is what tells a reader on a screen reader
17
+ which of a page's menus this one is. Two navs with no labels are two navs
18
+ called "navigation".
19
+
20
+ An item's `rel` is whatever `rel` values its line carried, already lower case
21
+ and each said once, so it is printed as one attribute and nothing is joined
22
+ here. `me` is the one most menus want: it is how Mastodon and the rest of the
23
+ IndieWeb verify that the site and the profile it links belong to the same
24
+ person — the profile links back, and the pair is the proof.
25
+ #}
26
+ {% macro list(items, label) %}{% if items.length %}
27
+ <nav class="site-nav" aria-label="{{ label }}">
28
+ <ul class="hlist">
29
+ {% for item in items %}
30
+ <li><a href="{{ item.url | url }}"{% if item.rel %} rel="{{ item.rel }}"{% endif %}{% if item.current %} class="is-current" aria-current="page"{% endif %}>{{ item.label }}</a></li>
31
+ {% endfor %}
32
+ </ul>
33
+ </nav>
34
+ {% endif %}{% endmacro %}
@@ -2,6 +2,11 @@
2
2
  The site's search box (TASK-22): a plain GET form, so a search is a URL a
3
3
  reader can bookmark or share and the box needs no JavaScript.
4
4
 
5
+ `layouts/search.njk` is the only thing that includes it (TASK-105): the box
6
+ was in the footer of every page as well, and search is a menu item now —
7
+ a `Search | /search/` line like any other — so the page about searching is
8
+ where the box is.
9
+
5
10
  Expects nothing. `query`, when the page has one, goes back in the box, so the
6
11
  results page shows what was searched for. The label is read out rather than
7
12
  shown, because the button beside the box already says what it is for, and it
@@ -299,14 +299,29 @@ a:focus-visible {
299
299
  color: var(--color-primary);
300
300
  }
301
301
 
302
- header a,
303
- header a:visited {
302
+ /* The two links that are the page saying where it is rather than somewhere to
303
+ go: the site title at the root and the small link home everywhere else. Both
304
+ read as plain text, in the heading font the rules below give them.
305
+
306
+ Named rather than reached for through the element they sit in (TASK-111). A
307
+ bare `header a` also caught the site menu, which is navigation somebody is
308
+ meant to use, and every link inside a post's own `<header>`. The `:visited`
309
+ halves are here because `a:visited` outweighs a bare class, and the hover
310
+ and focus halves because `a:focus-visible` outweighs one too: without them
311
+ these two would take the outline rather than the flourish. */
312
+
313
+ .main-heading a,
314
+ .main-heading a:visited,
315
+ .header-link-home,
316
+ .header-link-home:visited {
304
317
  color: var(--color-text);
305
318
  text-decoration: none;
306
319
  }
307
320
 
308
- header a:hover,
309
- header a:focus {
321
+ .main-heading a:hover,
322
+ .main-heading a:focus,
323
+ .header-link-home:hover,
324
+ .header-link-home:focus {
310
325
  background-color: var(--color-primary);
311
326
  color: var(--color-body);
312
327
  text-decoration: none;
@@ -616,6 +631,32 @@ pre code {
616
631
  text-decoration: none;
617
632
  }
618
633
 
634
+ /* The site menu, which the header carries on every page (TASK-105). At the
635
+ root the header is the site title with the tagline under it, and the menu
636
+ is a line of its own under that.
637
+
638
+ No size of its own (TASK-111): a menu is navigation somebody is meant to
639
+ use rather than a footnote, so it reads at the page's size, like the footer
640
+ menu, which never had one. */
641
+ .global-header .site-nav {
642
+ margin-top: var(--spacing-2);
643
+ }
644
+
645
+ /* Everywhere else the header is the small link home, and the menu sits beside
646
+ it on the same line — the two wrap onto a second line together rather than
647
+ the menu dropping under the link on a narrow screen. */
648
+ .global-wrapper:not([data-is-root-path='true']) .global-header {
649
+ display: flex;
650
+ flex-wrap: wrap;
651
+ align-items: baseline;
652
+ column-gap: var(--spacing-5);
653
+ row-gap: var(--spacing-1);
654
+ }
655
+
656
+ .global-wrapper:not([data-is-root-path='true']) .global-header .site-nav {
657
+ margin-top: var(--spacing-0);
658
+ }
659
+
619
660
  /* An entry: a post or a page (TASK-83). The source design's own rules — the
620
661
  title tight against the words under it, a subtitle in the heading font —
621
662
  plus the small line the `e-content` ends on, which carries the permalink,
@@ -667,13 +708,12 @@ pre code {
667
708
  font-style: italic;
668
709
  }
669
710
 
670
- /* The site menu, and an author archive's `rel="me"` links: both horizontal
671
- lists under the credit, small, in the heading font like every other piece
672
- of navigation. */
673
- .bio .site-nav,
711
+ /* The links the person calls their own, under the credit: a horizontal list in
712
+ the heading font, at the page's size like every other nav (TASK-111). The
713
+ site menu used to share this rule; it is in the header now (TASK-105) and
714
+ the bio carries nobody but the person. */
674
715
  .bio-links {
675
716
  margin-top: var(--spacing-2);
676
- font-size: var(--fontSize-0);
677
717
  }
678
718
 
679
719
  .bio-avatar {
@@ -803,9 +843,9 @@ pre code {
803
843
  font-size: var(--fontSize-0);
804
844
  }
805
845
 
806
- /* The search box (TASK-22): a field and a button on one line, in the footer
807
- of every page and at the top of the search page. The field is drawn the way
808
- the comment form's are, so the site has one look for a place to type. */
846
+ /* The search box (TASK-22): a field and a button on one line, at the top of
847
+ the search page and nowhere else (TASK-105). The field is drawn the way the
848
+ comment form's are, so the site has one look for a place to type. */
809
849
 
810
850
  .search-form {
811
851
  display: flex;
@@ -1185,7 +1225,8 @@ pre code {
1185
1225
  border-inline-start-color: var(--color-error);
1186
1226
  }
1187
1227
 
1188
- .comment-replying-to {
1228
+ .comment-replying-to,
1229
+ .comment-signed-in {
1189
1230
  margin: 0 0 var(--spacing-4);
1190
1231
  font-family: var(--font-heading);
1191
1232
  font-size: var(--fontSize-0);
@@ -1,5 +1,9 @@
1
1
  {
2
2
  "name": "Default",
3
3
  "kind": "site",
4
- "description": "The theme that ships with Geekity: plain Nunjucks and plain CSS, and the layer every other theme is laid over."
4
+ "description": "The theme that ships with Geekity: plain Nunjucks and plain CSS, and the layer every other theme is laid over.",
5
+ "areas": [
6
+ { "name": "primary", "label": "Site menu" },
7
+ { "name": "footer", "label": "Footer links" }
8
+ ]
5
9
  }