@geekity/cms 0.13.0 → 0.14.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 (122) hide show
  1. package/README.md +18 -5
  2. package/admin/pages/documents/editor.njk +13 -0
  3. package/admin/pages/settings/general.njk +7 -6
  4. package/dist/admin/documents.d.ts +2 -0
  5. package/dist/admin/documents.d.ts.map +1 -1
  6. package/dist/admin/documents.js +28 -4
  7. package/dist/admin/documents.js.map +1 -1
  8. package/dist/admin/federation.js +2 -2
  9. package/dist/admin/federation.js.map +1 -1
  10. package/dist/admin/headers.d.ts +4 -1
  11. package/dist/admin/headers.d.ts.map +1 -1
  12. package/dist/admin/headers.js +9 -4
  13. package/dist/admin/headers.js.map +1 -1
  14. package/dist/admin/settings-general.d.ts.map +1 -1
  15. package/dist/admin/settings-general.js +28 -3
  16. package/dist/admin/settings-general.js.map +1 -1
  17. package/dist/admin/settings.d.ts +11 -9
  18. package/dist/admin/settings.d.ts.map +1 -1
  19. package/dist/admin/settings.js +6 -10
  20. package/dist/admin/settings.js.map +1 -1
  21. package/dist/config.d.ts +4 -0
  22. package/dist/config.d.ts.map +1 -1
  23. package/dist/config.js.map +1 -1
  24. package/dist/content/pinned.d.ts +26 -0
  25. package/dist/content/pinned.d.ts.map +1 -0
  26. package/dist/content/pinned.js +42 -0
  27. package/dist/content/pinned.js.map +1 -0
  28. package/dist/content/store.d.ts +7 -0
  29. package/dist/content/store.d.ts.map +1 -1
  30. package/dist/content/store.js +20 -0
  31. package/dist/content/store.js.map +1 -1
  32. package/dist/env.d.ts +7 -0
  33. package/dist/env.d.ts.map +1 -1
  34. package/dist/federation/actor.d.ts +15 -0
  35. package/dist/federation/actor.d.ts.map +1 -1
  36. package/dist/federation/actor.js +94 -3
  37. package/dist/federation/actor.js.map +1 -1
  38. package/dist/federation/article.d.ts +13 -1
  39. package/dist/federation/article.d.ts.map +1 -1
  40. package/dist/federation/article.js +28 -2
  41. package/dist/federation/article.js.map +1 -1
  42. package/dist/federation/delivery.d.ts.map +1 -1
  43. package/dist/federation/delivery.js +36 -4
  44. package/dist/federation/delivery.js.map +1 -1
  45. package/dist/federation/federation.d.ts.map +1 -1
  46. package/dist/federation/federation.js +24 -2
  47. package/dist/federation/federation.js.map +1 -1
  48. package/dist/federation/mount.js +2 -2
  49. package/dist/federation/mount.js.map +1 -1
  50. package/dist/federation/paths.d.ts +30 -0
  51. package/dist/federation/paths.d.ts.map +1 -1
  52. package/dist/federation/paths.js +36 -0
  53. package/dist/federation/paths.js.map +1 -1
  54. package/dist/images/variants.d.ts +11 -0
  55. package/dist/images/variants.d.ts.map +1 -1
  56. package/dist/images/variants.js +21 -0
  57. package/dist/images/variants.js.map +1 -1
  58. package/dist/index.d.ts +1 -1
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +5 -1
  61. package/dist/index.js.map +1 -1
  62. package/dist/indieauth/identity.d.ts +3 -3
  63. package/dist/indieauth/identity.d.ts.map +1 -1
  64. package/dist/indieauth/identity.js +6 -7
  65. package/dist/indieauth/identity.js.map +1 -1
  66. package/dist/web/admin-bar.d.ts +3 -1
  67. package/dist/web/admin-bar.d.ts.map +1 -1
  68. package/dist/web/admin-bar.js +5 -1
  69. package/dist/web/admin-bar.js.map +1 -1
  70. package/dist/web/authors.d.ts +19 -0
  71. package/dist/web/authors.d.ts.map +1 -1
  72. package/dist/web/authors.js +25 -0
  73. package/dist/web/authors.js.map +1 -1
  74. package/dist/web/feed-atom.d.ts.map +1 -1
  75. package/dist/web/feed-atom.js +2 -1
  76. package/dist/web/feed-atom.js.map +1 -1
  77. package/dist/web/feed-item.d.ts +15 -6
  78. package/dist/web/feed-item.d.ts.map +1 -1
  79. package/dist/web/feed-item.js +9 -7
  80. package/dist/web/feed-item.js.map +1 -1
  81. package/dist/web/feed-json.d.ts +2 -2
  82. package/dist/web/feed-json.d.ts.map +1 -1
  83. package/dist/web/feed-json.js +2 -1
  84. package/dist/web/feed-json.js.map +1 -1
  85. package/dist/web/feed-rss.js +1 -1
  86. package/dist/web/feed-rss.js.map +1 -1
  87. package/dist/web/feed-source.d.ts +3 -0
  88. package/dist/web/feed-source.d.ts.map +1 -1
  89. package/dist/web/feed-source.js.map +1 -1
  90. package/dist/web/feeds.d.ts.map +1 -1
  91. package/dist/web/feeds.js +7 -2
  92. package/dist/web/feeds.js.map +1 -1
  93. package/dist/web/index.d.ts +1 -1
  94. package/dist/web/index.d.ts.map +1 -1
  95. package/dist/web/index.js +1 -1
  96. package/dist/web/index.js.map +1 -1
  97. package/dist/web/oembed.d.ts +104 -0
  98. package/dist/web/oembed.d.ts.map +1 -0
  99. package/dist/web/oembed.js +290 -0
  100. package/dist/web/oembed.js.map +1 -0
  101. package/dist/web/opensearch.d.ts +35 -0
  102. package/dist/web/opensearch.d.ts.map +1 -0
  103. package/dist/web/opensearch.js +65 -0
  104. package/dist/web/opensearch.js.map +1 -0
  105. package/dist/web/render.d.ts.map +1 -1
  106. package/dist/web/render.js +6 -7
  107. package/dist/web/render.js.map +1 -1
  108. package/dist/web/routes.d.ts.map +1 -1
  109. package/dist/web/routes.js +74 -2
  110. package/dist/web/routes.js.map +1 -1
  111. package/dist/web/templates.d.ts.map +1 -1
  112. package/dist/web/templates.js +5 -0
  113. package/dist/web/templates.js.map +1 -1
  114. package/package.json +2 -1
  115. package/templates/site/content/_data/site.json +0 -1
  116. package/themes/default/README.md +65 -24
  117. package/themes/default/layouts/base.njk +23 -3
  118. package/themes/default/layouts/front-page.njk +1 -0
  119. package/themes/default/layouts/home.njk +1 -0
  120. package/themes/default/partials/bio.njk +7 -0
  121. package/themes/default/partials/jsonld.njk +33 -8
  122. package/themes/default/static/style.css +4 -0
