@geekity/cms 0.40.0 → 0.42.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 (345) hide show
  1. package/admin/components/blocks.njk +15 -1
  2. package/admin/pages/appearance/look.njk +135 -0
  3. package/admin/pages/dashboard/home.njk +9 -3
  4. package/admin/pages/documents/conflict.njk +35 -10
  5. package/admin/pages/documents/editor.njk +29 -0
  6. package/admin/pages/documents/list.njk +44 -1
  7. package/admin/pages/settings/general.njk +4 -0
  8. package/admin/pages/settings/reading.njk +14 -0
  9. package/admin/pages/users/edit.njk +1 -1
  10. package/admin/pages/users/writing-goals.njk +64 -0
  11. package/admin/src/admin.css +32 -0
  12. package/admin/static/admin.css +202 -4
  13. package/admin/static/dashboard.js +51 -23
  14. package/admin/static/editor.js +22 -19
  15. package/dist/access-log.d.ts +3 -0
  16. package/dist/access-log.d.ts.map +1 -1
  17. package/dist/access-log.js +13 -9
  18. package/dist/access-log.js.map +1 -1
  19. package/dist/admin/autosave-client.d.ts +85 -0
  20. package/dist/admin/autosave-client.d.ts.map +1 -0
  21. package/dist/admin/autosave-client.js +218 -0
  22. package/dist/admin/autosave-client.js.map +1 -0
  23. package/dist/admin/autosave.d.ts +12 -0
  24. package/dist/admin/autosave.d.ts.map +1 -0
  25. package/dist/admin/autosave.js +92 -0
  26. package/dist/admin/autosave.js.map +1 -0
  27. package/dist/admin/blocks.d.ts +13 -1
  28. package/dist/admin/blocks.d.ts.map +1 -1
  29. package/dist/admin/blocks.js +40 -5
  30. package/dist/admin/blocks.js.map +1 -1
  31. package/dist/admin/core-widgets.d.ts.map +1 -1
  32. package/dist/admin/core-widgets.js +2 -0
  33. package/dist/admin/core-widgets.js.map +1 -1
  34. package/dist/admin/dashboard.d.ts +2 -2
  35. package/dist/admin/dashboard.d.ts.map +1 -1
  36. package/dist/admin/dashboard.js +23 -15
  37. package/dist/admin/dashboard.js.map +1 -1
  38. package/dist/admin/documents.d.ts.map +1 -1
  39. package/dist/admin/documents.js +223 -16
  40. package/dist/admin/documents.js.map +1 -1
  41. package/dist/admin/editor-word-counter.d.ts +8 -0
  42. package/dist/admin/editor-word-counter.d.ts.map +1 -0
  43. package/dist/admin/editor-word-counter.js +27 -0
  44. package/dist/admin/editor-word-counter.js.map +1 -0
  45. package/dist/admin/editor-words.d.ts +7 -0
  46. package/dist/admin/editor-words.d.ts.map +1 -0
  47. package/dist/admin/editor-words.js +9 -0
  48. package/dist/admin/editor-words.js.map +1 -0
  49. package/dist/admin/flash.d.ts +2 -0
  50. package/dist/admin/flash.d.ts.map +1 -1
  51. package/dist/admin/flash.js +12 -0
  52. package/dist/admin/flash.js.map +1 -1
  53. package/dist/admin/focus-mode.d.ts +37 -0
  54. package/dist/admin/focus-mode.d.ts.map +1 -0
  55. package/dist/admin/focus-mode.js +71 -0
  56. package/dist/admin/focus-mode.js.map +1 -0
  57. package/dist/admin/look.d.ts +12 -0
  58. package/dist/admin/look.d.ts.map +1 -0
  59. package/dist/admin/look.js +179 -0
  60. package/dist/admin/look.js.map +1 -0
  61. package/dist/admin/menu.d.ts.map +1 -1
  62. package/dist/admin/menu.js +7 -3
  63. package/dist/admin/menu.js.map +1 -1
  64. package/dist/admin/preview.d.ts.map +1 -1
  65. package/dist/admin/preview.js +1 -0
  66. package/dist/admin/preview.js.map +1 -1
  67. package/dist/admin/routes.d.ts.map +1 -1
  68. package/dist/admin/routes.js +8 -4
  69. package/dist/admin/routes.js.map +1 -1
  70. package/dist/admin/settings-fields.d.ts +1 -1
  71. package/dist/admin/settings-fields.d.ts.map +1 -1
  72. package/dist/admin/settings-fields.js +2 -0
  73. package/dist/admin/settings-fields.js.map +1 -1
  74. package/dist/admin/settings-general.d.ts.map +1 -1
  75. package/dist/admin/settings-general.js +1 -0
  76. package/dist/admin/settings-general.js.map +1 -1
  77. package/dist/admin/settings-reading.d.ts.map +1 -1
  78. package/dist/admin/settings-reading.js +7 -1
  79. package/dist/admin/settings-reading.js.map +1 -1
  80. package/dist/admin/templates.d.ts +2 -0
  81. package/dist/admin/templates.d.ts.map +1 -1
  82. package/dist/admin/templates.js +2 -0
  83. package/dist/admin/templates.js.map +1 -1
  84. package/dist/admin/users.d.ts.map +1 -1
  85. package/dist/admin/users.js +4 -0
  86. package/dist/admin/users.js.map +1 -1
  87. package/dist/admin/widget-writing.d.ts +3 -0
  88. package/dist/admin/widget-writing.d.ts.map +1 -0
  89. package/dist/admin/widget-writing.js +102 -0
  90. package/dist/admin/widget-writing.js.map +1 -0
  91. package/dist/admin/widgets.d.ts +4 -1
  92. package/dist/admin/widgets.d.ts.map +1 -1
  93. package/dist/admin/widgets.js +19 -8
  94. package/dist/admin/widgets.js.map +1 -1
  95. package/dist/admin/writing-goals.d.ts +33 -0
  96. package/dist/admin/writing-goals.d.ts.map +1 -0
  97. package/dist/admin/writing-goals.js +149 -0
  98. package/dist/admin/writing-goals.js.map +1 -0
  99. package/dist/autosave/index.d.ts +5 -0
  100. package/dist/autosave/index.d.ts.map +1 -0
  101. package/dist/autosave/index.js +3 -0
  102. package/dist/autosave/index.js.map +1 -0
  103. package/dist/autosave/key.d.ts +13 -0
  104. package/dist/autosave/key.d.ts.map +1 -0
  105. package/dist/autosave/key.js +29 -0
  106. package/dist/autosave/key.js.map +1 -0
  107. package/dist/autosave/store.d.ts +23 -0
  108. package/dist/autosave/store.d.ts.map +1 -0
  109. package/dist/autosave/store.js +114 -0
  110. package/dist/autosave/store.js.map +1 -0
  111. package/dist/cli.d.ts +1 -1
  112. package/dist/cli.d.ts.map +1 -1
  113. package/dist/cli.js +65 -4
  114. package/dist/cli.js.map +1 -1
  115. package/dist/cms/app.d.ts.map +1 -1
  116. package/dist/cms/app.js +1 -0
  117. package/dist/cms/app.js.map +1 -1
  118. package/dist/cms/boot.d.ts.map +1 -1
  119. package/dist/cms/boot.js +2 -0
  120. package/dist/cms/boot.js.map +1 -1
  121. package/dist/cms/create.d.ts +11 -2
  122. package/dist/cms/create.d.ts.map +1 -1
  123. package/dist/cms/create.js +61 -2
  124. package/dist/cms/create.js.map +1 -1
  125. package/dist/cms/server-error.d.ts.map +1 -1
  126. package/dist/cms/server-error.js +1 -0
  127. package/dist/cms/server-error.js.map +1 -1
  128. package/dist/cms/services.d.ts +2 -0
  129. package/dist/cms/services.d.ts.map +1 -1
  130. package/dist/cms/services.js +14 -0
  131. package/dist/cms/services.js.map +1 -1
  132. package/dist/config.d.ts +20 -0
  133. package/dist/config.d.ts.map +1 -1
  134. package/dist/config.js +6 -2
  135. package/dist/config.js.map +1 -1
  136. package/dist/content/post-type.d.ts +1 -0
  137. package/dist/content/post-type.d.ts.map +1 -1
  138. package/dist/content/post-type.js +1 -1
  139. package/dist/content/post-type.js.map +1 -1
  140. package/dist/content/words.d.ts +3 -0
  141. package/dist/content/words.d.ts.map +1 -0
  142. package/dist/content/words.js +120 -0
  143. package/dist/content/words.js.map +1 -0
  144. package/dist/content/write.d.ts +8 -0
  145. package/dist/content/write.d.ts.map +1 -1
  146. package/dist/content/write.js +1 -1
  147. package/dist/content/write.js.map +1 -1
  148. package/dist/files/data-files.d.ts +5 -0
  149. package/dist/files/data-files.d.ts.map +1 -1
  150. package/dist/files/data-files.js +30 -0
  151. package/dist/files/data-files.js.map +1 -1
  152. package/dist/fonts/css.d.ts +25 -0
  153. package/dist/fonts/css.d.ts.map +1 -0
  154. package/dist/fonts/css.js +88 -0
  155. package/dist/fonts/css.js.map +1 -0
  156. package/dist/fonts/family.d.ts +23 -0
  157. package/dist/fonts/family.d.ts.map +1 -0
  158. package/dist/fonts/family.js +41 -0
  159. package/dist/fonts/family.js.map +1 -0
  160. package/dist/fonts/index.d.ts +10 -0
  161. package/dist/fonts/index.d.ts.map +1 -0
  162. package/dist/fonts/index.js +6 -0
  163. package/dist/fonts/index.js.map +1 -0
  164. package/dist/fonts/job.d.ts +20 -0
  165. package/dist/fonts/job.d.ts.map +1 -0
  166. package/dist/fonts/job.js +49 -0
  167. package/dist/fonts/job.js.map +1 -0
  168. package/dist/fonts/roles.d.ts +53 -0
  169. package/dist/fonts/roles.d.ts.map +1 -0
  170. package/dist/fonts/roles.js +64 -0
  171. package/dist/fonts/roles.js.map +1 -0
  172. package/dist/fonts/store.d.ts +69 -0
  173. package/dist/fonts/store.d.ts.map +1 -0
  174. package/dist/fonts/store.js +237 -0
  175. package/dist/fonts/store.js.map +1 -0
  176. package/dist/gemini/capsule.d.ts +4 -0
  177. package/dist/gemini/capsule.d.ts.map +1 -0
  178. package/dist/gemini/capsule.js +9 -0
  179. package/dist/gemini/capsule.js.map +1 -0
  180. package/dist/gemini/certificate.d.ts +34 -0
  181. package/dist/gemini/certificate.d.ts.map +1 -0
  182. package/dist/gemini/certificate.js +255 -0
  183. package/dist/gemini/certificate.js.map +1 -0
  184. package/dist/gemini/site-certificate.d.ts +8 -0
  185. package/dist/gemini/site-certificate.d.ts.map +1 -0
  186. package/dist/gemini/site-certificate.js +17 -0
  187. package/dist/gemini/site-certificate.js.map +1 -0
  188. package/dist/micropub/endpoint.d.ts.map +1 -1
  189. package/dist/micropub/endpoint.js +12 -0
  190. package/dist/micropub/endpoint.js.map +1 -1
  191. package/dist/plugin.d.ts +15 -2
  192. package/dist/plugin.d.ts.map +1 -1
  193. package/dist/plugin.js.map +1 -1
  194. package/dist/settings/registry.d.ts.map +1 -1
  195. package/dist/settings/registry.js +5 -1
  196. package/dist/settings/registry.js.map +1 -1
  197. package/dist/settings/types.d.ts +1 -1
  198. package/dist/settings/types.d.ts.map +1 -1
  199. package/dist/site/dashboard-layout.d.ts +33 -26
  200. package/dist/site/dashboard-layout.d.ts.map +1 -1
  201. package/dist/site/dashboard-layout.js +94 -39
  202. package/dist/site/dashboard-layout.js.map +1 -1
  203. package/dist/site/namespace.d.ts +6 -0
  204. package/dist/site/namespace.d.ts.map +1 -1
  205. package/dist/site/namespace.js +46 -1
  206. package/dist/site/namespace.js.map +1 -1
  207. package/dist/site/users.d.ts +7 -0
  208. package/dist/site/users.d.ts.map +1 -1
  209. package/dist/site/users.js +7 -0
  210. package/dist/site/users.js.map +1 -1
  211. package/dist/site/writing-goals.d.ts +22 -0
  212. package/dist/site/writing-goals.d.ts.map +1 -0
  213. package/dist/site/writing-goals.js +42 -0
  214. package/dist/site/writing-goals.js.map +1 -0
  215. package/dist/store/schema.d.ts.map +1 -1
  216. package/dist/store/schema.js +4 -0
  217. package/dist/store/schema.js.map +1 -1
  218. package/dist/store/sessions.d.ts +2 -1
  219. package/dist/store/sessions.d.ts.map +1 -1
  220. package/dist/store/sessions.js +30 -12
  221. package/dist/store/sessions.js.map +1 -1
  222. package/dist/theme/font-family.d.ts +13 -0
  223. package/dist/theme/font-family.d.ts.map +1 -0
  224. package/dist/theme/font-family.js +21 -0
  225. package/dist/theme/font-family.js.map +1 -0
  226. package/dist/theme/scheme-tokens.d.ts +50 -0
  227. package/dist/theme/scheme-tokens.d.ts.map +1 -0
  228. package/dist/theme/scheme-tokens.js +240 -0
  229. package/dist/theme/scheme-tokens.js.map +1 -0
  230. package/dist/theme/site-data.d.ts +12 -0
  231. package/dist/theme/site-data.d.ts.map +1 -1
  232. package/dist/theme/site-data.js +15 -0
  233. package/dist/theme/site-data.js.map +1 -1
  234. package/dist/theme/themes.d.ts +74 -0
  235. package/dist/theme/themes.d.ts.map +1 -1
  236. package/dist/theme/themes.js +100 -9
  237. package/dist/theme/themes.js.map +1 -1
  238. package/dist/util/public-address.d.ts +1 -0
  239. package/dist/util/public-address.d.ts.map +1 -1
  240. package/dist/util/public-address.js +38 -30
  241. package/dist/util/public-address.js.map +1 -1
  242. package/dist/web/access-line.d.ts +2 -0
  243. package/dist/web/access-line.d.ts.map +1 -0
  244. package/dist/web/access-line.js +6 -0
  245. package/dist/web/access-line.js.map +1 -0
  246. package/dist/web/document-page.d.ts.map +1 -1
  247. package/dist/web/document-page.js +3 -4
  248. package/dist/web/document-page.js.map +1 -1
  249. package/dist/web/embed.d.ts.map +1 -1
  250. package/dist/web/embed.js +2 -1
  251. package/dist/web/embed.js.map +1 -1
  252. package/dist/web/env.d.ts +2 -0
  253. package/dist/web/env.d.ts.map +1 -1
  254. package/dist/web/feed-routes.d.ts.map +1 -1
  255. package/dist/web/feed-routes.js +4 -4
  256. package/dist/web/feed-routes.js.map +1 -1
  257. package/dist/web/feed-source.d.ts +1 -1
  258. package/dist/web/feed-source.d.ts.map +1 -1
  259. package/dist/web/feed-source.js +1 -1
  260. package/dist/web/feed-source.js.map +1 -1
  261. package/dist/web/font-routes.d.ts +13 -0
  262. package/dist/web/font-routes.d.ts.map +1 -0
  263. package/dist/web/font-routes.js +27 -0
  264. package/dist/web/font-routes.js.map +1 -0
  265. package/dist/web/gemini-listener.d.ts +30 -0
  266. package/dist/web/gemini-listener.d.ts.map +1 -0
  267. package/dist/web/gemini-listener.js +186 -0
  268. package/dist/web/gemini-listener.js.map +1 -0
  269. package/dist/web/gemini-request.d.ts +23 -0
  270. package/dist/web/gemini-request.d.ts.map +1 -0
  271. package/dist/web/gemini-request.js +127 -0
  272. package/dist/web/gemini-request.js.map +1 -0
  273. package/dist/web/listing-pages.d.ts.map +1 -1
  274. package/dist/web/listing-pages.js +7 -5
  275. package/dist/web/listing-pages.js.map +1 -1
  276. package/dist/web/llms.d.ts +1 -0
  277. package/dist/web/llms.d.ts.map +1 -1
  278. package/dist/web/llms.js +3 -0
  279. package/dist/web/llms.js.map +1 -1
  280. package/dist/web/maintenance.d.ts.map +1 -1
  281. package/dist/web/maintenance.js +6 -2
  282. package/dist/web/maintenance.js.map +1 -1
  283. package/dist/web/manifest.d.ts +8 -5
  284. package/dist/web/manifest.d.ts.map +1 -1
  285. package/dist/web/manifest.js +10 -7
  286. package/dist/web/manifest.js.map +1 -1
  287. package/dist/web/markdown-representation.d.ts +11 -20
  288. package/dist/web/markdown-representation.d.ts.map +1 -1
  289. package/dist/web/markdown-representation.js +57 -58
  290. package/dist/web/markdown-representation.js.map +1 -1
  291. package/dist/web/negotiate.d.ts +4 -16
  292. package/dist/web/negotiate.d.ts.map +1 -1
  293. package/dist/web/negotiate.js +23 -18
  294. package/dist/web/negotiate.js.map +1 -1
  295. package/dist/web/oembed.d.ts +17 -3
  296. package/dist/web/oembed.d.ts.map +1 -1
  297. package/dist/web/oembed.js +68 -26
  298. package/dist/web/oembed.js.map +1 -1
  299. package/dist/web/proxy-protocol.d.ts +13 -0
  300. package/dist/web/proxy-protocol.d.ts.map +1 -0
  301. package/dist/web/proxy-protocol.js +79 -0
  302. package/dist/web/proxy-protocol.js.map +1 -0
  303. package/dist/web/render.d.ts +52 -22
  304. package/dist/web/render.d.ts.map +1 -1
  305. package/dist/web/render.js +94 -30
  306. package/dist/web/render.js.map +1 -1
  307. package/dist/web/routes.d.ts.map +1 -1
  308. package/dist/web/routes.js +7 -8
  309. package/dist/web/routes.js.map +1 -1
  310. package/dist/web/site-index.d.ts.map +1 -1
  311. package/dist/web/site-index.js +6 -2
  312. package/dist/web/site-index.js.map +1 -1
  313. package/dist/web/status-pages.d.ts +2 -3
  314. package/dist/web/status-pages.d.ts.map +1 -1
  315. package/dist/web/status-pages.js +14 -11
  316. package/dist/web/status-pages.js.map +1 -1
  317. package/dist/web/throttle.d.ts +9 -0
  318. package/dist/web/throttle.d.ts.map +1 -1
  319. package/dist/web/throttle.js +17 -0
  320. package/dist/web/throttle.js.map +1 -1
  321. package/dist/webmention/fetch-public.d.ts +6 -0
  322. package/dist/webmention/fetch-public.d.ts.map +1 -1
  323. package/dist/webmention/fetch-public.js +6 -1
  324. package/dist/webmention/fetch-public.js.map +1 -1
  325. package/dist/writing/ledger.d.ts +15 -0
  326. package/dist/writing/ledger.d.ts.map +1 -0
  327. package/dist/writing/ledger.js +70 -0
  328. package/dist/writing/ledger.js.map +1 -0
  329. package/dist/writing/progress.d.ts +25 -0
  330. package/dist/writing/progress.d.ts.map +1 -0
  331. package/dist/writing/progress.js +83 -0
  332. package/dist/writing/progress.js.map +1 -0
  333. package/package.json +2 -1
  334. package/themes/default/layouts/404.gmi.njk +10 -0
  335. package/themes/default/layouts/410.gmi.njk +8 -0
  336. package/themes/default/layouts/500.gmi.njk +9 -0
  337. package/themes/default/layouts/503.gmi.njk +9 -0
  338. package/themes/default/layouts/base.njk +31 -16
  339. package/themes/default/layouts/page.njk +4 -8
  340. package/themes/default/partials/bio.njk +1 -1
  341. package/themes/default/partials/contact-form.njk +1 -1
  342. package/themes/default/partials/markdown-footer.md.njk +9 -1
  343. package/themes/default/src/style.css +326 -15
  344. package/themes/default/static/style.css +489 -3
  345. package/themes/default/theme.json +23 -1
