@geekity/cms 0.13.0 → 0.15.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 +181 -57
- package/admin/pages/documents/editor.njk +82 -0
- package/admin/pages/media/library.njk +4 -3
- package/admin/pages/settings/general.njk +51 -6
- package/admin/static/admin.css +33 -0
- package/dist/admin/documents.d.ts +5 -0
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +63 -6
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/enclosure-field.d.ts +91 -0
- package/dist/admin/enclosure-field.d.ts.map +1 -0
- package/dist/admin/enclosure-field.js +282 -0
- package/dist/admin/enclosure-field.js.map +1 -0
- package/dist/admin/federation.js +2 -2
- package/dist/admin/federation.js.map +1 -1
- package/dist/admin/headers.d.ts +4 -1
- package/dist/admin/headers.d.ts.map +1 -1
- package/dist/admin/headers.js +9 -4
- package/dist/admin/headers.js.map +1 -1
- package/dist/admin/media.d.ts +7 -2
- package/dist/admin/media.d.ts.map +1 -1
- package/dist/admin/media.js +4 -2
- package/dist/admin/media.js.map +1 -1
- package/dist/admin/settings-general.d.ts.map +1 -1
- package/dist/admin/settings-general.js +63 -4
- package/dist/admin/settings-general.js.map +1 -1
- package/dist/admin/settings-page.d.ts.map +1 -1
- package/dist/admin/settings-page.js +1 -2
- package/dist/admin/settings-page.js.map +1 -1
- package/dist/admin/settings.d.ts +37 -9
- package/dist/admin/settings.d.ts.map +1 -1
- package/dist/admin/settings.js +93 -11
- package/dist/admin/settings.js.map +1 -1
- package/dist/admin/uploads.d.ts +7 -2
- package/dist/admin/uploads.d.ts.map +1 -1
- package/dist/admin/uploads.js +23 -5
- package/dist/admin/uploads.js.map +1 -1
- package/dist/config.d.ts +21 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +11 -7
- package/dist/config.js.map +1 -1
- package/dist/content/enclosure.d.ts +69 -0
- package/dist/content/enclosure.d.ts.map +1 -0
- package/dist/content/enclosure.js +165 -0
- package/dist/content/enclosure.js.map +1 -0
- package/dist/content/index.d.ts +3 -1
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +1 -0
- package/dist/content/index.js.map +1 -1
- package/dist/content/media.d.ts +15 -2
- package/dist/content/media.d.ts.map +1 -1
- package/dist/content/media.js +92 -9
- package/dist/content/media.js.map +1 -1
- package/dist/content/pinned.d.ts +26 -0
- package/dist/content/pinned.d.ts.map +1 -0
- package/dist/content/pinned.js +42 -0
- package/dist/content/pinned.js.map +1 -0
- package/dist/content/store.d.ts +7 -0
- package/dist/content/store.d.ts.map +1 -1
- package/dist/content/store.js +20 -0
- package/dist/content/store.js.map +1 -1
- package/dist/env.d.ts +7 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/federation/actor.d.ts +15 -0
- package/dist/federation/actor.d.ts.map +1 -1
- package/dist/federation/actor.js +94 -3
- package/dist/federation/actor.js.map +1 -1
- package/dist/federation/article.d.ts +13 -1
- package/dist/federation/article.d.ts.map +1 -1
- package/dist/federation/article.js +62 -7
- package/dist/federation/article.js.map +1 -1
- package/dist/federation/delivery.d.ts.map +1 -1
- package/dist/federation/delivery.js +36 -4
- package/dist/federation/delivery.js.map +1 -1
- package/dist/federation/federation.d.ts.map +1 -1
- package/dist/federation/federation.js +24 -2
- package/dist/federation/federation.js.map +1 -1
- package/dist/federation/mount.js +2 -2
- package/dist/federation/mount.js.map +1 -1
- package/dist/federation/paths.d.ts +30 -0
- package/dist/federation/paths.d.ts.map +1 -1
- package/dist/federation/paths.js +36 -0
- package/dist/federation/paths.js.map +1 -1
- package/dist/images/icons.d.ts +5 -0
- package/dist/images/icons.d.ts.map +1 -1
- package/dist/images/icons.js +13 -8
- package/dist/images/icons.js.map +1 -1
- package/dist/images/paths.d.ts +1 -1
- package/dist/images/paths.d.ts.map +1 -1
- package/dist/images/paths.js.map +1 -1
- package/dist/images/variants.d.ts +11 -0
- package/dist/images/variants.d.ts.map +1 -1
- package/dist/images/variants.js +21 -0
- package/dist/images/variants.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/indieauth/identity.d.ts +3 -3
- package/dist/indieauth/identity.d.ts.map +1 -1
- package/dist/indieauth/identity.js +6 -7
- package/dist/indieauth/identity.js.map +1 -1
- package/dist/web/admin-bar.d.ts +3 -1
- package/dist/web/admin-bar.d.ts.map +1 -1
- package/dist/web/admin-bar.js +5 -1
- package/dist/web/admin-bar.js.map +1 -1
- package/dist/web/assets.d.ts +14 -0
- package/dist/web/assets.d.ts.map +1 -1
- package/dist/web/assets.js +56 -1
- package/dist/web/assets.js.map +1 -1
- package/dist/web/authors.d.ts +19 -0
- package/dist/web/authors.d.ts.map +1 -1
- package/dist/web/authors.js +25 -0
- package/dist/web/authors.js.map +1 -1
- package/dist/web/context.d.ts +26 -0
- package/dist/web/context.d.ts.map +1 -1
- package/dist/web/context.js +15 -0
- package/dist/web/context.js.map +1 -1
- package/dist/web/feed-atom.d.ts.map +1 -1
- package/dist/web/feed-atom.js +22 -1
- package/dist/web/feed-atom.js.map +1 -1
- package/dist/web/feed-item.d.ts +34 -6
- package/dist/web/feed-item.d.ts.map +1 -1
- package/dist/web/feed-item.js +31 -7
- package/dist/web/feed-item.js.map +1 -1
- package/dist/web/feed-json.d.ts +15 -2
- package/dist/web/feed-json.d.ts.map +1 -1
- package/dist/web/feed-json.js +17 -1
- package/dist/web/feed-json.js.map +1 -1
- package/dist/web/feed-rss.d.ts.map +1 -1
- package/dist/web/feed-rss.js +60 -3
- package/dist/web/feed-rss.js.map +1 -1
- package/dist/web/feed-source.d.ts +3 -0
- package/dist/web/feed-source.d.ts.map +1 -1
- package/dist/web/feed-source.js.map +1 -1
- package/dist/web/feed-xml.d.ts +7 -1
- package/dist/web/feed-xml.d.ts.map +1 -1
- package/dist/web/feed-xml.js +8 -2
- package/dist/web/feed-xml.js.map +1 -1
- package/dist/web/feeds.d.ts +1 -1
- package/dist/web/feeds.d.ts.map +1 -1
- package/dist/web/feeds.js +13 -2
- package/dist/web/feeds.js.map +1 -1
- package/dist/web/index.d.ts +5 -2
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +3 -1
- package/dist/web/index.js.map +1 -1
- package/dist/web/license.d.ts +94 -0
- package/dist/web/license.d.ts.map +1 -0
- package/dist/web/license.js +116 -0
- package/dist/web/license.js.map +1 -0
- package/dist/web/oembed.d.ts +104 -0
- package/dist/web/oembed.d.ts.map +1 -0
- package/dist/web/oembed.js +289 -0
- package/dist/web/oembed.js.map +1 -0
- package/dist/web/opensearch.d.ts +35 -0
- package/dist/web/opensearch.d.ts.map +1 -0
- package/dist/web/opensearch.js +65 -0
- package/dist/web/opensearch.js.map +1 -0
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +16 -8
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +82 -6
- package/dist/web/routes.js.map +1 -1
- package/dist/web/share-image.d.ts +7 -7
- package/dist/web/share-image.d.ts.map +1 -1
- package/dist/web/share-image.js +8 -7
- package/dist/web/share-image.js.map +1 -1
- package/dist/web/templates.d.ts.map +1 -1
- package/dist/web/templates.js +5 -0
- package/dist/web/templates.js.map +1 -1
- package/package.json +2 -1
- package/templates/site/content/_data/site.json +0 -1
- package/themes/default/README.md +142 -48
- package/themes/default/layouts/base.njk +25 -6
- package/themes/default/layouts/front-page.njk +1 -0
- package/themes/default/layouts/home.njk +1 -0
- package/themes/default/layouts/post.njk +4 -0
- package/themes/default/partials/bio.njk +7 -0
- package/themes/default/partials/jsonld.njk +30 -7
- package/themes/default/partials/recording.njk +41 -0
- package/themes/default/src/style.css +16 -0
- package/themes/default/static/style.css +29 -0
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
* with a picture of their own, so the picture a site shows the fediverse is a
|
|
7
7
|
* user's, edited on the users screen beside the rest of their profile.
|
|
8
8
|
*/
|
|
9
|
+
import { iconSetting, siteIcons } from '../images/icons.js';
|
|
10
|
+
import { userForAuthor } from '../web/authors.js';
|
|
11
|
+
import { CREATIVE_COMMONS_LICENSES } from '../web/license.js';
|
|
12
|
+
import { listUsers } from './accounts.js';
|
|
9
13
|
import { bodyField, settingsPagePath } from './settings-page.js';
|
|
10
|
-
import { effectiveBaseUrl, SETTINGS_FIELDS } from './settings.js';
|
|
14
|
+
import { effectiveBaseUrl, readSiteJson, SETTINGS_FIELDS } from './settings.js';
|
|
11
15
|
import { ADMIN_TEMPLATES } from './templates.js';
|
|
12
16
|
/** The General settings page. */
|
|
13
17
|
export const GENERAL_SETTINGS = {
|
|
@@ -15,15 +19,52 @@ export const GENERAL_SETTINGS = {
|
|
|
15
19
|
label: 'General',
|
|
16
20
|
path: settingsPagePath('general'),
|
|
17
21
|
template: ADMIN_TEMPLATES.settingsGeneral,
|
|
18
|
-
fields: [
|
|
22
|
+
fields: [
|
|
23
|
+
'title',
|
|
24
|
+
'tagline',
|
|
25
|
+
'author',
|
|
26
|
+
'baseUrl',
|
|
27
|
+
'timezone',
|
|
28
|
+
'language',
|
|
29
|
+
'locale',
|
|
30
|
+
'icon',
|
|
31
|
+
'license',
|
|
32
|
+
'licenseUrl',
|
|
33
|
+
'licenseName',
|
|
34
|
+
],
|
|
19
35
|
// The base URL field shows the one in effect rather than the one the file
|
|
20
36
|
// happens to hold: a site.json with no `url` at all would otherwise render an
|
|
21
37
|
// empty field that the validator refuses the moment anything is saved.
|
|
22
|
-
|
|
23
|
-
|
|
38
|
+
//
|
|
39
|
+
// The author is shown as the user it resolves to, so a site.json written
|
|
40
|
+
// before the select, holding a display name, selects that user and the
|
|
41
|
+
// first save writes their username (TASK-192). A name nobody answers to
|
|
42
|
+
// selects Several authors.
|
|
43
|
+
shown: (config, settings) => ({
|
|
44
|
+
...settings,
|
|
45
|
+
baseUrl: effectiveBaseUrl(config, settings),
|
|
46
|
+
author: siteAuthorUsername(config, settings.author),
|
|
47
|
+
icon: iconInEffect(config, settings) ?? '',
|
|
48
|
+
}),
|
|
49
|
+
panels: (c, settings) => ({
|
|
50
|
+
...baseUrlPanel(c.var.config, settings),
|
|
51
|
+
...iconPanel(c.var.config, settings),
|
|
52
|
+
licenseChoices: Object.entries(CREATIVE_COMMONS_LICENSES).map(([key, license]) => ({
|
|
53
|
+
key,
|
|
54
|
+
name: `${license.name}, ${license.title}`,
|
|
55
|
+
})),
|
|
56
|
+
authorChoices: listUsers(c.var.config.dataDir).map((user) => ({
|
|
57
|
+
username: user.username,
|
|
58
|
+
name: user.profile?.displayName ?? user.username,
|
|
59
|
+
})),
|
|
60
|
+
}),
|
|
24
61
|
// A field the form rendered read-only is not submitted, so an overridden base
|
|
25
62
|
// URL keeps the value it had rather than being cleared by a save.
|
|
63
|
+
//
|
|
64
|
+
// The author is whoever the submitted username is, and nobody when it is
|
|
65
|
+
// not a user, so the file only ever holds a username or no author at all.
|
|
26
66
|
reads: ({ c, body, current }) => ({
|
|
67
|
+
author: siteAuthorUsername(c.var.config, bodyField(body[SETTINGS_FIELDS.author])),
|
|
27
68
|
baseUrl: c.var.config.baseUrlSource === 'default'
|
|
28
69
|
? bodyField(body[SETTINGS_FIELDS.baseUrl])
|
|
29
70
|
: current.baseUrl === ''
|
|
@@ -31,6 +72,24 @@ export const GENERAL_SETTINGS = {
|
|
|
31
72
|
: current.baseUrl,
|
|
32
73
|
}),
|
|
33
74
|
};
|
|
75
|
+
/** The username a stored or submitted author names, or empty for several authors. */
|
|
76
|
+
function siteAuthorUsername(config, author) {
|
|
77
|
+
return userForAuthor(listUsers(config.dataDir), author)?.username ?? '';
|
|
78
|
+
}
|
|
79
|
+
function iconInEffect(config, settings) {
|
|
80
|
+
return iconSetting({ icon: settings.icon, avatar: readSiteJson(config.contentDir)['avatar'] });
|
|
81
|
+
}
|
|
82
|
+
function iconPanel(config, settings) {
|
|
83
|
+
const inEffect = iconInEffect(config, settings);
|
|
84
|
+
const preview = siteIcons(config, inEffect).find((icon) => icon.rel === 'apple-touch-icon');
|
|
85
|
+
return {
|
|
86
|
+
iconInEffect: inEffect ?? '',
|
|
87
|
+
iconPreview: preview?.href ?? '',
|
|
88
|
+
iconFromAvatar: settings.icon === '' && inEffect !== undefined,
|
|
89
|
+
iconUnderived: inEffect !== undefined && preview === undefined,
|
|
90
|
+
imageOptimization: config.imageOptimization,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
34
93
|
/** What the page says about the base URL: the one in effect, and why it is. */
|
|
35
94
|
function baseUrlPanel(config, settings) {
|
|
36
95
|
const overridden = config.baseUrlSource !== 'default';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-general.js","sourceRoot":"","sources":["../../src/admin/settings-general.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEjE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"settings-general.js","sourceRoot":"","sources":["../../src/admin/settings-general.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-page.d.ts","sourceRoot":"","sources":["../../src/admin/settings-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAWlD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE/E,qEAAqE;AACrE,MAAM,WAAW,oBAAoB;IACnC,oFAAoF;IACpF,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,iEAAiE;AACjE,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpD,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IACjC;;;OAGG;IACH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,KAAK,YAAY,CAAC;IACzE,kFAAkF;IAClF,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrF;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE;QAChB,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACvB,IAAI,EAAE,aAAa,CAAC;QACpB,OAAO,EAAE,YAAY,CAAC;KACvB,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC5B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,CACN,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,EACtB,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,YAAY,KAChB,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC9B;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;CAC5E;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,EACrB,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,oBAAoB,GAC5B,IAAI,
|
|
1
|
+
{"version":3,"file":"settings-page.d.ts","sourceRoot":"","sources":["../../src/admin/settings-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAWlD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE/E,qEAAqE;AACrE,MAAM,WAAW,oBAAoB;IACnC,oFAAoF;IACpF,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,iEAAiE;AACjE,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpD,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IACjC;;;OAGG;IACH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,KAAK,YAAY,CAAC;IACzE,kFAAkF;IAClF,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrF;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE;QAChB,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACvB,IAAI,EAAE,aAAa,CAAC;QACpB,OAAO,EAAE,YAAY,CAAC;KACvB,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC5B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,CACN,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,EACtB,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,YAAY,KAChB,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC9B;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;CAC5E;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,EACrB,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,oBAAoB,GAC5B,IAAI,CA2CN;AAED,uDAAuD;AACvD,wBAAgB,cAAc,CAC5B,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,EACtB,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,YAAY,GACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiBzB;AA2BD,qFAAqF;AACrF,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,GAAG,MAAM,CAMxE"}
|
|
@@ -45,10 +45,9 @@ export function mountSettingsPage(app, page, options) {
|
|
|
45
45
|
const body = await c.req.parseBody();
|
|
46
46
|
const stored = readSiteSettings(c.var.config.contentDir);
|
|
47
47
|
const submitted = pageForm(c, page, body, stored);
|
|
48
|
-
// The themes directory goes in because one check needs the file system:
|
|
49
|
-
// whether the name a page submitted is a theme that is actually there.
|
|
50
48
|
const problems = settingsProblems(submitted, page.fields, {
|
|
51
49
|
themesDir: c.var.config.themesDir,
|
|
50
|
+
contentDir: c.var.config.contentDir,
|
|
52
51
|
});
|
|
53
52
|
if (Object.keys(problems).length > 0) {
|
|
54
53
|
c.status(400);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-page.js","sourceRoot":"","sources":["../../src/admin/settings-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAQH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AA2EvB;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,IAAI,KAAK,EAAE,CAAC;AAC3E,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAqB,EACrB,IAAkB,EAClB,OAA6B;IAE7B,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAE3B,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CACvB,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAC7F,CAAC;IAEF,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC9B,MAAM,IAAI,GAAkB,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACpD,MAAM,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAElD,
|
|
1
|
+
{"version":3,"file":"settings-page.js","sourceRoot":"","sources":["../../src/admin/settings-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAQH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AA2EvB;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,IAAI,KAAK,EAAE,CAAC;AAC3E,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAqB,EACrB,IAAkB,EAClB,OAA6B;IAE7B,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAE3B,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CACvB,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAC7F,CAAC;IAEF,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC9B,MAAM,IAAI,GAAkB,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACpD,MAAM,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAElD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE;YACxD,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS;YACjC,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU;SACpC,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,OAAO,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE;gBAC9B,GAAG,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC;gBAClC,IAAI,EAAE,SAAS;gBACf,QAAQ;gBACR,WAAW,EAAE,IAAI;aAClB,CAAC,CAAC;QACL,CAAC;QAED,uEAAuE;QACvE,2EAA2E;QAC3E,wEAAwE;QACxE,0EAA0E;QAC1E,2EAA2E;QAC3E,YAAY;QACZ,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC;YACxC,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU;YACnC,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC;SACjF,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QACnF,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,WAAW,CAAC,IAAI,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;QAClE,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,cAAc,CAC5B,CAAsB,EACtB,IAAkB,EAClB,QAAsB;IAEtB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAEvF,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,UAAU;QACnC,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,WAAW,EAAE,IAAI,CAAC,IAAI;QACtB,aAAa,EAAE,WAAW,CAAC,IAAI,CAAC;QAChC,MAAM,EAAE,eAAe;QACvB,IAAI,EAAE,gBAAgB,CAAC,KAAK,CAAC;QAC7B,QAAQ,EAAE,EAAE;QACZ,0EAA0E;QAC1E,0EAA0E;QAC1E,0CAA0C;QAC1C,WAAW,EAAE,KAAK;QAClB,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC;KAC9B,CAAC;AACJ,CAAC;AAED,oEAAoE;AACpE,SAAS,WAAW,CAAC,IAAkB;IACrC,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC;AACpC,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,QAAQ,CACf,CAAsB,EACtB,IAAkB,EAClB,IAAmB,EACnB,OAAqB;IAErB,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACvC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM;QAAE,IAAI,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpF,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAAkC;IAC9D,MAAM,KAAK,GAAG,MAAM,EAAE,UAAU,CAAC,MAAM,IAAI,CAAC,CAAC;IAC7C,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3B,OAAO,KAAK,KAAK,CAAC;QAChB,CAAC,CAAC,8BAA8B;QAChC,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC;AACpD,CAAC"}
|
package/dist/admin/settings.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { RetentionPolicy } from '../privacy/policy.ts';
|
|
|
2
2
|
import type { ResolvedConfig } from '../config.ts';
|
|
3
3
|
import type { MailProviderName } from '../mail/provider.ts';
|
|
4
4
|
import type { UpdatePeriod } from '../web/feed-source.ts';
|
|
5
|
+
import type { CreativeCommonsKey } from '../web/license.ts';
|
|
5
6
|
import type { AiCrawlerPolicy, RobotsPolicy } from '../web/robots.ts';
|
|
6
7
|
import type { NavigationMenus } from '../web/navigation.ts';
|
|
7
8
|
import type { TaxonomyBases, TaxonomyRedirect } from '../web/taxonomy.ts';
|
|
@@ -90,15 +91,18 @@ export interface SiteSettings {
|
|
|
90
91
|
* settings screen refuses one without it, exactly as WordPress does.
|
|
91
92
|
*/
|
|
92
93
|
postsPage: string;
|
|
93
|
-
/** Site author, used as the feed author. May be empty. */
|
|
94
|
-
author: string;
|
|
95
94
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* `rel="me"` links,
|
|
99
|
-
*
|
|
95
|
+
* Who the site is: one user's username, or empty for a site with several
|
|
96
|
+
* authors (TASK-192). A username makes it that user's blog: the homepage
|
|
97
|
+
* carries their bio card and their `rel="me"` links, it and their archive
|
|
98
|
+
* claim each other, and the root is their IndieAuth identity (decision-23).
|
|
99
|
+
*
|
|
100
|
+
* A file written before the Site author select may hold a display name or a
|
|
101
|
+
* name nobody has. It is read as stored and resolved where it is used, by
|
|
102
|
+
* `userForAuthor`, so a display name still names its user and anything else
|
|
103
|
+
* names nobody; the General page writes the username at its next save.
|
|
100
104
|
*/
|
|
101
|
-
|
|
105
|
+
author: string;
|
|
102
106
|
/**
|
|
103
107
|
* The theme the site renders through: the name of one directory under the
|
|
104
108
|
* configured themes directory, or empty for the theme the package ships
|
|
@@ -111,6 +115,24 @@ export interface SiteSettings {
|
|
|
111
115
|
* site, so a hand-edited file is a warning in the log rather than a 500.
|
|
112
116
|
*/
|
|
113
117
|
theme: string;
|
|
118
|
+
/**
|
|
119
|
+
* The upload the site's icons are derived from, as a path such as
|
|
120
|
+
* `/uploads/2026/10/icon.png`, or empty for none. Read from and written
|
|
121
|
+
* to the `icon` key of `site.json` only.
|
|
122
|
+
*/
|
|
123
|
+
icon: string;
|
|
124
|
+
/**
|
|
125
|
+
* What readers may do with the site's posts: empty for no
|
|
126
|
+
* license, which is all rights reserved, a Creative Commons key, or
|
|
127
|
+
* `custom` for the URL and name beside it. `site.json` writes a key, or a
|
|
128
|
+
* custom license's URL, under `license`, so the file says it the way a
|
|
129
|
+
* post's front matter does.
|
|
130
|
+
*/
|
|
131
|
+
license: LicenseChoice;
|
|
132
|
+
/** A custom license's terms, as an absolute URL. Empty unless `license` is `custom`. */
|
|
133
|
+
licenseUrl: string;
|
|
134
|
+
/** A custom license's name. Empty unless `license` is `custom`. */
|
|
135
|
+
licenseName: string;
|
|
114
136
|
/**
|
|
115
137
|
* The first URL segment the tag archives live under, `tag` by default: one
|
|
116
138
|
* URL-safe path segment, no slashes. WordPress's own base, so a site
|
|
@@ -316,6 +338,7 @@ export interface SiteSettings {
|
|
|
316
338
|
}
|
|
317
339
|
/** What a site says about one Content-Signal: yes, no, or nothing. */
|
|
318
340
|
export type ContentSignalChoice = '' | 'yes' | 'no';
|
|
341
|
+
export type LicenseChoice = '' | CreativeCommonsKey | 'custom';
|
|
319
342
|
/** What the settings say the robots file should carry. */
|
|
320
343
|
export declare function robotsPolicyOf(settings: SiteSettings): RobotsPolicy;
|
|
321
344
|
/**
|
|
@@ -354,8 +377,11 @@ export declare const SETTINGS_FIELDS: {
|
|
|
354
377
|
readonly homepage: 'homepage';
|
|
355
378
|
readonly postsPage: 'posts_page';
|
|
356
379
|
readonly author: 'author';
|
|
357
|
-
readonly soloAuthor: 'solo_author';
|
|
358
380
|
readonly theme: 'theme';
|
|
381
|
+
readonly icon: 'icon';
|
|
382
|
+
readonly license: 'license';
|
|
383
|
+
readonly licenseUrl: 'license_url';
|
|
384
|
+
readonly licenseName: 'license_name';
|
|
359
385
|
readonly tagBase: 'tag_base';
|
|
360
386
|
readonly categoryBase: 'category_base';
|
|
361
387
|
readonly comments: 'comments';
|
|
@@ -404,6 +430,7 @@ export type SettingsProblems = Partial<Record<SettingsField, string>>;
|
|
|
404
430
|
* with the settings screen there to put it right.
|
|
405
431
|
*/
|
|
406
432
|
export declare function readSiteSettings(contentDir: string): SiteSettings;
|
|
433
|
+
export declare function readSiteJson(contentDir: string): Record<string, unknown>;
|
|
407
434
|
/**
|
|
408
435
|
* `content/_data/site.json` as the settings it names, defaults filled in.
|
|
409
436
|
*
|
|
@@ -423,7 +450,7 @@ export declare function taxonomyBasesFromSettings(settings: SiteSettings): Taxon
|
|
|
423
450
|
*
|
|
424
451
|
* Every key the settings model is written whether or not it has a value, so
|
|
425
452
|
* the file's shape is stable and an Eleventy template may reference
|
|
426
|
-
* `site.
|
|
453
|
+
* `site.tagline` without guarding it. Every other key the file already had is
|
|
427
454
|
* kept: a site may put anything in there and reach it from its templates, and
|
|
428
455
|
* the settings form is not going to be the thing that throws it away.
|
|
429
456
|
*
|
|
@@ -506,6 +533,7 @@ export declare function effectiveBaseUrl(config: Pick<ResolvedConfig, 'baseUrl'
|
|
|
506
533
|
export interface SettingsContext {
|
|
507
534
|
/** Where the site's themes are: {@link ResolvedConfig.themesDir}. */
|
|
508
535
|
themesDir?: string | undefined;
|
|
536
|
+
contentDir?: string | undefined;
|
|
509
537
|
}
|
|
510
538
|
/** Every field of the settings, in the order the form fields name them. */
|
|
511
539
|
export declare const SETTINGS_FIELD_NAMES: readonly SettingsField[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/admin/settings.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/admin/settings.ts"],"names":[],"mappings":"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"}
|
package/dist/admin/settings.js
CHANGED
|
@@ -2,11 +2,14 @@ import { statSync } from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { DEFAULT_COMMENTS_CLOSE_AFTER_DAYS } from '../comments/policy.js';
|
|
4
4
|
import { readFileIfPresentSync, updateFileAtomically, writeFileAtomicallySync, } from '../files/atomic.js';
|
|
5
|
+
import { parseIconSetting } from '../images/icons.js';
|
|
6
|
+
import { sourceFile } from '../images/paths.js';
|
|
5
7
|
import { MAIL_PROVIDERS } from '../mail/provider.js';
|
|
6
8
|
import { SITE_DATA_FILE } from '../web/context.js';
|
|
7
9
|
import { DEFAULT_FEED_CADENCE, isUpdatePeriod, UPDATE_PERIODS } from '../web/feed-source.js';
|
|
8
10
|
import { DEFAULT_NOTIFY_SERVER } from '../web/feeds.js';
|
|
9
11
|
import { generateIndexNowKey, isIndexNowKey } from '../web/indexnow.js';
|
|
12
|
+
import { classifyLicense, isCreativeCommonsKey, isLicenseUrl, NO_LICENSE } from '../web/license.js';
|
|
10
13
|
import { canonicalLocale } from '../web/locale.js';
|
|
11
14
|
import { DEFAULT_MENU_NAME, menuItemsFromText, menusOf } from '../web/navigation.js';
|
|
12
15
|
import { AI_CRAWLER_POLICIES, robotsRuleLines, robotsRuleProblem } from '../web/robots.js';
|
|
@@ -82,8 +85,11 @@ export const DEFAULT_SITE_SETTINGS = {
|
|
|
82
85
|
homepage: '',
|
|
83
86
|
postsPage: '',
|
|
84
87
|
author: '',
|
|
85
|
-
soloAuthor: false,
|
|
86
88
|
theme: '',
|
|
89
|
+
icon: '',
|
|
90
|
+
license: '',
|
|
91
|
+
licenseUrl: '',
|
|
92
|
+
licenseName: '',
|
|
87
93
|
tagBase: DEFAULT_TAXONOMY_BASES.tag,
|
|
88
94
|
categoryBase: DEFAULT_TAXONOMY_BASES.category,
|
|
89
95
|
comments: true,
|
|
@@ -131,8 +137,11 @@ export const SETTINGS_FIELDS = {
|
|
|
131
137
|
homepage: 'homepage',
|
|
132
138
|
postsPage: 'posts_page',
|
|
133
139
|
author: 'author',
|
|
134
|
-
soloAuthor: 'solo_author',
|
|
135
140
|
theme: 'theme',
|
|
141
|
+
icon: 'icon',
|
|
142
|
+
license: 'license',
|
|
143
|
+
licenseUrl: 'license_url',
|
|
144
|
+
licenseName: 'license_name',
|
|
136
145
|
tagBase: 'tag_base',
|
|
137
146
|
categoryBase: 'category_base',
|
|
138
147
|
comments: 'comments',
|
|
@@ -177,7 +186,10 @@ export const SETTINGS_FIELDS = {
|
|
|
177
186
|
* with the settings screen there to put it right.
|
|
178
187
|
*/
|
|
179
188
|
export function readSiteSettings(contentDir) {
|
|
180
|
-
return settingsFromSiteJson(
|
|
189
|
+
return settingsFromSiteJson(readSiteJson(contentDir));
|
|
190
|
+
}
|
|
191
|
+
export function readSiteJson(contentDir) {
|
|
192
|
+
return readSiteJsonSync(siteDataPath(contentDir));
|
|
181
193
|
}
|
|
182
194
|
/**
|
|
183
195
|
* `content/_data/site.json` as the settings it names, defaults filled in.
|
|
@@ -208,6 +220,8 @@ export function settingsFromSiteJson(file) {
|
|
|
208
220
|
// Absent is the ordinary state of this one: a site on the packaged theme
|
|
209
221
|
// has never written the key, so anything but a string is that site.
|
|
210
222
|
...(typeof file['theme'] === 'string' ? { theme: file['theme'] } : {}),
|
|
223
|
+
...(typeof file['icon'] === 'string' ? { icon: file['icon'].trim() } : {}),
|
|
224
|
+
...licenseFromSiteJson(file),
|
|
211
225
|
// Absent is the ordinary state of these two: a site showing its latest
|
|
212
226
|
// posts writes neither key, so anything but a string is read as none.
|
|
213
227
|
...(typeof file['homepage'] === 'string' ? { homepage: file['homepage'] } : {}),
|
|
@@ -256,7 +270,6 @@ export function settingsFromSiteJson(file) {
|
|
|
256
270
|
robotsRules: robotsRuleLines(file['robotsRules'].filter((entry) => typeof entry === 'string')),
|
|
257
271
|
}
|
|
258
272
|
: {}),
|
|
259
|
-
...(typeof file['soloAuthor'] === 'boolean' ? { soloAuthor: file['soloAuthor'] } : {}),
|
|
260
273
|
...(typeof file['llmsTxt'] === 'boolean' ? { llmsTxt: file['llmsTxt'] } : {}),
|
|
261
274
|
...(typeof file['indexNow'] === 'boolean' ? { indexNow: file['indexNow'] } : {}),
|
|
262
275
|
// A key IndexNow would refuse is no key: the site then has none to serve
|
|
@@ -326,7 +339,7 @@ export function taxonomyBasesFromSettings(settings) {
|
|
|
326
339
|
*
|
|
327
340
|
* Every key the settings model is written whether or not it has a value, so
|
|
328
341
|
* the file's shape is stable and an Eleventy template may reference
|
|
329
|
-
* `site.
|
|
342
|
+
* `site.tagline` without guarding it. Every other key the file already had is
|
|
330
343
|
* kept: a site may put anything in there and reach it from its templates, and
|
|
331
344
|
* the settings form is not going to be the thing that throws it away.
|
|
332
345
|
*
|
|
@@ -341,8 +354,6 @@ export function siteJsonFor(settings, existing = {}) {
|
|
|
341
354
|
title: settings.title,
|
|
342
355
|
tagline: settings.tagline,
|
|
343
356
|
url: settings.baseUrl,
|
|
344
|
-
author: settings.author,
|
|
345
|
-
soloAuthor: settings.soloAuthor,
|
|
346
357
|
postsPerPage: settings.postsPerPage,
|
|
347
358
|
timezone: settings.timezone,
|
|
348
359
|
language: settings.language,
|
|
@@ -389,12 +400,16 @@ export function siteJsonFor(settings, existing = {}) {
|
|
|
389
400
|
// nothing reads it from is the kind of thing somebody edits for an hour
|
|
390
401
|
// before noticing.
|
|
391
402
|
delete file['navigation'];
|
|
403
|
+
// The Solo author switch, which the author setting now says on its own
|
|
404
|
+
// (TASK-192): a username is a solo author site and no author is not.
|
|
405
|
+
delete file['soloAuthor'];
|
|
392
406
|
// `theme` is absent for a site on the packaged theme, on the same rule and
|
|
393
407
|
// for the same reason as the two above: running what the package ships is
|
|
394
408
|
// not a choice a site should have to write down, and a `theme` of `""` would
|
|
395
409
|
// be a name no directory has. `locale` too: a site whose dates follow its
|
|
396
410
|
// language has made no choice to write down.
|
|
397
|
-
|
|
411
|
+
// `author` too: a site with several authors names nobody (TASK-192).
|
|
412
|
+
for (const key of ['homepage', 'postsPage', 'theme', 'locale', 'author', 'icon']) {
|
|
398
413
|
if (settings[key] === '')
|
|
399
414
|
delete file[key];
|
|
400
415
|
else
|
|
@@ -408,6 +423,15 @@ export function siteJsonFor(settings, existing = {}) {
|
|
|
408
423
|
file['wordpressActivityPub'] = true;
|
|
409
424
|
else
|
|
410
425
|
delete file['wordpressActivityPub'];
|
|
426
|
+
delete file['licenseName'];
|
|
427
|
+
if (settings.license === '')
|
|
428
|
+
delete file['license'];
|
|
429
|
+
else if (settings.license !== 'custom')
|
|
430
|
+
file['license'] = settings.license;
|
|
431
|
+
else {
|
|
432
|
+
file['license'] = settings.licenseUrl;
|
|
433
|
+
file['licenseName'] = settings.licenseName;
|
|
434
|
+
}
|
|
411
435
|
// A site that has never turned IndexNow on has no key to write down.
|
|
412
436
|
if (settings.indexNowKey !== '')
|
|
413
437
|
file['indexNowKey'] = settings.indexNowKey;
|
|
@@ -612,6 +636,14 @@ const FIELD_CHECKS = {
|
|
|
612
636
|
const read = readTheme(path.join(context.themesDir, name));
|
|
613
637
|
return read.ok ? undefined : `There is no theme called "${name}": ${read.reason}`;
|
|
614
638
|
},
|
|
639
|
+
icon: (form, context) => iconProblem(form.icon.trim(), context),
|
|
640
|
+
license: (form) => isLicenseChoice(form.license.trim()) ? undefined : 'Choose a license from the list.',
|
|
641
|
+
licenseUrl: (form) => form.license.trim() === 'custom' && !isLicenseUrl(form.licenseUrl.trim())
|
|
642
|
+
? 'A custom license needs the URL of its terms, starting http:// or https://.'
|
|
643
|
+
: undefined,
|
|
644
|
+
licenseName: (form) => form.license.trim() === 'custom' && form.licenseName.trim() === ''
|
|
645
|
+
? 'A custom license needs a name for the footer to show.'
|
|
646
|
+
: undefined,
|
|
615
647
|
comments: () => undefined,
|
|
616
648
|
// The empty string is refused rather than read as zero, which is what
|
|
617
649
|
// `Number('')` would make it: a cleared field is a mistake, and "never close
|
|
@@ -647,7 +679,6 @@ const FIELD_CHECKS = {
|
|
|
647
679
|
contentSignalAiInput: (form) => contentSignalProblem(form.contentSignalAiInput),
|
|
648
680
|
contentSignalAiTrain: (form) => contentSignalProblem(form.contentSignalAiTrain),
|
|
649
681
|
robotsRules: (form) => robotsRuleProblem([form.robotsRules]),
|
|
650
|
-
soloAuthor: () => undefined,
|
|
651
682
|
llmsTxt: () => undefined,
|
|
652
683
|
indexNow: () => undefined,
|
|
653
684
|
mailProvider: (form) => MAIL_PROVIDERS.includes(form.mailProvider)
|
|
@@ -703,6 +734,42 @@ const FIELD_CHECKS = {
|
|
|
703
734
|
tagBase: (form) => taxonomyBaseProblems({ tag: form.tagBase, category: form.categoryBase }).tag,
|
|
704
735
|
categoryBase: (form) => taxonomyBaseProblems({ tag: form.tagBase, category: form.categoryBase }).category,
|
|
705
736
|
};
|
|
737
|
+
function isLicenseChoice(value) {
|
|
738
|
+
return value === '' || value === 'custom' || isCreativeCommonsKey(value);
|
|
739
|
+
}
|
|
740
|
+
function licenseFromSiteJson(file) {
|
|
741
|
+
const said = classifyLicense(file['license']);
|
|
742
|
+
if (said === undefined || said === NO_LICENSE)
|
|
743
|
+
return {};
|
|
744
|
+
if ('key' in said)
|
|
745
|
+
return { license: said.key, licenseUrl: '', licenseName: '' };
|
|
746
|
+
const name = typeof file['licenseName'] === 'string' ? file['licenseName'].trim() : '';
|
|
747
|
+
return { license: 'custom', licenseUrl: said.url, licenseName: name };
|
|
748
|
+
}
|
|
749
|
+
function iconProblem(icon, context) {
|
|
750
|
+
if (icon === '')
|
|
751
|
+
return undefined;
|
|
752
|
+
const parsed = parseIconSetting(icon);
|
|
753
|
+
if ('problem' in parsed) {
|
|
754
|
+
return parsed.problem === 'not-an-upload'
|
|
755
|
+
? 'The site icon has to be a file in the media library, a path such as /uploads/2026/10/icon.png.'
|
|
756
|
+
: 'The site icon has to be an image: PNG, JPEG, GIF, WebP, AVIF, TIFF or SVG.';
|
|
757
|
+
}
|
|
758
|
+
if (context.contentDir === undefined)
|
|
759
|
+
return undefined;
|
|
760
|
+
const file = sourceFile({ contentDir: context.contentDir }, parsed.source);
|
|
761
|
+
return file !== undefined && isFile(file)
|
|
762
|
+
? undefined
|
|
763
|
+
: `There is no upload at ${icon}. Upload the picture on the Media screen first.`;
|
|
764
|
+
}
|
|
765
|
+
function isFile(file) {
|
|
766
|
+
try {
|
|
767
|
+
return statSync(file).isFile();
|
|
768
|
+
}
|
|
769
|
+
catch {
|
|
770
|
+
return false;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
706
773
|
/** What is wrong with a submitted Content-Signal choice. */
|
|
707
774
|
function contentSignalProblem(value) {
|
|
708
775
|
return isContentSignalChoice(value) ? undefined : 'A content signal is yes, no, or not said.';
|
|
@@ -753,8 +820,9 @@ export function settingsFromForm(form, carried = {}) {
|
|
|
753
820
|
// the listing's own page with it rather than leave it stranded.
|
|
754
821
|
postsPage: form.homepage.trim() === '' ? '' : form.postsPage.trim(),
|
|
755
822
|
author: form.author.trim(),
|
|
756
|
-
soloAuthor: form.soloAuthor !== '',
|
|
757
823
|
theme: form.theme.trim(),
|
|
824
|
+
icon: form.icon.trim(),
|
|
825
|
+
...licenseFromForm(form),
|
|
758
826
|
tagBase: form.tagBase.trim(),
|
|
759
827
|
categoryBase: form.categoryBase.trim(),
|
|
760
828
|
// A checkbox submits nothing at all when it is clear, which is what the
|
|
@@ -805,6 +873,17 @@ export function settingsFromForm(form, carried = {}) {
|
|
|
805
873
|
wordpressActivityPub: form.wordpressActivityPub !== '',
|
|
806
874
|
};
|
|
807
875
|
}
|
|
876
|
+
function licenseFromForm(form) {
|
|
877
|
+
const license = form.license.trim();
|
|
878
|
+
if (license === 'custom') {
|
|
879
|
+
return { license, licenseUrl: form.licenseUrl.trim(), licenseName: form.licenseName.trim() };
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
license: isLicenseChoice(license) ? license : '',
|
|
883
|
+
licenseUrl: '',
|
|
884
|
+
licenseName: '',
|
|
885
|
+
};
|
|
886
|
+
}
|
|
808
887
|
/** The settings as the form shows them. */
|
|
809
888
|
export function formFromSettings(settings) {
|
|
810
889
|
return {
|
|
@@ -818,8 +897,11 @@ export function formFromSettings(settings) {
|
|
|
818
897
|
homepage: settings.homepage,
|
|
819
898
|
postsPage: settings.postsPage,
|
|
820
899
|
author: settings.author,
|
|
821
|
-
soloAuthor: settings.soloAuthor ? '1' : '',
|
|
822
900
|
theme: settings.theme,
|
|
901
|
+
icon: settings.icon,
|
|
902
|
+
license: settings.license,
|
|
903
|
+
licenseUrl: settings.licenseUrl,
|
|
904
|
+
licenseName: settings.licenseName,
|
|
823
905
|
tagBase: settings.tagBase,
|
|
824
906
|
categoryBase: settings.categoryBase,
|
|
825
907
|
comments: settings.comments ? '1' : '',
|