@@ -1,5 +1,6 @@
1
1
  import { Environment, FileSystemLoader } from 'nunjucks';
2
2
  import { calendarDayIn, DEFAULT_TIMEZONE } from '../content/time.js';
3
+ import { accountOf } from '../federation/paths.js';
3
4
  import { themeAssetUrl } from './assets.js';
4
5
  import { siteLocale, siteTimezone } from './context.js';
5
6
  import { canonicalLocale, DEFAULT_LOCALE, pluralForm } from './locale.js';
@@ -113,6 +114,10 @@ function addFilters(environment, baseUrl, loader) {
113
114
  return pathname;
114
115
  }
115
116
  });
117
+ // `{{ siteAuthor.username | fediverseHandle }}`: a user's own account on
118
+ // this site, `@ada@example.com`, exactly as WebFinger answers for it
119
+ // (TASK-202), so a theme never spells the host.
120
+ environment.addFilter('fediverseHandle', (value) => typeof value === 'string' && value !== '' ? `@${accountOf(value, baseUrl)}` : '');
116
121
  return environment;
117
122
  }
118
123
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/web/templates.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/web/templates.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekity/cms",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "type": "module",
5
5
  "description": "A file-first CMS: Markdown content, a SQLite index, a Hono server that is both the editor and the public site.",
6
6
  "license": "MIT",
@@ -55,6 +55,7 @@
55
55
  "codemirror": "^6.0.2",
56
56
  "esbuild": "^0.28.2",