@@ -87,23 +87,19 @@
87
87
  {% endif %}
88
88
  {% set breadcrumbs = [{ "name": "Home", "url": "/" }].concat(crumbs) if crumbs.length else [] %}
89
89
  <!doctype html>
90
- <html lang="{{ site.language | default("en") }}">
90
+ <html lang="{{ site.language | default("en") }}"{% if theme.scheme %} data-scheme="{{ theme.scheme.name }}" data-mode="{{ theme.mode }}"{% endif %}>
91
91
  <head>
92
92
  <meta charset="utf-8">
93
93
  <meta name="viewport" content="width=device-width, initial-scale=1">
94
- {#
95
- The colours the theme's `theme.json` declares (TASK-146). The colour
96
- scheme goes before the stylesheet, so a reader in dark mode gets a dark
97
- canvas while the stylesheet is still on its way rather than a white
98
- flash. The theme colour tints the browser around the page, one per
99
- scheme, and is the page's own background so the two meet without a seam.
100
- #}
101
- {% if theme.colorScheme %}
102
- <meta name="color-scheme" content="{{ theme.colorScheme }}">
94
+ {% set colorModes = (["light", "dark"] if theme.mode == "system" else [theme.mode]) if theme.scheme else ["light", "dark"] %}
95
+ {% set themeColor = theme.scheme.themeColor if theme.scheme else theme.themeColor %}
96
+ {% set colorScheme = colorModes | join(" ") if theme.scheme else theme.colorScheme %}
97
+ {% if colorScheme %}
98
+ <meta name="color-scheme" content="{{ colorScheme }}">
103
99
  {% endif %}
104
- {% for scheme in ["light", "dark"] %}
105
- {% if theme.themeColor[scheme] %}
106
- <meta name="theme-color" content="{{ theme.themeColor[scheme] }}" media="(prefers-color-scheme: {{ scheme }})">
100
+ {% for mode in colorModes %}
101
+ {% if themeColor[mode] %}
102
+ <meta name="theme-color" content="{{ themeColor[mode] }}"{% if colorModes.length > 1 %} media="(prefers-color-scheme: {{ mode }})"{% endif %}>
107
103
  {% endif %}
108
104
  {% endfor %}
109
105
  <title>{% block title %}{% if pageTitle %}{{ pageTitle }} &middot; {% endif %}{{ site.title }}{% endblock %}</title>
@@ -114,6 +110,18 @@
114
110
  {% endif %}
115
111
  <link rel="canonical" href="{{ canonicalUrl }}">
116
112
  <link rel="stylesheet" href="{{ "style.css" | asset }}">
113
+ {% if fonts %}
114
+ {% for href in fonts.stylesheets %}
115
+ <link rel="stylesheet" href="{{ href | url }}">
116
+ {% endfor %}
117
+ <style{% if cspNonce %} nonce="{{ cspNonce }}"{% endif %}>
118
+ :root {
119
+ {% for font in fonts.properties %}
120
+ {{ font.property }}: {{ font.value | safe }};
121
+ {% endfor %}
122
+ }
123
+ </style>
124
+ {% endif %}
117
125
  {% block speculationRules %}
118
126
  {#
119
127
  Prefetch the page behind a link the reader is about to follow: a hover
@@ -159,6 +167,9 @@
159
167
  {% if activityStreams %}
160
168
  <link rel="alternate" type="application/activity+json" href="{{ activityStreams }}">
161
169
  {% endif %}
170
+ {% if capsuleUrl %}
171
+ <link rel="alternate" type="text/gemini" href="{{ capsuleUrl }}">
172
+ {% endif %}
162
173
  {% endblock %}
163
174
  {% if webmention %}
164
175
  <link rel="webmention" href="{{ webmention | url }}">
@@ -283,7 +294,9 @@
283
294
  <header class="global-header">
284
295
  {% if atRoot %}
285
296
  <h1 class="main-heading">
286
- <a href="{{ "/" | url }}">{{ site.title }}</a>
297
+ <a href="{{ "/" | url }}">
298
+ {%- if headerIcon %}<img class="site-icon" src="{{ headerIcon | url }}" alt="" width="48" height="48">{% endif -%}
299
+ {{ site.title }}</a>
287
300
  </h1>
288
301
  {% if site.tagline %}
289
302
  <p class="site-tagline">{{ site.tagline }}</p>
@@ -291,7 +304,9 @@
291
304
  {% else %}
292
305
  {#- The solo author's own archive claims the homepage back, so the
293
306
  two URLs are provably one person (TASK-180). -#}
294
- <a class="header-link-home"{% if isAuthorArchive and soloAuthor.url == author.url %} rel="me"{% endif %} href="{{ "/" | url }}">{{ site.title }}</a>
307
+ <a class="header-link-home"{% if isAuthorArchive and soloAuthor.url == author.url %} rel="me"{% endif %} href="{{ "/" | url }}">
308
+ {%- if headerIcon %}<img class="site-icon" src="{{ headerIcon | url }}" alt="" width="24" height="24">{% endif -%}
309
+ {{ site.title }}</a>
295
310
  {% endif %}
296
311
  {{ nav.list(menus.primary, "Site") }}
297
312
  </header>
@@ -304,7 +319,7 @@
304
319
 
305
320
  {% block footer %}
306
321
  <footer>
307
- <p>&copy; {{ "now" | date("year") }}, {{ soloAuthor.name or site.title }}{% if license %} &middot; <a rel="license" href="{{ license.url }}">{{ license.name }}</a>{% endif %} &middot; Published with Geekity</p>
322
+ <p>&copy; {{ "now" | date("year") }}, {{ soloAuthor.name or site.title }}{% if license %} &middot; <a rel="license" href="{{ license.url }}">{{ license.name }}</a>{% endif %} &middot; Published with Geekity CMS</p>
308
323
  {#
309
324
  The footer menu: the `footer` area this theme declares in its
310
325
  `theme.json`, which a site fills in on the Navigation screen, and the
@@ -3,10 +3,6 @@
3
3
  TASK-83): the same `blog-post h-entry` a post is, with the same Published
4
4
  line inside the `e-content` and the same bio under a rule.
5
5
 
6
- Two front matter keys add to it: `contact: true` puts the contact form under
7
- the words, and `archive: true` puts every post the site has published under
8
- them, month by month (TASK-85).
9
-
10
6
  What a page does not have: an IndieNews link, since it is not a post
11
7
  anybody syndicates; neighbours, since it is in no archive; and taxonomy,
12
8
  since only posts are filed. The bio credits `siteAuthor` — a page is by
@@ -53,6 +49,10 @@
53
49
  {% include "partials/archive.njk" %}
54
50
  {% endif %}
55
51
 
52
+ {% if contactForm %}
53
+ {% include "partials/contact-form.njk" %}
54
+ {% endif %}
55
+
56
56
  {#- The rule and the footer are the bio's own: a site whose author setting
57
57
  names nobody with an account here ends the page at its words. -#}
58
58
  {% if bioAuthor %}
@@ -72,8 +72,4 @@
72
72
  {% include "partials/comment-form.njk" %}
73
73
  {% endif %}
74
74
 
75
- {# Only a page whose front matter says `contact: true` has one (TASK-56). #}
76
- {% if contactForm %}
77
- {% include "partials/contact-form.njk" %}
78
- {% endif %}
79
75
  {% endblock %}
@@ -68,7 +68,7 @@
68
68
  {%- else %}
69
69
  <strong class="p-name">{{ bioAuthor.name }}</strong>
70
70
  {%- endif %}
71
- {%- if bioAuthor.jobTitle %}, a <span class="p-job-title">{{ bioAuthor.jobTitle }}</span>{% endif %}
71
+ {%- if bioAuthor.jobTitle %}, <span class="p-job-title">{{ bioAuthor.jobTitle }}</span>{% endif %}
72
72
  {%- if bioAuthor.location %} from <span class="p-locality">{{ bioAuthor.location }}</span>{% endif %}.
73
73
  </p>
74
74
 
@@ -1,5 +1,5 @@
1
1
  {#
2
- The form under a page whose front matter says `contact: true`.
2
+ The form on a page whose front matter says `contact: true`.
3
3
 
4
4
  `contactForm` is on the context only when the page asked for one, so a layout
5
5
  asks `{% if contactForm %}` and nothing else. A site replaces this whole
@@ -27,7 +27,9 @@
27
27
  under its list item. `commentForm` and `contactForm` are each the `url` of
28
28
  the form on the HTML page, printed as it is, since a form needs HTML;
29
29
  `commentForm` is absent while comments are closed. `webmention` is there
30
- when the site takes webmentions.
30
+ when the site takes webmentions. `capsuleUrl` is this page's gemini:// URL
31
+ while the site serves Gemini, and is never set when this is written as
32
+ gemtext.
31
33
  `thread` is on a comment's own page, as the header describes it: its
32
34
  `comment.replies` are threaded as a conversation's are, and `onPostUrl` is the
33
35
  comment on the post's page.
@@ -135,6 +137,12 @@ Or reply from your own site and send a [webmention](https://indieweb.org/Webment
135
137
 
136
138
  [Send a message on the web page]({{ contactForm.url }})
137
139
 
140
+ {% endif %}
141
+ {% if capsuleUrl %}
142
+ ## Gemini
143
+
144
+ [Read this page over Gemini]({{ capsuleUrl }})
145
+
138
146
  {% endif %}
139
147
  {% if feeds.length %}
140
148
  ## Feeds
@@ -4,11 +4,12 @@
4
4
  * The source. `pnpm build` compiles it with Tailwind v4 to `static/style.css`,
5
5
  * which is what a page loads and what the package ships; that file is a build
6
6
  * product and gitignored. Nothing about Tailwind reaches a reader: no script,
7
- * no CDN, no web font, one stylesheet.
7
+ * no CDN, one stylesheet. A site may choose Google Fonts for headings and
8
+ * body; the site serves their files itself, so nothing third-party loads.
8
9
  *
9
10
  * One warm column at 42rem, serif throughout, sans reserved for small labels.
10
11
  * Only an article has a headline; every other kind of post is its words under
11
- * a small-caps kicker that names the kind. Dark mode follows the system.
12
+ * a small-caps kicker that names the kind.
12
13
  *
13
14
  * The look lives here, on the theme's semantic class names, through `@apply`:
14
15
  * the templates carry no utility classes, so a site theme that has CSS for the
@@ -19,18 +20,39 @@
19
20
  * "Colours" in docs/theme/page-shell.md). `src/web/theme-colors.test.ts` reads
20
21
  * them out of the compiled file and computes the WCAG 2.2 ratio of every pair
21
22
  * the design puts on screen: every run of text at 7:1, every border a reader
22
- * relies on at 3:1, in both schemes. `--color-rule` is the one exception, a
23
- * decorative hairline nothing a reader needs is drawn with.
23
+ * relies on at 3:1, in every scheme and both modes. `--color-rule` is the one
24
+ * exception, a decorative hairline nothing a reader needs is drawn with.
24
25
  */
25
26
  @import 'tailwindcss' source(none);
26
27
  @source '../layouts';
27
28
  @source '../partials';
28
29
 
30
+ @custom-variant dark {
31
+ @media (prefers-color-scheme: dark) {
32
+ &:not([data-mode='light']) {
33
+ @slot;
34
+ }
35
+ }
36
+
37
+ &[data-mode='dark'] {
38
+ @slot;
39
+ }
40
+ }
41
+
29
42
  :root {
30
- /* Light and dark are both drawn below, so a browser may paint its own form
31
- controls, scrollbars and spellcheck marks to match. */
32
43
  color-scheme: light dark;
44
+ }
45
+
46
+ :root[data-mode='light'] {
47
+ color-scheme: light;
48
+ }
49
+
50
+ :root[data-mode='dark'] {
51
+ color-scheme: dark;
52
+ }
33
53
 
54
+ :root,
55
+ :root[data-scheme='paper'] {
34
56
  /* `body` is the paper and `text` the ink. `muted` is every small line of
35
57
  sans and every quote; `primary` is links, the kind a kicker names and the
36
58
  citation rule; `secondary` is tags and the focus outline. `rule` is a
@@ -72,10 +94,8 @@
72
94
  --color-code-meta: #6d453c; /* base0F, stock #a3685a */
73
95
  --color-code-added-background: #dcedd3;
74
96
  --color-code-removed-background: #f5d8d6;
75
- }
76
97
 
77
- @media (prefers-color-scheme: dark) {
78
- :root {
98
+ @variant dark {
79
99
  --color-body: #171412;
80
100
  --color-text: #ece6de;
81
101
  --color-muted: #b2aaa0;
@@ -108,6 +128,286 @@
108
128
  }
109
129
  }
110
130
 
131
+ :root[data-scheme='slate'] {
132
+ --color-body: #f4f7fb;
133
+ --color-text: #161b20;
134
+ --color-muted: #4b4f54;
135
+ --color-primary: #0f4e94;
136
+ --color-secondary: #59447b;
137
+ --color-rule: #dadee3;
138
+ --color-edge: #82868a;
139
+ --color-base: #edf1f6;
140
+ --color-base-2: #f3f2f5;
141
+ --color-base-3: #ffffff;
142
+ --color-code-background: #edf1f6;
143
+ --color-code-text: #161b20;
144
+ --color-error: #9d121d;
145
+ --color-code-comment: #4e4e4e;
146
+ --color-code-tag: #514e4f;
147
+ --color-code-name: #991c21;
148
+ --color-code-literal: #7c3e03;
149
+ --color-code-class: #614c02;
150
+ --color-code-string: #405603;
151
+ --color-code-support: #045858;
152
+ --color-code-function: #1f4f8a;
153
+ --color-code-keyword: #6b3a7f;
154
+ --color-code-meta: #6d443a;
155
+ --color-code-added-background: #d6f0d6;
156
+ --color-code-removed-background: #fedbda;
157
+
158
+ @variant dark {
159
+ --color-body: #12161c;
160
+ --color-text: #e3e8f0;
161
+ --color-muted: #a3adba;
162
+ --color-primary: #80b7fe;
163
+ --color-secondary: #b7a2e0;
164
+ --color-rule: #212831;
165
+ --color-edge: #676e77;
166
+ --color-base: #181f27;
167
+ --color-base-2: #1e1d22;
168
+ --color-base-3: #21272f;
169
+ --color-code-background: #181f27;
170
+ --color-code-text: #e3e8f0;
171
+ --color-error: #ff8a83;
172
+ --color-code-comment: #acacac;
173
+ --color-code-tag: #adabab;
174
+ --color-code-name: #ff8a83;
175
+ --color-code-literal: #f29551;
176
+ --color-code-class: #cca83c;
177
+ --color-code-string: #95b84d;
178
+ --color-code-support: #5bbaba;
179
+ --color-code-function: #7caff1;
180
+ --color-code-keyword: #cd98e4;
181
+ --color-code-meta: #d1a195;
182
+ --color-code-added-background: #213622;
183
+ --color-code-removed-background: #442727;
184
+ }
185
+ }
186
+
187
+ :root[data-scheme='forest'] {
188
+ --color-body: #f5f7ed;
189
+ --color-text: #1a1b15;
190
+ --color-muted: #4d4f42;
191
+ --color-primary: #035b27;
192
+ --color-secondary: #734301;
193
+ --color-rule: #dcdfd0;
194
+ --color-edge: #84867b;
195
+ --color-base: #eff1e4;
196
+ --color-base-2: #eef3ef;
197
+ --color-base-3: #ffffff;
198
+ --color-code-background: #eff1e4;
199
+ --color-code-text: #1a1b15;
200
+ --color-error: #9c111c;
201
+ --color-code-comment: #4e4e4e;
202
+ --color-code-tag: #504d4e;
203
+ --color-code-name: #991b21;
204
+ --color-code-literal: #7b3d02;
205
+ --color-code-class: #604b01;
206
+ --color-code-string: #3f5501;
207
+ --color-code-support: #025757;
208
+ --color-code-function: #1e4e89;
209
+ --color-code-keyword: #6a3a7f;
210
+ --color-code-meta: #6c4339;
211
+ --color-code-added-background: #d6f0d6;
212
+ --color-code-removed-background: #fedbda;
213
+
214
+ @variant dark {
215
+ --color-body: #0f1912;
216
+ --color-text: #e2eae4;
217
+ --color-muted: #9db1a3;
218
+ --color-primary: #75c687;
219
+ --color-secondary: #daa168;
220
+ --color-rule: #1c2c22;
221
+ --color-edge: #627166;
222
+ --color-base: #142219;
223
+ --color-base-2: #182020;
224
+ --color-base-3: #1c2a21;
225
+ --color-code-background: #142219;
226
+ --color-code-text: #e2eae4;
227
+ --color-error: #fe8c84;
228
+ --color-code-comment: #acacac;
229
+ --color-code-tag: #aeacac;
230
+ --color-code-name: #fe8c84;
231
+ --color-code-literal: #f39651;
232
+ --color-code-class: #cca83c;
233
+ --color-code-string: #95b84d;
234
+ --color-code-support: #5cbbba;
235
+ --color-code-function: #7caff1;
236
+ --color-code-keyword: #cd99e5;
237
+ --color-code-meta: #d1a195;
238
+ --color-code-added-background: #213622;
239
+ --color-code-removed-background: #442727;
240
+ }
241
+ }
242
+
243
+ :root[data-scheme='plum'] {
244
+ --color-body: #fbf3fa;
245
+ --color-text: #1e191d;
246
+ --color-muted: #544b53;
247
+ --color-primary: #822973;
248
+ --color-secondary: #3f488b;
249
+ --color-rule: #e4d9e2;
250
+ --color-edge: #8a8289;
251
+ --color-base: #f6ecf5;
252
+ --color-base-2: #f6f0f1;
253
+ --color-base-3: #ffffff;
254
+ --color-code-background: #f6ecf5;
255
+ --color-code-text: #1e191d;
256
+ --color-error: #9c111c;
257
+ --color-code-comment: #4d4d4d;
258
+ --color-code-tag: #504d4e;
259
+ --color-code-name: #981b20;
260
+ --color-code-literal: #7b3d02;
261
+ --color-code-class: #604b01;
262
+ --color-code-string: #3f5501;
263
+ --color-code-support: #025757;
264
+ --color-code-function: #1e4e89;
265
+ --color-code-keyword: #6a397e;
266
+ --color-code-meta: #6c4339;
267
+ --color-code-added-background: #d6f0d6;
268
+ --color-code-removed-background: #fedbda;
269
+
270
+ @variant dark {
271
+ --color-body: #1b121d;
272
+ --color-text: #ece5ed;
273
+ --color-muted: #b7a5bc;
274
+ --color-primary: #f493e0;
275
+ --color-secondary: #98a6f2;
276
+ --color-rule: #302233;
277
+ --color-edge: #766879;
278
+ --color-base: #251928;
279
+ --color-base-2: #251b1e;
280
+ --color-base-3: #2e2131;
281
+ --color-code-background: #251928;
282
+ --color-code-text: #ece5ed;
283
+ --color-error: #ff8880;
284
+ --color-code-comment: #ababab;
285
+ --color-code-tag: #acaaab;
286
+ --color-code-name: #ff8880;
287
+ --color-code-literal: #f1944f;
288
+ --color-code-class: #cba63a;
289
+ --color-code-string: #94b74c;
290
+ --color-code-support: #5ab9b8;
291
+ --color-code-function: #7aadef;
292
+ --color-code-keyword: #cb97e3;
293
+ --color-code-meta: #d0a093;
294
+ --color-code-added-background: #213622;
295
+ --color-code-removed-background: #442727;
296
+ }
297
+ }
298
+
299
+ :root[data-scheme='ocean'] {
300
+ --color-body: #eef9fb;
301
+ --color-text: #141c1d;
302
+ --color-muted: #435153;
303
+ --color-primary: #04585c;
304
+ --color-secondary: #184f90;
305
+ --color-rule: #d2e1e3;
306
+ --color-edge: #7c888a;
307
+ --color-base: #e5f4f6;
308
+ --color-base-2: #eff3f7;
309
+ --color-base-3: #ffffff;
310
+ --color-code-background: #e5f4f6;
311
+ --color-code-text: #141c1d;
312
+ --color-error: #9e131d;
313
+ --color-code-comment: #4f4f4f;
314
+ --color-code-tag: #514e4f;
315
+ --color-code-name: #991c21;
316
+ --color-code-literal: #7d3e00;
317
+ --color-code-class: #624c03;
318
+ --color-code-string: #405603;
319
+ --color-code-support: #045858;
320
+ --color-code-function: #1f4f8a;
321
+ --color-code-keyword: #6b3b80;
322
+ --color-code-meta: #6d443a;
323
+ --color-code-added-background: #d6f0d6;
324
+ --color-code-removed-background: #fedbda;
325
+
326
+ @variant dark {
327
+ --color-body: #08191f;
328
+ --color-text: #e0eaee;
329
+ --color-muted: #91b1be;
330
+ --color-primary: #57c5cb;
331
+ --color-secondary: #77aff7;
332
+ --color-rule: #122b35;
333
+ --color-edge: #59717a;
334
+ --color-base: #0a212a;
335
+ --color-base-2: #1a1e26;
336
+ --color-base-3: #122a33;
337
+ --color-code-background: #0a212a;
338
+ --color-code-text: #e0eaee;
339
+ --color-error: #ff8a83;
340
+ --color-code-comment: #acacac;
341
+ --color-code-tag: #adabab;
342
+ --color-code-name: #ff8a83;
343
+ --color-code-literal: #f29551;
344
+ --color-code-class: #cca83c;
345
+ --color-code-string: #95b84d;
346
+ --color-code-support: #5bbaba;
347
+ --color-code-function: #7caff1;
348
+ --color-code-keyword: #cd98e4;
349
+ --color-code-meta: #d1a195;
350
+ --color-code-added-background: #213622;
351
+ --color-code-removed-background: #442727;
352
+ }
353
+ }
354
+
355
+ :root[data-scheme='ink'] {
356
+ --color-body: #ffffff;
357
+ --color-text: #030303;
358
+ --color-muted: #3f3f3f;
359
+ --color-primary: #1b388a;
360
+ --color-secondary: #3f3f3f;
361
+ --color-rule: #e6e6e6;
362
+ --color-edge: #737373;
363
+ --color-base: #f9f9f9;
364
+ --color-base-2: #fbfbfb;
365
+ --color-base-3: #ffffff;
366
+ --color-code-background: #f9f9f9;
367
+ --color-code-text: #030303;
368
+ --color-error: #840111;
369
+ --color-code-comment: #3f3f3f;
370
+ --color-code-tag: #3f3e3f;
371
+ --color-code-name: #6c2927;
372
+ --color-code-literal: #61320b;
373
+ --color-code-class: #4e3d02;
374
+ --color-code-string: #334408;
375
+ --color-code-support: #114646;
376
+ --color-code-function: #264061;
377
+ --color-code-keyword: #4f345b;
378
+ --color-code-meta: #513933;
379
+ --color-code-added-background: #d6f0d6;
380
+ --color-code-removed-background: #fedbda;
381
+
382
+ @variant dark {
383
+ --color-body: #0d0d0d;
384
+ --color-text: #f5f5f5;
385
+ --color-muted: #c2c2c2;
386
+ --color-primary: #aec8fe;
387
+ --color-secondary: #c2c2c2;
388
+ --color-rule: #1e1e1e;
389
+ --color-edge: #7f7f7f;
390
+ --color-base: #151515;
391
+ --color-base-2: #151515;
392
+ --color-base-3: #1d1d1d;
393
+ --color-code-background: #151515;
394
+ --color-code-text: #f5f5f5;
395
+ --color-error: #ffaaa2;
396
+ --color-code-comment: #c2c2c2;
397
+ --color-code-tag: #c1c0c0;
398
+ --color-code-name: #fcaba4;
399
+ --color-code-literal: #edb48d;
400
+ --color-code-class: #d4bf86;
401
+ --color-code-string: #b1c88c;
402
+ --color-code-support: #96cac9;
403
+ --color-code-function: #a4c3eb;
404
+ --color-code-keyword: #d4b5e3;
405
+ --color-code-meta: #d8bab2;
406
+ --color-code-added-background: #213622;
407
+ --color-code-removed-background: #442727;
408
+ }
409
+ }
410
+
111
411
  /* Tailwind's utilities, drawn from the tokens above rather than its own
112
412
  palette, which is cleared so a utility can only name a colour of this
113
413
  design. `inline` puts the `var()` in the utility, so the scheme the custom
@@ -124,7 +424,8 @@
124
424
  --color-surface: var(--color-base);
125
425
  --color-code: var(--color-code-background);
126
426
  --color-error: var(--color-error);
127
- --font-serif: 'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', Georgia, serif;
427
+ --font-heading: var(--font-heading);
428
+ --font-body: var(--font-body);
128
429
  --font-sans: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
129
430
  --font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
130
431
  }
@@ -162,6 +463,12 @@
162
463
  }
163
464
 
164
465
  @layer base {
466
+ :root {
467
+ --font-heading:
468
+ 'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', Georgia, serif;
469
+ --font-body: 'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', Georgia, serif;
470
+ }
471
+
165
472
  /* `scrollbar-gutter` keeps the scrollbar's room whether or not the page is
166
473
  long enough to scroll, so moving between a short page and a long one does
167
474
  not shift the column sideways. */
@@ -173,7 +480,7 @@
173
480
  }
174
481
 
175
482
  body {
176
- @apply bg-paper font-serif leading-relaxed text-ink antialiased;
483
+ @apply bg-paper font-body leading-relaxed text-ink antialiased;
177
484
  }
178
485
 
179
486
  h1,
@@ -182,7 +489,7 @@
182
489
  h4,
183
490
  h5,
184
491
  h6 {
185
- @apply font-bold tracking-tight;
492
+ @apply font-heading font-bold tracking-tight;
186
493
  text-wrap: balance;
187
494
  }
188
495
 
@@ -285,7 +592,11 @@
285
592
  }
286
593
 
287
594
  .header-link-home {
288
- @apply target text-lg font-bold;
595
+ @apply target font-heading text-lg font-bold;
596
+ }
597
+
598
+ .site-icon {
599
+ @apply me-[0.3em] inline-block size-[1em] rounded-[0.18em] align-[-0.12em];
289
600
  }
290
601
 
291
602
  .site-tagline {
@@ -923,7 +1234,7 @@
923
1234
  }
924
1235
 
925
1236
  .backlinks-title {
926
- @apply mb-2 text-[0.72rem] font-normal tracking-[0.14em] text-muted uppercase;
1237
+ @apply mb-2 font-sans text-[0.72rem] font-normal tracking-[0.14em] text-muted uppercase;
927
1238
  }
928
1239
 
929
1240
  .backlinks ol {
@@ -1161,7 +1472,7 @@
1161
1472
  }
1162
1473
 
1163
1474
  :is(.comment-respond, .search-form) :is(input:not([type='checkbox'], [type='hidden']), textarea) {
1164
- @apply block w-full rounded-md border border-edge bg-surface px-3 py-2 font-serif text-base text-ink;
1475
+ @apply block w-full rounded-md border border-edge bg-surface px-3 py-2 font-body text-base text-ink;
1165
1476
  }
1166
1477
 
1167
1478
  /* A field the reader has left invalid, or one a refused submission marked,