57
57
  "highlight.js": "11.12.0",
58
+ "microformats-parser": "^2.0.6",
58
59
  "tailwindcss": "^4.3.3",
59
60
  "tsx": "^4.23.15",
60
61
  "typescript": "^7.0.2"
@@ -2,7 +2,6 @@
2
2
  "title": "A Geekity site",
3
3
  "tagline": "Markdown on disk, served straight",
4
4
  "url": "http://localhost:3000",
5
- "author": "You",
6
5
  "language": "en",
7
6
  "menus": {
8
7
  "primary": [
@@ -204,7 +204,9 @@ stylesheet tells the two apart. `menus.primary` is printed inside the
204
204
  tagline, and everywhere else the stylesheet lays the header out as one line so
205
205
  it sits beside the link home. See [Navigation](#navigation).
206
206
 
207
- **The footer** prints the copyright with the current year and `site.author`,
207
+ **The footer** prints the copyright with the current year and the site
208
+ author's display name, `soloAuthor.name`, or the site title on a site with
209
+ several authors,
208
210
  `Published with Geekity`, and then `menus.footer` — the `footer` area this
209
211
  theme declares, and the whole of what the footer links. A site that wants its
210
212
  feed there types an `RSS | /feed/` line into it, the way the starter site does.
@@ -431,12 +433,17 @@ Links box typed. Set `bioRelMe` to `false` to keep the card and drop its
431
433
  claims: the name is linked `rel="author"` alone and `me` comes off every
432
434
  link.
433
435
 
434
- **The homepage** speaks for the site's author only on a solo author blog,
435
- which `soloAuthor` on the context says. Then both `layouts/home.njk` at `/` and
436
- `layouts/front-page.njk` end with that person's card, with its `rel="me"`
437
- claims, and their author archive's link home carries `rel="me"` back, so the
438
- homepage and the archive name each other. On any other site a listing homepage
439
- prints no card, and the front page prints its card with `bioRelMe` false. Each of
436
+ **The homepage** speaks for the site's author only on a site whose Site author
437
+ setting names a user, which `soloAuthor` on the context says. Then both
438
+ `layouts/home.njk` at `/` and `layouts/front-page.njk` end with that person's
439
+ card, with its `rel="me"` claims, and their author archive's link home carries
440
+ `rel="me"` back, so the homepage and the archive name each other. Those two
441
+ layouts also set `bioHome` to the homepage's absolute URL, which puts a
442
+ `data.u-url.u-uid` holding it first in the card, so a parser running the
443
+ [representative h-card algorithm](https://microformats.org/wiki/representative-h-card-parsing)
444
+ on the homepage finds this card as the site's (TASK-193). The archive stays a
445
+ second `u-url`. No other page sets `bioHome`. On a site
446
+ with several authors neither homepage prints a card. Each of
440
447
  those is printed only when the profile says it, so a profile holding a name
441
448
  alone prints a name alone. A name this site has no account for is printed
442
449
  unlinked, because the file still said somebody wrote this.
@@ -459,7 +466,7 @@ an overridden layout — either includes this partial instead or writes the line
459
466
  itself. It was four lines of markup, and the object behind it has not changed:
460
467
 
461
468
  ```njk
462
- {% set writer = author or { name: site.author } %}
469
+ {% set writer = author or { name: site.title } %}
463
470
  <span class="p-author h-card">
464
471
  {%- if writer.url %}<a class="u-url" href="{{ writer.url | url }}">{{ writer.name }}</a>
465
472
  {%- else %}{{ writer.name }}{% endif %}
@@ -734,26 +741,62 @@ site with no icon. `/manifest.webmanifest` gives the site's title as `name` and
734
741
  pixels plus a maskable 512 whose picture sits inside the middle 80%, padded
735
742
  with its own dominant colour. The head links it on every page.
736
743
 
744
+ **The search description** is a route too. `/opensearch.xml` is an OpenSearch
745
+ 1.1 description that names the site by its title (cut to the 16 characters
746
+ `ShortName` allows), describes it by its tagline, else its title, shows
747
+ `/favicon.ico` as its `Image` when the site has an icon, and searches
748
+ `/search/?q={searchTerms}`. Every URL in it is absolute and carries the base
749
+ path. The head links it on every page with `<link rel="search"
750
+ type="application/opensearchdescription+xml">`, outside the `head` block, so a
751
+ browser offers the site as a search engine. A theme that replaces `base.njk`
752
+ copies that line to keep the offer.
753
+
754
+ **The embed card** is a route too. `/_geekity/oembed?url=…` is an oEmbed
755
+ provider: for the URL of a published post or page it answers a `rich` embed
756
+ with the title, the author and their archive, the site as provider, a
757
+ thumbnail when the post's own `image` has a recorded size, and an `html`
758
+ card that is a blockquote of escaped text and links with no script, followed
759
+ by a hidden, sandboxed `<iframe>` of `/_geekity/embed?url=…`. That route is
760
+ the same card as a page of its own, and it is the one response another site may
761
+ frame. WordPress keeps a card from a provider it does not know only when the
762
+ card has an iframe, and it shows the frame once the page inside reports its
763
+ height. A consumer that strips iframes still has the blockquote. `maxwidth`
764
+ and `maxheight` are honoured, `format=xml` gives the same fields as XML, and
765
+ any other URL is a 404. The head of each post and page links it with
766
+ `<link rel="alternate" type="application/json+oembed">` and its `text/xml+oembed`
767
+ twin, outside the `head` block. A theme that replaces `base.njk` copies those
768
+ lines to keep the card.
769
+
737
770
  **The structured data** is `partials/jsonld.njk`, one `<script
738
771
  type="application/ld+json">` holding one `@graph` per page, and it is the only
739
772
  structured data the theme emits — there is no Microdata anywhere, by
740
773
  decision-16, because the visible markup already carries microformats2 for the
741
774
  IndieWeb. The graph holds:
742
775
 
743
- - `WebSite`, always, with the site's title, tagline and URL, and a `publisher`
744
- pointing at the Person, and a `potentialAction` that is a `SearchAction` on
745
- `/search/?q={search_term_string}`. On the homepage of a solo author blog it
746
- also has an `about` pointing at the site author's Person.
776
+ - `WebSite`, always, with the site's title, tagline and URL, and a
777
+ `potentialAction` that is a `SearchAction` on
778
+ `/search/?q={search_term_string}`. On a site whose author is a user, its
779
+ `publisher` and `about` both point at that user's Person, on every page. On
780
+ a site with several authors its `publisher` is the Organization below and it
781
+ has no `about`.
782
+ - `Organization`, on a site with several authors only: the site itself, named
783
+ for its title, at `{baseUrl}/#organization`. It publishes the `WebSite` and
784
+ every entry.
747
785
  - `Person`, from `siteAuthor`: their name, archive URL, avatar, bio, job title
748
786
  and location, and a `sameAs` of their profile links and their actor id, which
749
787
  is what asserts that the schema.org Person and the fediverse actor are one
750
788
  identity. Identity comes from a user profile, so a site — or a byline —
751
- naming nobody with an account here prints no Person, and the `author` and
752
- `publisher` references go with it.
789
+ naming nobody with an account here prints no Person, and the `author`
790
+ reference goes with it. A site with several authors prints no Person on a
791
+ page about nobody in particular.
753
792
  - `ProfilePage` on an author archive, whose `mainEntity` is that Person.
754
793
  - `BlogPosting` on a post and `Article` on a page, with the headline, URL,
755
794
  `mainEntityOfPage`, `datePublished`, `dateModified`, description, image,
756
- `author` and `publisher`.
795
+ `author`, and the site's `publisher`: the site author's Person, or the
796
+ Organization. A post with no title is headed by the words its `<title>`
797
+ names it by, its `label`, cut on a word boundary to at most 110 characters.
798
+ A post with no picture of its own, on a site with no avatar, takes its
799
+ author's photo, else the site's `icon` upload.
757
800
  - `BreadcrumbList` wherever the page prints a breadcrumb (see
758
801
  [The page shell](#the-page-shell)): one `ListItem` per crumb with its
759
802
  `position`, `name` and absolute URL as `item`.
@@ -1017,7 +1060,7 @@ Every template gets:
1017
1060
  | `site` | `content/_data/site.json`, if the site has one, over the defaults `title` and `url`. Any key in the file is readable, so `site.tagline`, `site.author` and anything else a site adds are all available. |
1018
1061
  | `menus` | Every menu the site stores, by name, marked for this page: `menus.primary`, `menus.footer`, and any other name. See [Navigation](#navigation). |
1019
1062
  | `siteAuthor` | Who the page is by, as a profile. **Absent** when nobody matches. See [Bylines and author archives](#bylines-and-author-archives). |
1020
- | `soloAuthor` | The site author's profile, on a site whose Solo author blog setting is on. **Absent** when it is off or the author setting names nobody. See [The bio](#the-bio). |
1063
+ | `soloAuthor` | The site author's profile, on every page of a site whose Site author setting names a user. **Absent** on a site with several authors. See [The bio](#the-bio). |
1021
1064
  | `icons` | The site's icons, as `{ rel, sizes, type, href }`. Empty until the site has an icon or an avatar to derive them from. See [The head](#the-head). |
1022
1065
  | `theme` | The colours the theme declares, as `{ colorScheme, themeColor: { light, dark } }`, each absent when no theme declares it. See [The manifest](#the-manifest). |
1023
1066
  | `shareImage` | The picture a shared link shows, as `{ url, alt, size: { width, height }, card }`. `size` is absent when it is not known. **Absent** when there is no picture. See [The head](#the-head). |
@@ -1121,14 +1164,12 @@ account. It resolves in this order:
1121
1164
 
1122
1165
  - the document's own `author`, on a post or a page that names one;
1123
1166
  - the person whose archive it is, on an author archive;
1124
- - the profile behind the site's `author` setting, everywhere else — the home
1125
- page, a taxonomy archive, a page that names nobody, the 404.
1126
-
1127
- It is **absent** when none of those name anybody this site has. The site
1128
- setting is read more strictly than a byline is: a byline prints the name a file
1129
- gives whether or not somebody answers to it, but a site author with no profile
1130
- behind it has no picture, no bio and nowhere to link, so there is nothing to
1131
- print and the key is not there. Write `{% if siteAuthor %}` around the bio.
1167
+ - the site author, `soloAuthor`, everywhere else — the home page, a taxonomy
1168
+ archive, a page that names nobody, the 404.
1169
+
1170
+ It is **absent** when none of those name anybody this site has, which on a
1171
+ site with several authors is every page about nobody in particular. Write
1172
+ `{% if siteAuthor %}` around the bio.
1132
1173
 
1133
1174
  The URL is not only a page. Each user is an ActivityPub actor at that address,
1134
1175
  so it is the page a follower lands on when they click through from the
@@ -152,6 +152,16 @@
152
152
  {% if webmention %}
153
153
  <link rel="webmention" href="{{ webmention | url }}">
154
154
  {% endif %}
155
+ {#- The site's search, for a browser to offer from its address bar
156
+ (TASK-204). #}
157
+ <link rel="search" type="application/opensearchdescription+xml" title="{{ site.title }}" href="{{ "/opensearch.xml" | url }}">
158
+ {#- Where a tool that is pasted this post's URL asks for its card
159
+ (TASK-205), as JSON and as XML. #}
160
+ {% if isEntry %}
161
+ {% set oembed = "/_geekity/oembed?url=" + (metaUrl | urlencode) + "&format=" %}
162
+ <link rel="alternate" type="application/json+oembed" href="{{ (oembed + "json") | absoluteUrl }}" title="{{ metaTitle }}">
163
+ <link rel="alternate" type="text/xml+oembed" href="{{ (oembed + "xml") | absoluteUrl }}" title="{{ metaTitle }}">
164
+ {% endif %}
155
165
  {#- The site's index for language models (TASK-149), from the front page,
156
166
  which is where a tool that found the site looks for it. #}
157
167
  {% if llmsTxt and atRoot %}
@@ -194,13 +204,23 @@
194
204
  {% endif %}
195
205
  {% if siteAuthor.url %}
196
206
  <meta property="article:author" content="{{ siteAuthor.url | absoluteUrl }}">
197
- {% elif siteAuthor.name or author.name or author or site.author %}
198
- <meta property="article:author" content="{{ siteAuthor.name or author.name or author or site.author }}">
207
+ {% elif siteAuthor.name or author.name or author %}
208
+ <meta property="article:author" content="{{ siteAuthor.name or author.name or author }}">
199
209
  {% endif %}
200
210
  {% for tag in tags %}
201
211
  <meta property="article:tag" content="{{ tag }}">
202
212
  {% endfor %}
203
213
  {% endif %}
214
+ {#
215
+ Who a Mastodon link preview credits, with a follow button (TASK-202):
216
+ the user's own account here, on an entry by them and on the homepage of
217
+ a site one person writes. Mastodon shows it only when that account lists
218
+ this site's domain under author attribution.
219
+ #}
220
+ {% set creator = siteAuthor if isEntry else (soloAuthor if atRoot) %}
221
+ {% if creator.username %}
222
+ <meta name="fediverse:creator" content="{{ creator.username | fediverseHandle }}">
223
+ {% endif %}
204
224
  <meta name="twitter:card" content="{{ shareImage.card if shareImage else "summary" }}">
205
225
  <meta name="twitter:title" content="{{ metaTitle }}">
206
226
  {% if metaDescription %}
@@ -261,7 +281,7 @@
261
281
 
262
282
  {% block footer %}
263
283
  <footer>
264
- <p>&copy; {{ "now" | date("year") }}{% if site.author %}, {{ site.author }}{% endif %} &middot; Published with Geekity</p>
284
+ <p>&copy; {{ "now" | date("year") }}, {{ soloAuthor.name or site.title }} &middot; Published with Geekity</p>
265
285
  {#
266
286
  The footer menu: the `footer` area this theme declares in its
267
287
  `theme.json`, which a site fills in on the Navigation screen, and the
@@ -22,6 +22,7 @@
22
22
  {#- Who the bio credits: the person the site's author setting names. -#}
23
23
  {% set bioAuthor = soloAuthor or siteAuthor %}
24
24
  {% set bioRelMe = true if soloAuthor else false %}
25
+ {% set bioHome = "/" | absoluteUrl if soloAuthor else "" %}
25
26
 
26
27
  {% block content %}
27
28
  <div class="page-body e-content">
@@ -27,6 +27,7 @@
27
27
  listing, and the homepage of any other site, is nobody's. -#}
28
28
  {% if atRoot and soloAuthor %}
29
29
  {% set bioAuthor = soloAuthor %}
30
+ {% set bioHome = "/" | absoluteUrl %}
30
31
  <hr>
31
32
  <footer>
32
33
  {% include "partials/bio.njk" %}
@@ -38,6 +38,12 @@
38
38
  homepage of a site that is not a solo author blog sets it (TASK-180), because
39
39
  that page speaks for nobody even when it shows the site author's card.
40
40
 
41
+ `bioHome` set to the homepage's absolute URL makes the card the site's
42
+ representative h-card (TASK-193): its first `u-url` and its `u-uid` are that
43
+ URL, which is what a parser reading the homepage looks for to learn who the
44
+ site is. The name keeps its link to the archive, as a second `u-url`. Only
45
+ the homepage of a solo author blog sets it; every other card is unchanged.
46
+
41
47
  The `p-note` and the `rel="me"` links are printed wherever the card is, which
42
48
  is what `bioProfile` used to ask for on an author archive alone. An entry
43
49
  left that switch unset because the page footer carried the site's identity
@@ -55,6 +61,7 @@
55
61
 
56
62
  <div>
57
63
  <p>
64
+ {%- if bioHome %}<data class="u-url u-uid" value="{{ bioHome }}"></data>{% endif %}
58
65
  {{ bioLead | default("Written by") }}
59
66
  {%- if bioAuthor.url %}
60
67
  <a class="u-url p-name" rel="author{% if bioClaims %} me{% endif %}" href="{{ bioAuthor.url | url }}">{{ bioAuthor.name }}</a>
@@ -12,7 +12,12 @@
12
12
  `siteAuthor`: the site's own author on a page about nobody in particular, the
13
13
  writer on a post, the archive's user on an author archive. Identity comes
14
14
  from a user profile, so a name that answers to no account here has no Person
15
- at all, and the author and publisher references go with it.
15
+ at all, and the author reference goes with it.
16
+
17
+ Who publishes the site follows the Site author setting (TASK-192). A site
18
+ whose author is a user is published by that user's Person and is about
19
+ them, on every page. A site with several authors is published by an
20
+ Organization named for the site and is about nobody.
16
21
 
17
22
  How it is printed: every value goes through `dump`, which is JSON.stringify,
18
23
  with every `<` escaped to its `\u003C` form so nothing in a title or a
@@ -34,6 +39,10 @@
34
39
  {#- What the author, publisher and mainEntity members hold: a reference to the
35
40
  Person rather than a second copy of them. -#}
36
41
  {% set person = { "@id": personId } if personId else "" %}
42
+ {#- Who publishes the site and everything on it: the site author, else the
43
+ site itself. -#}
44
+ {% set soloId = (soloAuthor.url | absoluteUrl) + "#person" if soloAuthor.url else "" %}
45
+ {% set publisher = { "@id": soloId or home + "#organization" } %}
37
46
  {#- `sameAs` is everywhere else this person is: the profile links they listed,
38
47
  and their actor id, which asserts that the schema.org Person and the
39
48
  fediverse actor are one identity — decision-14 makes their archive URL the
@@ -43,6 +52,14 @@
43
52
  {% if personUrl %}{% set _ = sameAs.push(personUrl) %}{% endif %}
44
53
  {% set address = { "@type": "PostalAddress", "addressLocality": siteAuthor.location } if siteAuthor.location else "" %}
45
54
  {% set entryType = "BlogPosting" if type == "post" else "Article" %}
55
+ {#- A post with no title is headed by the words its <title> names it by,
56
+ within the 110 characters Google reads, cut where a word ends (TASK-201).
57
+ Its picture is its own, else the site's avatar, else its author's photo,
58
+ else the site icon: the original upload rather than a derived icon, which
59
+ at 180 pixels is too small for an article image. A page keeps its title
60
+ and its own picture. -#}
61
+ {% set headline = title or (label | truncate(109, false, "…") if type == "post" else "") %}
62
+ {% set entryImage = metaImage or (siteAuthor.avatar or site.icon if type == "post" else "") %}
46
63
  {% set nodes = [] %}
47
64
  {% set website %}
48
65
  {
@@ -63,12 +80,20 @@
63
80
  },
64
81
  "query-input": "required name=search_term_string"
65
82
  }) }}
66
- {{- member("publisher", person) }}
67
- {#- What the site is about, on the homepage of a solo author blog
68
- (TASK-180): the site's author, and nobody on any other site. #}
69
- {{- member("about", { "@id": (soloAuthor.url | absoluteUrl) + "#person" } if atRoot and soloAuthor.url else "") }}
83
+ {{- member("publisher", publisher) }}
84
+ {{- member("about", { "@id": soloId } if soloId else "") }}
70
85
  }{% endset %}
71
86
  {% set _ = nodes.push(website) %}
87
+ {% if not soloId %}
88
+ {% set organization %}
89
+ {
90
+ "@type": "Organization"
91
+ {{- member("@id", publisher["@id"]) }}
92
+ {{- member("name", site.title) }}
93
+ {{- member("url", home) }}
94
+ }{% endset %}
95
+ {% set _ = nodes.push(organization) %}
96
+ {% endif %}
72
97
  {% if personId %}
73
98
  {% set profile %}
74
99
  {
@@ -98,15 +123,15 @@
98
123
  {% set entry %}
99
124
  {
100
125
  "@type": {{ entryType | dump | safe }}
101
- {{- member("headline", title) }}
126
+ {{- member("headline", headline) }}
102
127
  {{- member("url", metaUrl) }}
103
128
  {{- member("mainEntityOfPage", metaUrl) }}
104
129
  {{- member("datePublished", date | date("iso") if date else "") }}
105
130
  {{- member("dateModified", (updated or date) | date("iso") if (updated or date) else "") }}
106
131
  {{- member("description", metaDescription) }}
107
- {{- member("image", metaImage | absoluteUrl if metaImage else "") }}
132
+ {{- member("image", entryImage | absoluteUrl if entryImage else "") }}
108
133
  {{- member("author", person) }}
109
- {{- member("publisher", person) }}
134
+ {{- member("publisher", publisher) }}
110
135
  }{% endset %}
111
136
  {% set _ = nodes.push(entry) %}
112
137
  {% endif %}
@@ -2083,6 +2083,10 @@
2083
2083
  visibility: visible;
2084
2084
  }
2085
2085
 
2086
+ .absolute {
2087
+ position: absolute;
2088
+ }
2089
+
2086
2090
  .fixed {
2087
2091
  position: fixed;
2088
2092
  }