@geekity/cms 0.3.0 → 0.4.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 +2091 -214
- package/admin/components/fields.njk +165 -0
- package/admin/layouts/base.njk +1 -1
- package/admin/layouts/settings-page.njk +26 -0
- package/admin/layouts/shell.njk +17 -3
- package/admin/pages/account/forgot.njk +47 -0
- package/admin/pages/account/login.njk +26 -0
- package/admin/pages/account/reset.njk +38 -0
- package/admin/pages/account/setup.njk +28 -0
- package/admin/pages/appearance/themes.njk +69 -0
- package/admin/pages/comments/all.njk +133 -0
- package/admin/{layouts/dashboard.njk → pages/dashboard/home.njk} +8 -15
- package/admin/{layouts/document-conflict.njk → pages/documents/conflict.njk} +1 -0
- package/admin/pages/documents/editor.njk +196 -0
- package/admin/{layouts/document-list.njk → pages/documents/list.njk} +19 -2
- package/admin/pages/documents/taxonomy.njk +95 -0
- package/admin/pages/federation/followers.njk +238 -0
- package/admin/pages/media/library.njk +160 -0
- package/admin/pages/messages/all.njk +110 -0
- package/admin/{layouts → pages}/placeholder.njk +5 -1
- package/admin/pages/settings/discussion.njk +99 -0
- package/admin/pages/settings/email.njk +203 -0
- package/admin/pages/settings/federation.njk +75 -0
- package/admin/pages/settings/general.njk +29 -0
- package/admin/pages/settings/permalinks.njk +50 -0
- package/admin/pages/settings/reading.njk +72 -0
- package/admin/pages/users/edit.njk +239 -0
- package/admin/pages/users/list.njk +48 -0
- package/admin/pages/users/new.njk +41 -0
- package/admin/static/admin.css +498 -3
- package/admin/static/copy.js +52 -0
- package/admin/static/editor.js +16 -16
- package/admin/static/slug.js +61 -0
- package/dist/admin/accounts.d.ts +413 -0
- package/dist/admin/accounts.d.ts.map +1 -0
- package/dist/admin/accounts.js +680 -0
- package/dist/admin/accounts.js.map +1 -0
- package/dist/admin/appearance.d.ts +80 -0
- package/dist/admin/appearance.d.ts.map +1 -0
- package/dist/admin/appearance.js +136 -0
- package/dist/admin/appearance.js.map +1 -0
- package/dist/admin/comments.d.ts +90 -0
- package/dist/admin/comments.d.ts.map +1 -0
- package/dist/admin/comments.js +244 -0
- package/dist/admin/comments.js.map +1 -0
- package/dist/admin/credentials.d.ts +26 -2
- package/dist/admin/credentials.d.ts.map +1 -1
- package/dist/admin/credentials.js +35 -2
- package/dist/admin/credentials.js.map +1 -1
- package/dist/admin/documents.d.ts +127 -10
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +360 -41
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/federation.d.ts +151 -50
- package/dist/admin/federation.d.ts.map +1 -1
- package/dist/admin/federation.js +225 -93
- package/dist/admin/federation.js.map +1 -1
- package/dist/admin/formatting.d.ts +20 -0
- package/dist/admin/formatting.d.ts.map +1 -0
- package/dist/admin/formatting.js +72 -0
- package/dist/admin/formatting.js.map +1 -0
- package/dist/admin/headers.d.ts +65 -0
- package/dist/admin/headers.d.ts.map +1 -0
- package/dist/admin/headers.js +104 -0
- package/dist/admin/headers.js.map +1 -0
- package/dist/admin/index.d.ts +38 -12
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +25 -7
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/media.d.ts +168 -0
- package/dist/admin/media.d.ts.map +1 -0
- package/dist/admin/media.js +295 -0
- package/dist/admin/media.js.map +1 -0
- package/dist/admin/menu.d.ts +79 -0
- package/dist/admin/menu.d.ts.map +1 -0
- package/dist/admin/menu.js +126 -0
- package/dist/admin/menu.js.map +1 -0
- package/dist/admin/messages.d.ts +80 -0
- package/dist/admin/messages.d.ts.map +1 -0
- package/dist/admin/messages.js +152 -0
- package/dist/admin/messages.js.map +1 -0
- package/dist/admin/preview.d.ts.map +1 -1
- package/dist/admin/preview.js +31 -7
- package/dist/admin/preview.js.map +1 -1
- package/dist/admin/recovery.d.ts +92 -0
- package/dist/admin/recovery.d.ts.map +1 -0
- package/dist/admin/recovery.js +229 -0
- package/dist/admin/recovery.js.map +1 -0
- package/dist/admin/routes.d.ts +0 -20
- package/dist/admin/routes.d.ts.map +1 -1
- package/dist/admin/routes.js +155 -105
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/settings-discussion.d.ts +37 -0
- package/dist/admin/settings-discussion.d.ts.map +1 -0
- package/dist/admin/settings-discussion.js +117 -0
- package/dist/admin/settings-discussion.js.map +1 -0
- package/dist/admin/settings-email.d.ts +54 -0
- package/dist/admin/settings-email.d.ts.map +1 -0
- package/dist/admin/settings-email.js +189 -0
- package/dist/admin/settings-email.js.map +1 -0
- package/dist/admin/settings-federation.d.ts +39 -0
- package/dist/admin/settings-federation.d.ts.map +1 -0
- package/dist/admin/settings-federation.js +103 -0
- package/dist/admin/settings-federation.js.map +1 -0
- package/dist/admin/settings-general.d.ts +12 -0
- package/dist/admin/settings-general.d.ts.map +1 -0
- package/dist/admin/settings-general.js +48 -0
- package/dist/admin/settings-general.js.map +1 -0
- package/dist/admin/settings-page.d.ts +102 -0
- package/dist/admin/settings-page.d.ts.map +1 -0
- package/dist/admin/settings-page.js +126 -0
- package/dist/admin/settings-page.js.map +1 -0
- package/dist/admin/settings-pages.d.ts +19 -0
- package/dist/admin/settings-pages.d.ts.map +1 -0
- package/dist/admin/settings-pages.js +33 -0
- package/dist/admin/settings-pages.js.map +1 -0
- package/dist/admin/settings-permalinks.d.ts +16 -0
- package/dist/admin/settings-permalinks.d.ts.map +1 -0
- package/dist/admin/settings-permalinks.js +32 -0
- package/dist/admin/settings-permalinks.js.map +1 -0
- package/dist/admin/settings-reading.d.ts +33 -0
- package/dist/admin/settings-reading.d.ts.map +1 -0
- package/dist/admin/settings-reading.js +48 -0
- package/dist/admin/settings-reading.js.map +1 -0
- package/dist/admin/settings.d.ts +325 -96
- package/dist/admin/settings.d.ts.map +1 -1
- package/dist/admin/settings.js +650 -308
- package/dist/admin/settings.js.map +1 -1
- package/dist/admin/store.d.ts +606 -152
- package/dist/admin/store.d.ts.map +1 -1
- package/dist/admin/store.js +863 -268
- package/dist/admin/store.js.map +1 -1
- package/dist/admin/taxonomy.d.ts +114 -0
- package/dist/admin/taxonomy.d.ts.map +1 -0
- package/dist/admin/taxonomy.js +289 -0
- package/dist/admin/taxonomy.js.map +1 -0
- package/dist/admin/templates.d.ts +44 -14
- package/dist/admin/templates.d.ts.map +1 -1
- package/dist/admin/templates.js +44 -14
- package/dist/admin/templates.js.map +1 -1
- package/dist/admin/throttle.d.ts +84 -0
- package/dist/admin/throttle.d.ts.map +1 -0
- package/dist/admin/throttle.js +143 -0
- package/dist/admin/throttle.js.map +1 -0
- package/dist/admin/uploads.d.ts +28 -2
- package/dist/admin/uploads.d.ts.map +1 -1
- package/dist/admin/uploads.js +43 -4
- package/dist/admin/uploads.js.map +1 -1
- package/dist/admin/users.d.ts +100 -13
- package/dist/admin/users.d.ts.map +1 -1
- package/dist/admin/users.js +412 -39
- package/dist/admin/users.js.map +1 -1
- package/dist/cache.d.ts +141 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +207 -0
- package/dist/cache.js.map +1 -0
- package/dist/cli.d.ts +14 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +424 -21
- package/dist/cli.js.map +1 -1
- package/dist/comments/akismet.d.ts +130 -0
- package/dist/comments/akismet.d.ts.map +1 -0
- package/dist/comments/akismet.js +274 -0
- package/dist/comments/akismet.js.map +1 -0
- package/dist/comments/conversation.d.ts +29 -0
- package/dist/comments/conversation.d.ts.map +1 -0
- package/dist/comments/conversation.js +60 -0
- package/dist/comments/conversation.js.map +1 -0
- package/dist/comments/form.d.ts +75 -0
- package/dist/comments/form.d.ts.map +1 -0
- package/dist/comments/form.js +64 -0
- package/dist/comments/form.js.map +1 -0
- package/dist/comments/index.d.ts +15 -0
- package/dist/comments/index.d.ts.map +1 -0
- package/dist/comments/index.js +9 -0
- package/dist/comments/index.js.map +1 -0
- package/dist/comments/markdown.d.ts +8 -0
- package/dist/comments/markdown.d.ts.map +1 -0
- package/dist/comments/markdown.js +85 -0
- package/dist/comments/markdown.js.map +1 -0
- package/dist/comments/moderate.d.ts +71 -0
- package/dist/comments/moderate.d.ts.map +1 -0
- package/dist/comments/moderate.js +88 -0
- package/dist/comments/moderate.js.map +1 -0
- package/dist/comments/policy.d.ts +57 -0
- package/dist/comments/policy.d.ts.map +1 -0
- package/dist/comments/policy.js +80 -0
- package/dist/comments/policy.js.map +1 -0
- package/dist/comments/records.d.ts +266 -0
- package/dist/comments/records.d.ts.map +1 -0
- package/dist/comments/records.js +487 -0
- package/dist/comments/records.js.map +1 -0
- package/dist/comments/routes.d.ts +58 -0
- package/dist/comments/routes.d.ts.map +1 -0
- package/dist/comments/routes.js +177 -0
- package/dist/comments/routes.js.map +1 -0
- package/dist/comments/submission.d.ts +263 -0
- package/dist/comments/submission.d.ts.map +1 -0
- package/dist/comments/submission.js +241 -0
- package/dist/comments/submission.js.map +1 -0
- package/dist/config.d.ts +190 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +118 -6
- package/dist/config.js.map +1 -1
- package/dist/contact/delivery.d.ts +60 -0
- package/dist/contact/delivery.d.ts.map +1 -0
- package/dist/contact/delivery.js +87 -0
- package/dist/contact/delivery.js.map +1 -0
- package/dist/contact/form.d.ts +130 -0
- package/dist/contact/form.d.ts.map +1 -0
- package/dist/contact/form.js +163 -0
- package/dist/contact/form.js.map +1 -0
- package/dist/contact/index.d.ts +17 -0
- package/dist/contact/index.d.ts.map +1 -0
- package/dist/contact/index.js +13 -0
- package/dist/contact/index.js.map +1 -0
- package/dist/contact/records.d.ts +124 -0
- package/dist/contact/records.d.ts.map +1 -0
- package/dist/contact/records.js +218 -0
- package/dist/contact/records.js.map +1 -0
- package/dist/contact/routes.d.ts +17 -0
- package/dist/contact/routes.d.ts.map +1 -0
- package/dist/contact/routes.js +127 -0
- package/dist/contact/routes.js.map +1 -0
- package/dist/contact/submission.d.ts +103 -0
- package/dist/contact/submission.d.ts.map +1 -0
- package/dist/contact/submission.js +166 -0
- package/dist/contact/submission.js.map +1 -0
- package/dist/content/document.d.ts +7 -2
- package/dist/content/document.d.ts.map +1 -1
- package/dist/content/document.js +1 -0
- package/dist/content/document.js.map +1 -1
- package/dist/content/index.d.ts +7 -2
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +4 -1
- package/dist/content/index.js.map +1 -1
- package/dist/content/markdown.d.ts.map +1 -1
- package/dist/content/markdown.js +24 -2
- package/dist/content/markdown.js.map +1 -1
- package/dist/content/parser.d.ts.map +1 -1
- package/dist/content/parser.js +11 -4
- package/dist/content/parser.js.map +1 -1
- package/dist/content/save.d.ts +5 -0
- package/dist/content/save.d.ts.map +1 -1
- package/dist/content/save.js +44 -1
- package/dist/content/save.js.map +1 -1
- package/dist/content/schedule.d.ts +125 -0
- package/dist/content/schedule.d.ts.map +1 -0
- package/dist/content/schedule.js +207 -0
- package/dist/content/schedule.js.map +1 -0
- package/dist/content/search.d.ts +64 -0
- package/dist/content/search.d.ts.map +1 -0
- package/dist/content/search.js +136 -0
- package/dist/content/search.js.map +1 -0
- package/dist/content/store.d.ts +202 -7
- package/dist/content/store.d.ts.map +1 -1
- package/dist/content/store.js +374 -67
- package/dist/content/store.js.map +1 -1
- package/dist/content/sync.d.ts +7 -1
- package/dist/content/sync.d.ts.map +1 -1
- package/dist/content/sync.js +18 -10
- package/dist/content/sync.js.map +1 -1
- package/dist/content/time.d.ts +56 -0
- package/dist/content/time.d.ts.map +1 -0
- package/dist/content/time.js +141 -0
- package/dist/content/time.js.map +1 -0
- package/dist/content/writer.d.ts.map +1 -1
- package/dist/content/writer.js +3 -0
- package/dist/content/writer.js.map +1 -1
- package/dist/env.d.ts +58 -4
- package/dist/env.d.ts.map +1 -1
- package/dist/federation/actor.d.ts +95 -41
- package/dist/federation/actor.d.ts.map +1 -1
- package/dist/federation/actor.js +180 -53
- package/dist/federation/actor.js.map +1 -1
- package/dist/federation/article.d.ts +44 -17
- package/dist/federation/article.d.ts.map +1 -1
- package/dist/federation/article.js +98 -46
- package/dist/federation/article.js.map +1 -1
- package/dist/federation/delivery.d.ts +63 -15
- package/dist/federation/delivery.d.ts.map +1 -1
- package/dist/federation/delivery.js +154 -80
- package/dist/federation/delivery.js.map +1 -1
- package/dist/federation/federation.d.ts +22 -17
- package/dist/federation/federation.d.ts.map +1 -1
- package/dist/federation/federation.js +98 -77
- package/dist/federation/federation.js.map +1 -1
- package/dist/federation/followers.d.ts +3 -2
- package/dist/federation/followers.d.ts.map +1 -1
- package/dist/federation/followers.js +6 -5
- package/dist/federation/followers.js.map +1 -1
- package/dist/federation/import-wordpress.d.ts +128 -0
- package/dist/federation/import-wordpress.d.ts.map +1 -0
- package/dist/federation/import-wordpress.js +426 -0
- package/dist/federation/import-wordpress.js.map +1 -0
- package/dist/federation/inbox.d.ts +36 -13
- package/dist/federation/inbox.d.ts.map +1 -1
- package/dist/federation/inbox.js +120 -49
- package/dist/federation/inbox.js.map +1 -1
- package/dist/federation/index.d.ts +22 -10
- package/dist/federation/index.d.ts.map +1 -1
- package/dist/federation/index.js +13 -8
- package/dist/federation/index.js.map +1 -1
- package/dist/federation/keys.d.ts +98 -20
- package/dist/federation/keys.d.ts.map +1 -1
- package/dist/federation/keys.js +269 -39
- package/dist/federation/keys.js.map +1 -1
- package/dist/federation/mount.d.ts +42 -10
- package/dist/federation/mount.d.ts.map +1 -1
- package/dist/federation/mount.js +266 -26
- package/dist/federation/mount.js.map +1 -1
- package/dist/federation/paths.d.ts +23 -35
- package/dist/federation/paths.d.ts.map +1 -1
- package/dist/federation/paths.js +26 -39
- package/dist/federation/paths.js.map +1 -1
- package/dist/federation/records.d.ts +223 -0
- package/dist/federation/records.d.ts.map +1 -0
- package/dist/federation/records.js +506 -0
- package/dist/federation/records.js.map +1 -0
- package/dist/federation/relays.d.ts +114 -0
- package/dist/federation/relays.d.ts.map +1 -0
- package/dist/federation/relays.js +290 -0
- package/dist/federation/relays.js.map +1 -0
- package/dist/federation/replies.d.ts +80 -0
- package/dist/federation/replies.d.ts.map +1 -0
- package/dist/federation/replies.js +166 -0
- package/dist/federation/replies.js.map +1 -0
- package/dist/federation/wordpress.d.ts +131 -0
- package/dist/federation/wordpress.d.ts.map +1 -0
- package/dist/federation/wordpress.js +341 -0
- package/dist/federation/wordpress.js.map +1 -0
- package/dist/files/atomic.d.ts +103 -0
- package/dist/files/atomic.d.ts.map +1 -0
- package/dist/files/atomic.js +150 -0
- package/dist/files/atomic.js.map +1 -0
- package/dist/files/index.d.ts +3 -0
- package/dist/files/index.d.ts.map +1 -0
- package/dist/files/index.js +2 -0
- package/dist/files/index.js.map +1 -0
- package/dist/forms/protection.d.ts +85 -0
- package/dist/forms/protection.d.ts.map +1 -0
- package/dist/forms/protection.js +116 -0
- package/dist/forms/protection.js.map +1 -0
- package/dist/images/icons.d.ts +59 -0
- package/dist/images/icons.d.ts.map +1 -0
- package/dist/images/icons.js +131 -0
- package/dist/images/icons.js.map +1 -0
- package/dist/images/index.d.ts +7 -0
- package/dist/images/index.d.ts.map +1 -0
- package/dist/images/index.js +4 -0
- package/dist/images/index.js.map +1 -0
- package/dist/images/markup.d.ts +47 -0
- package/dist/images/markup.d.ts.map +1 -0
- package/dist/images/markup.js +175 -0
- package/dist/images/markup.js.map +1 -0
- package/dist/images/paths.d.ts +34 -0
- package/dist/images/paths.d.ts.map +1 -0
- package/dist/images/paths.js +41 -0
- package/dist/images/paths.js.map +1 -0
- package/dist/images/variants.d.ts +104 -0
- package/dist/images/variants.d.ts.map +1 -0
- package/dist/images/variants.js +320 -0
- package/dist/images/variants.js.map +1 -0
- package/dist/index.d.ts +123 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +327 -25
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +18 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +34 -3
- package/dist/init.js.map +1 -1
- package/dist/mail/brevo.d.ts +35 -0
- package/dist/mail/brevo.d.ts.map +1 -0
- package/dist/mail/brevo.js +85 -0
- package/dist/mail/brevo.js.map +1 -0
- package/dist/mail/credentials.d.ts +62 -0
- package/dist/mail/credentials.d.ts.map +1 -0
- package/dist/mail/credentials.js +86 -0
- package/dist/mail/credentials.js.map +1 -0
- package/dist/mail/index.d.ts +15 -0
- package/dist/mail/index.d.ts.map +1 -0
- package/dist/mail/index.js +8 -0
- package/dist/mail/index.js.map +1 -0
- package/dist/mail/memory.d.ts +35 -0
- package/dist/mail/memory.d.ts.map +1 -0
- package/dist/mail/memory.js +29 -0
- package/dist/mail/memory.js.map +1 -0
- package/dist/mail/provider.d.ts +80 -0
- package/dist/mail/provider.d.ts.map +1 -0
- package/dist/mail/provider.js +23 -0
- package/dist/mail/provider.js.map +1 -0
- package/dist/mail/service.d.ts +156 -0
- package/dist/mail/service.d.ts.map +1 -0
- package/dist/mail/service.js +265 -0
- package/dist/mail/service.js.map +1 -0
- package/dist/mail/smtp.d.ts +39 -0
- package/dist/mail/smtp.d.ts.map +1 -0
- package/dist/mail/smtp.js +58 -0
- package/dist/mail/smtp.js.map +1 -0
- package/dist/mail/templates.d.ts +91 -0
- package/dist/mail/templates.d.ts.map +1 -0
- package/dist/mail/templates.js +69 -0
- package/dist/mail/templates.js.map +1 -0
- package/dist/notifications/comments.d.ts +66 -0
- package/dist/notifications/comments.d.ts.map +1 -0
- package/dist/notifications/comments.js +151 -0
- package/dist/notifications/comments.js.map +1 -0
- package/dist/notifications/digest.d.ts +135 -0
- package/dist/notifications/digest.d.ts.map +1 -0
- package/dist/notifications/digest.js +287 -0
- package/dist/notifications/digest.js.map +1 -0
- package/dist/notifications/index.d.ts +13 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +8 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/links.d.ts +60 -0
- package/dist/notifications/links.d.ts.map +1 -0
- package/dist/notifications/links.js +63 -0
- package/dist/notifications/links.js.map +1 -0
- package/dist/notifications/optouts.d.ts +48 -0
- package/dist/notifications/optouts.d.ts.map +1 -0
- package/dist/notifications/optouts.js +93 -0
- package/dist/notifications/optouts.js.map +1 -0
- package/dist/notifications/preferences.d.ts +158 -0
- package/dist/notifications/preferences.d.ts.map +1 -0
- package/dist/notifications/preferences.js +195 -0
- package/dist/notifications/preferences.js.map +1 -0
- package/dist/notifications/routes.d.ts +28 -0
- package/dist/notifications/routes.d.ts.map +1 -0
- package/dist/notifications/routes.js +184 -0
- package/dist/notifications/routes.js.map +1 -0
- package/dist/notifications/tokens.d.ts +60 -0
- package/dist/notifications/tokens.d.ts.map +1 -0
- package/dist/notifications/tokens.js +125 -0
- package/dist/notifications/tokens.js.map +1 -0
- package/dist/notify.d.ts +84 -0
- package/dist/notify.d.ts.map +1 -0
- package/dist/notify.js +149 -0
- package/dist/notify.js.map +1 -0
- package/dist/web/archive.d.ts +49 -0
- package/dist/web/archive.d.ts.map +1 -0
- package/dist/web/archive.js +59 -0
- package/dist/web/archive.js.map +1 -0
- package/dist/web/assets.d.ts +6 -5
- package/dist/web/assets.d.ts.map +1 -1
- package/dist/web/assets.js +5 -7
- package/dist/web/assets.js.map +1 -1
- package/dist/web/authors.d.ts +143 -0
- package/dist/web/authors.d.ts.map +1 -0
- package/dist/web/authors.js +178 -0
- package/dist/web/authors.js.map +1 -0
- package/dist/web/comments.d.ts +60 -0
- package/dist/web/comments.d.ts.map +1 -0
- package/dist/web/comments.js +207 -0
- package/dist/web/comments.js.map +1 -0
- package/dist/web/context.d.ts +162 -28
- package/dist/web/context.d.ts.map +1 -1
- package/dist/web/context.js +123 -26
- package/dist/web/context.js.map +1 -1
- package/dist/web/conversation.d.ts +209 -0
- package/dist/web/conversation.d.ts.map +1 -0
- package/dist/web/conversation.js +557 -0
- package/dist/web/conversation.js.map +1 -0
- package/dist/web/documents.d.ts +36 -6
- package/dist/web/documents.d.ts.map +1 -1
- package/dist/web/documents.js +52 -10
- package/dist/web/documents.js.map +1 -1
- package/dist/web/feed-atom.d.ts +22 -0
- package/dist/web/feed-atom.d.ts.map +1 -0
- package/dist/web/feed-atom.js +83 -0
- package/dist/web/feed-atom.js.map +1 -0
- package/dist/web/feed-item.d.ts +145 -0
- package/dist/web/feed-item.d.ts.map +1 -0
- package/dist/web/feed-item.js +120 -0
- package/dist/web/feed-item.js.map +1 -0
- package/dist/web/feed-json.d.ts +79 -0
- package/dist/web/feed-json.d.ts.map +1 -0
- package/dist/web/feed-json.js +53 -0
- package/dist/web/feed-json.js.map +1 -0
- package/dist/web/feed-rss.d.ts +26 -0
- package/dist/web/feed-rss.d.ts.map +1 -0
- package/dist/web/feed-rss.js +203 -0
- package/dist/web/feed-rss.js.map +1 -0
- package/dist/web/feed-source.d.ts +244 -0
- package/dist/web/feed-source.d.ts.map +1 -0
- package/dist/web/feed-source.js +201 -0
- package/dist/web/feed-source.js.map +1 -0
- package/dist/web/feed-xml.d.ts +63 -0
- package/dist/web/feed-xml.d.ts.map +1 -0
- package/dist/web/feed-xml.js +116 -0
- package/dist/web/feed-xml.js.map +1 -0
- package/dist/web/feeds.d.ts +31 -96
- package/dist/web/feeds.d.ts.map +1 -1
- package/dist/web/feeds.js +94 -198
- package/dist/web/feeds.js.map +1 -1
- package/dist/web/health.d.ts +31 -0
- package/dist/web/health.d.ts.map +1 -0
- package/dist/web/health.js +44 -0
- package/dist/web/health.js.map +1 -0
- package/dist/web/index.d.ts +30 -10
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +18 -7
- package/dist/web/index.js.map +1 -1
- package/dist/web/navigation.d.ts +73 -0
- package/dist/web/navigation.d.ts.map +1 -0
- package/dist/web/navigation.js +110 -0
- package/dist/web/navigation.js.map +1 -0
- package/dist/web/negotiate.d.ts +9 -0
- package/dist/web/negotiate.d.ts.map +1 -1
- package/dist/web/negotiate.js +6 -1
- package/dist/web/negotiate.js.map +1 -1
- package/dist/web/recent.d.ts +43 -0
- package/dist/web/recent.d.ts.map +1 -0
- package/dist/web/recent.js +37 -0
- package/dist/web/recent.js.map +1 -0
- package/dist/web/render.d.ts +197 -9
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +334 -17
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.d.ts +25 -8
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +845 -93
- package/dist/web/routes.js.map +1 -1
- package/dist/web/sanitize.d.ts +19 -0
- package/dist/web/sanitize.d.ts.map +1 -0
- package/dist/web/sanitize.js +272 -0
- package/dist/web/sanitize.js.map +1 -0
- package/dist/web/search.d.ts +79 -0
- package/dist/web/search.d.ts.map +1 -0
- package/dist/web/search.js +94 -0
- package/dist/web/search.js.map +1 -0
- package/dist/web/sitemap.d.ts +120 -0
- package/dist/web/sitemap.d.ts.map +1 -0
- package/dist/web/sitemap.js +199 -0
- package/dist/web/sitemap.js.map +1 -0
- package/dist/web/taxonomy.d.ts +152 -0
- package/dist/web/taxonomy.d.ts.map +1 -0
- package/dist/web/taxonomy.js +237 -0
- package/dist/web/taxonomy.js.map +1 -0
- package/dist/web/templates.d.ts +54 -16
- package/dist/web/templates.d.ts.map +1 -1
- package/dist/web/templates.js +109 -28
- package/dist/web/templates.js.map +1 -1
- package/dist/web/themes.d.ts +205 -0
- package/dist/web/themes.d.ts.map +1 -0
- package/dist/web/themes.js +277 -0
- package/dist/web/themes.js.map +1 -0
- package/dist/webmention/discovery.d.ts +51 -0
- package/dist/webmention/discovery.d.ts.map +1 -0
- package/dist/webmention/discovery.js +176 -0
- package/dist/webmention/discovery.js.map +1 -0
- package/dist/webmention/html.d.ts +71 -0
- package/dist/webmention/html.d.ts.map +1 -0
- package/dist/webmention/html.js +285 -0
- package/dist/webmention/html.js.map +1 -0
- package/dist/webmention/index.d.ts +12 -0
- package/dist/webmention/index.d.ts.map +1 -0
- package/dist/webmention/index.js +8 -0
- package/dist/webmention/index.js.map +1 -0
- package/dist/webmention/links.d.ts +18 -0
- package/dist/webmention/links.d.ts.map +1 -0
- package/dist/webmention/links.js +64 -0
- package/dist/webmention/links.js.map +1 -0
- package/dist/webmention/microformats.d.ts +93 -0
- package/dist/webmention/microformats.d.ts.map +1 -0
- package/dist/webmention/microformats.js +376 -0
- package/dist/webmention/microformats.js.map +1 -0
- package/dist/webmention/receive.d.ts +141 -0
- package/dist/webmention/receive.d.ts.map +1 -0
- package/dist/webmention/receive.js +264 -0
- package/dist/webmention/receive.js.map +1 -0
- package/dist/webmention/routes.d.ts +37 -0
- package/dist/webmention/routes.d.ts.map +1 -0
- package/dist/webmention/routes.js +75 -0
- package/dist/webmention/routes.js.map +1 -0
- package/dist/webmention/service.d.ts +94 -0
- package/dist/webmention/service.d.ts.map +1 -0
- package/dist/webmention/service.js +207 -0
- package/dist/webmention/service.js.map +1 -0
- package/package.json +11 -6
- package/templates/site/content/_data/site.json +1 -0
- package/templates/site/content/posts/2026-01-01-hello-world.md +5 -3
- package/templates/site/geekity.config.ts +11 -1
- package/templates/site/tsconfig.json +1 -1
- package/themes/default/README.md +1096 -50
- package/themes/default/layouts/404.njk +2 -3
- package/themes/default/layouts/author.njk +37 -0
- package/themes/default/layouts/base.njk +172 -31
- package/themes/default/layouts/category.njk +27 -0
- package/themes/default/layouts/front-page.njk +57 -0
- package/themes/default/layouts/home.njk +17 -1
- package/themes/default/layouts/page.njk +57 -5
- package/themes/default/layouts/post.njk +78 -19
- package/themes/default/layouts/search.njk +57 -0
- package/themes/default/layouts/tag.njk +3 -6
- package/themes/default/mail/comment-digest.html.njk +37 -0
- package/themes/default/mail/comment-digest.subject.njk +3 -0
- package/themes/default/mail/comment-digest.txt.njk +40 -0
- package/themes/default/mail/comment-pending.html.njk +27 -0
- package/themes/default/mail/comment-pending.subject.njk +2 -0
- package/themes/default/mail/comment-pending.txt.njk +24 -0
- package/themes/default/mail/comment-reply.html.njk +21 -0
- package/themes/default/mail/comment-reply.subject.njk +2 -0
- package/themes/default/mail/comment-reply.txt.njk +22 -0
- package/themes/default/mail/contact-message.html.njk +24 -0
- package/themes/default/mail/contact-message.subject.njk +5 -0
- package/themes/default/mail/contact-message.txt.njk +20 -0
- package/themes/default/mail/password-changed.html.njk +18 -0
- package/themes/default/mail/password-changed.subject.njk +2 -0
- package/themes/default/mail/password-changed.txt.njk +17 -0
- package/themes/default/mail/password-reset.html.njk +22 -0
- package/themes/default/mail/password-reset.subject.njk +2 -0
- package/themes/default/mail/password-reset.txt.njk +18 -0
- package/themes/default/mail/test.html.njk +14 -0
- package/themes/default/mail/test.subject.njk +2 -0
- package/themes/default/mail/test.txt.njk +12 -0
- package/themes/default/partials/archive.njk +27 -0
- package/themes/default/partials/bio.njk +77 -0
- package/themes/default/partials/comment-form.njk +109 -0
- package/themes/default/partials/contact-form.njk +88 -0
- package/themes/default/partials/conversation.njk +139 -0
- package/themes/default/partials/feeds.njk +26 -0
- package/themes/default/partials/jsonld.njk +120 -0
- package/themes/default/partials/pagination.njk +12 -6
- package/themes/default/partials/post-list.njk +51 -18
- package/themes/default/partials/search-form.njk +17 -0
- package/themes/default/partials/tags.njk +26 -5
- package/themes/default/static/highlight.js +4 -0
- package/themes/default/static/style.css +1119 -194
- package/themes/default/theme.json +5 -0
- package/admin/layouts/document-editor.njk +0 -167
- package/admin/layouts/federation.njk +0 -145
- package/admin/layouts/login.njk +0 -23
- package/admin/layouts/settings.njk +0 -116
- package/admin/layouts/setup.njk +0 -27
- package/admin/layouts/users.njk +0 -91
- /package/admin/{layouts/_flash.njk → components/flash.njk} +0 -0
package/dist/admin/documents.js
CHANGED
|
@@ -2,11 +2,20 @@ import { mkdir, readFile, rename, rm } from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { parseDocument } from '../content/parser.js';
|
|
4
4
|
import { contentFilePath, freeSlug, saveDocument } from '../content/save.js';
|
|
5
|
+
import { scheduledFor } from '../content/schedule.js';
|
|
5
6
|
import { defaultPermalink, slugify } from '../content/slug.js';
|
|
6
7
|
import { DuplicatePermalinkError, isTrashedPath, TRASH_DIRECTORY } from '../content/store.js';
|
|
8
|
+
import { calendarDayIn, DEFAULT_TIMEZONE, toUtcInstant, wallClockIn, zoneLabel, } from '../content/time.js';
|
|
7
9
|
import { normalizeBody, serializeDocument } from '../content/writer.js';
|
|
8
10
|
import { isPublicDocument } from '../web/documents.js';
|
|
11
|
+
import { COMMENTS_FRONT_MATTER_KEY } from '../comments/policy.js';
|
|
12
|
+
import { CONTACT_FRONT_MATTER_KEY } from '../contact/form.js';
|
|
13
|
+
import { NAVIGATION_KEY, NAVIGATION_ORDER_KEY, navigationOrder } from '../web/navigation.js';
|
|
14
|
+
import { userForAuthor } from '../web/authors.js';
|
|
15
|
+
import { findUserById, listUsers } from './accounts.js';
|
|
9
16
|
import { flash } from './flash.js';
|
|
17
|
+
import { formatInTimezone } from './formatting.js';
|
|
18
|
+
import { readSiteSettings } from './settings.js';
|
|
10
19
|
import { PREVIEW_PATH } from './preview.js';
|
|
11
20
|
import { ADMIN_PREFIX } from './session.js';
|
|
12
21
|
import { ADMIN_TEMPLATES } from './templates.js';
|
|
@@ -19,7 +28,30 @@ import { UPLOADS_PATH } from './uploads.js';
|
|
|
19
28
|
* there, alongside every other key somebody added by hand.
|
|
20
29
|
*/
|
|
21
30
|
export const EXCLUDE_KEY = 'eleventyExcludeFromCollections';
|
|
22
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* What the editor's Comments field can say: leave it to the site's rules, hold
|
|
33
|
+
* this document open, or close it.
|
|
34
|
+
*
|
|
35
|
+
* The values are the strings the form submits and the template renders as
|
|
36
|
+
* options, spelled once so the two cannot drift.
|
|
37
|
+
*/
|
|
38
|
+
export const COMMENT_SETTINGS = { site: '', open: 'open', closed: 'closed' };
|
|
39
|
+
/** A submitted Comments field, or the site default for anything else. */
|
|
40
|
+
function commentSetting(value) {
|
|
41
|
+
return value === COMMENT_SETTINGS.open || value === COMMENT_SETTINGS.closed
|
|
42
|
+
? value
|
|
43
|
+
: COMMENT_SETTINGS.site;
|
|
44
|
+
}
|
|
45
|
+
/** What a document's front matter already says about comments. */
|
|
46
|
+
function commentSettingOf(document) {
|
|
47
|
+
const own = document.extra[COMMENTS_FRONT_MATTER_KEY];
|
|
48
|
+
if (own === true)
|
|
49
|
+
return COMMENT_SETTINGS.open;
|
|
50
|
+
if (own === false)
|
|
51
|
+
return COMMENT_SETTINGS.closed;
|
|
52
|
+
return COMMENT_SETTINGS.site;
|
|
53
|
+
}
|
|
54
|
+
/** The posts screens: dated, tagged, categorised, filed under `posts/`. */
|
|
23
55
|
export const POST_KIND = {
|
|
24
56
|
type: 'post',
|
|
25
57
|
section: 'posts',
|
|
@@ -28,7 +60,10 @@ export const POST_KIND = {
|
|
|
28
60
|
plural: 'Posts',
|
|
29
61
|
dated: true,
|
|
30
62
|
tagged: true,
|
|
63
|
+
categorised: true,
|
|
31
64
|
excludable: false,
|
|
65
|
+
navigable: false,
|
|
66
|
+
contactable: false,
|
|
32
67
|
};
|
|
33
68
|
/** The pages screens: standing content, no date prefix and no taxonomy. */
|
|
34
69
|
export const PAGE_KIND = {
|
|
@@ -39,7 +74,10 @@ export const PAGE_KIND = {
|
|
|
39
74
|
plural: 'Pages',
|
|
40
75
|
dated: false,
|
|
41
76
|
tagged: false,
|
|
77
|
+
categorised: false,
|
|
42
78
|
excludable: true,
|
|
79
|
+
navigable: true,
|
|
80
|
+
contactable: true,
|
|
43
81
|
};
|
|
44
82
|
/** The URL of the editor for one document. */
|
|
45
83
|
export function editorPath(kind, slug) {
|
|
@@ -50,7 +88,13 @@ export function newEditorPath(kind) {
|
|
|
50
88
|
return `${kind.basePath}/new`;
|
|
51
89
|
}
|
|
52
90
|
/** The filters, in the order they are shown. */
|
|
53
|
-
export const DOCUMENT_FILTERS = [
|
|
91
|
+
export const DOCUMENT_FILTERS = [
|
|
92
|
+
'all',
|
|
93
|
+
'published',
|
|
94
|
+
'scheduled',
|
|
95
|
+
'draft',
|
|
96
|
+
'trash',
|
|
97
|
+
];
|
|
54
98
|
/** How many rows one page of a listing holds. */
|
|
55
99
|
export const DOCUMENTS_PER_PAGE = 25;
|
|
56
100
|
/** The filter a query string asked for, defaulting to everything live. */
|
|
@@ -62,7 +106,8 @@ export function listOptionsFor(kind, filter) {
|
|
|
62
106
|
return {
|
|
63
107
|
type: kind.type,
|
|
64
108
|
trashed: filter === 'trash',
|
|
65
|
-
...(filter === 'published' ? { draft: false } : {}),
|
|
109
|
+
...(filter === 'published' ? { draft: false, scheduled: false } : {}),
|
|
110
|
+
...(filter === 'scheduled' ? { draft: false, scheduled: true } : {}),
|
|
66
111
|
...(filter === 'draft' ? { draft: true } : {}),
|
|
67
112
|
};
|
|
68
113
|
}
|
|
@@ -72,7 +117,7 @@ export function listOptionsFor(kind, filter) {
|
|
|
72
117
|
* Both `/admin/posts` and `/admin/pages` are this function with a different
|
|
73
118
|
* {@link DocumentKind}: the screens, the templates and the write path are
|
|
74
119
|
* shared, and the kind decides what a file is called, whether the form has a
|
|
75
|
-
* date and
|
|
120
|
+
* date and a taxonomy, and which section of the navigation marks itself.
|
|
76
121
|
*/
|
|
77
122
|
export function mountDocumentScreens(app, options) {
|
|
78
123
|
const { kind, render } = options;
|
|
@@ -89,6 +134,7 @@ export function mountDocumentScreens(app, options) {
|
|
|
89
134
|
const rows = found.slice(0, DOCUMENTS_PER_PAGE);
|
|
90
135
|
return render(c, ADMIN_TEMPLATES.documentList, {
|
|
91
136
|
section: kind.section,
|
|
137
|
+
child: 'all',
|
|
92
138
|
kind,
|
|
93
139
|
filter,
|
|
94
140
|
filters: DOCUMENT_FILTERS.map((name) => ({
|
|
@@ -97,7 +143,7 @@ export function mountDocumentScreens(app, options) {
|
|
|
97
143
|
url: listingUrl(kind, name, 1),
|
|
98
144
|
current: name === filter,
|
|
99
145
|
})),
|
|
100
|
-
documents: rows.map((document) => listRow(kind, document)),
|
|
146
|
+
documents: rows.map((document) => listRow(kind, document, c.var.store.now(), pageRole(kind, document, c))),
|
|
101
147
|
newUrl: newEditorPath(kind),
|
|
102
148
|
returnUrl: listingUrl(kind, filter, pageNumber),
|
|
103
149
|
page: pageNumber,
|
|
@@ -111,14 +157,14 @@ export function mountDocumentScreens(app, options) {
|
|
|
111
157
|
kind,
|
|
112
158
|
render,
|
|
113
159
|
document: undefined,
|
|
114
|
-
form: blankForm(kind),
|
|
160
|
+
form: blankForm(kind, siteTimezone(c), c.var.store.now()),
|
|
115
161
|
}));
|
|
116
162
|
app.post(newEditorPath(kind), async (c) => saveFromForm(c, { kind, render, document: undefined, body: await c.req.parseBody() }));
|
|
117
163
|
app.get(`${kind.basePath}/:slug`, (c) => {
|
|
118
164
|
const document = findBySlug(c.var.store, kind, c.req.param('slug'));
|
|
119
165
|
if (document === undefined)
|
|
120
166
|
return c.notFound();
|
|
121
|
-
return renderEditor(c, { kind, render, document, form: formFor(document) });
|
|
167
|
+
return renderEditor(c, { kind, render, document, form: formFor(document, siteTimezone(c)) });
|
|
122
168
|
});
|
|
123
169
|
app.post(`${kind.basePath}/:slug`, async (c) => {
|
|
124
170
|
const document = findBySlug(c.var.store, kind, c.req.param('slug'));
|
|
@@ -151,9 +197,15 @@ async function saveFromForm(c, options) {
|
|
|
151
197
|
permalink: text(body['permalink']).trim(),
|
|
152
198
|
date: text(body['date']).trim(),
|
|
153
199
|
tags: text(body['tags']).trim(),
|
|
200
|
+
categories: text(body['categories']).trim(),
|
|
154
201
|
description: text(body['description']).trim(),
|
|
202
|
+
author: text(body['author']).trim(),
|
|
155
203
|
draft: body['draft'] !== undefined,
|
|
156
204
|
exclude: body['exclude'] !== undefined,
|
|
205
|
+
navigation: body['navigation'] !== undefined,
|
|
206
|
+
navigationOrder: text(body['navigation_order']).trim(),
|
|
207
|
+
contact: body['contact'] !== undefined,
|
|
208
|
+
comments: commentSetting(text(body['comments'])),
|
|
157
209
|
body: normalizeBody(text(body['body'])),
|
|
158
210
|
hash: text(body['hash']),
|
|
159
211
|
};
|
|
@@ -173,19 +225,60 @@ async function saveFromForm(c, options) {
|
|
|
173
225
|
}
|
|
174
226
|
if (form.title === '')
|
|
175
227
|
return refuse(`A ${kind.singular} needs a title.`);
|
|
176
|
-
|
|
177
|
-
|
|
228
|
+
if (form.navigationOrder !== '' && !Number.isFinite(Number(form.navigationOrder))) {
|
|
229
|
+
return refuse('A menu order is a number, and pulls the lower numbers to the front.');
|
|
230
|
+
}
|
|
231
|
+
const timezone = siteTimezone(c);
|
|
232
|
+
// decision-11: what the file gets is a UTC instant, and an offset-less field
|
|
233
|
+
// is the site's own wall clock rather than the server's.
|
|
234
|
+
const typed = kind.dated ? (form.date === '' ? store.now().toISOString() : form.date) : undefined;
|
|
235
|
+
if (typed !== undefined && !/^\d{4}-\d{2}-\d{2}/.test(typed)) {
|
|
178
236
|
return refuse('A date has to start with a year, a month and a day, like 2026-03-04.');
|
|
179
237
|
}
|
|
238
|
+
const date = typed === undefined ? undefined : toUtcInstant(typed, timezone);
|
|
239
|
+
if (typed !== undefined && date === undefined) {
|
|
240
|
+
return refuse('That date is not one anybody can read. Try 2026-03-04 09:00.');
|
|
241
|
+
}
|
|
180
242
|
const slug = slugify(form.slug) || slugify(form.title) || (document?.slug ?? '') || 'untitled';
|
|
181
243
|
const trashed = document !== undefined && isTrashedPath(document.path);
|
|
244
|
+
// The calendar day the document is filed under: the site zone's day at its
|
|
245
|
+
// date for a new one, and the day already in the filename for one whose date
|
|
246
|
+
// has not moved, so a zone changed later never moves a URL that exists.
|
|
247
|
+
const filed = filedDay({ date, document, timezone });
|
|
182
248
|
// A new document gets out of the way of anything that already holds its
|
|
183
249
|
// name; an existing one keeps the slug it was given.
|
|
184
250
|
const finalSlug = document === undefined
|
|
185
|
-
? await freeSlug({ contentDir, store, type: kind.type, slug, date })
|
|
251
|
+
? await freeSlug({ contentDir, store, type: kind.type, slug, date: filed })
|
|
186
252
|
: slug;
|
|
187
|
-
|
|
188
|
-
|
|
253
|
+
// decision-13: a published post's permalink is its name in the fediverse as
|
|
254
|
+
// well as on the web, and the two are one promise. Moving it hands every
|
|
255
|
+
// follower a second object and breaks every link somebody already shared, so
|
|
256
|
+
// the editor refuses. A draft has promised nothing yet and may still move;
|
|
257
|
+
// a site that really means to move a published post can still do it in the
|
|
258
|
+
// file, knowing what it costs.
|
|
259
|
+
const promised = promisedDocument(kind, document, store.now());
|
|
260
|
+
if (promised !== undefined) {
|
|
261
|
+
if (finalSlug !== promised.slug) {
|
|
262
|
+
return refuse(`The permalink of a published post is permanent, and the slug names the file it is filed under: this ${kind.singular} keeps the slug ${promised.slug}.`);
|
|
263
|
+
}
|
|
264
|
+
// An empty field is not a request to move: it is a form that carried no
|
|
265
|
+
// permalink, and the promised one is what it keeps. Only a field naming
|
|
266
|
+
// some other URL is somebody asking for the one thing this refuses.
|
|
267
|
+
const submitted = normalizePermalink(form.permalink);
|
|
268
|
+
if (submitted !== undefined && submitted !== promised.permalink) {
|
|
269
|
+
return refuse(`The permalink of a published post is permanent: this ${kind.singular} stays at ${promised.permalink}.`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const permalink = promised?.permalink ??
|
|
273
|
+
resolvePermalink({
|
|
274
|
+
kind,
|
|
275
|
+
form,
|
|
276
|
+
slug: finalSlug,
|
|
277
|
+
date: filed,
|
|
278
|
+
document,
|
|
279
|
+
timezone,
|
|
280
|
+
});
|
|
281
|
+
const target = documentPath({ kind, slug: finalSlug, date: filed, trashed });
|
|
189
282
|
if (document !== undefined) {
|
|
190
283
|
const conflict = await conflictWith(contentDir, document, form.hash);
|
|
191
284
|
if (conflict !== undefined) {
|
|
@@ -198,14 +291,15 @@ async function saveFromForm(c, options) {
|
|
|
198
291
|
const content = {
|
|
199
292
|
title: form.title,
|
|
200
293
|
...(date === undefined ? {} : { date }),
|
|
201
|
-
updated:
|
|
294
|
+
updated: store.now().toISOString(),
|
|
202
295
|
permalink,
|
|
203
296
|
tags: kind.tagged ? splitTags(form.tags) : [],
|
|
297
|
+
categories: kind.categorised ? splitTags(form.categories) : [],
|
|
204
298
|
draft,
|
|
205
299
|
...(form.description === '' ? {} : { description: form.description }),
|
|
206
|
-
...optional('author',
|
|
300
|
+
...optional('author', chosenAuthor(c, form.author, document)),
|
|
207
301
|
...optional('activitypub', document?.activitypub),
|
|
208
|
-
extra: resolveExtra(kind, document, form
|
|
302
|
+
extra: resolveExtra(kind, document, form),
|
|
209
303
|
body: form.body,
|
|
210
304
|
};
|
|
211
305
|
// The row for the old path goes first: a rename briefly leaves two rows
|
|
@@ -215,7 +309,7 @@ async function saveFromForm(c, options) {
|
|
|
215
309
|
store.remove(renamedFrom.path);
|
|
216
310
|
let saved;
|
|
217
311
|
try {
|
|
218
|
-
saved = await saveDocument({ contentDir, store, path: target, content });
|
|
312
|
+
saved = await saveDocument({ contentDir, store, path: target, content, timezone });
|
|
219
313
|
}
|
|
220
314
|
catch (error) {
|
|
221
315
|
// Nothing was written, so the row that was taken out of the way goes back.
|
|
@@ -241,13 +335,18 @@ async function saveFromForm(c, options) {
|
|
|
241
335
|
next: saved,
|
|
242
336
|
origin: 'admin',
|
|
243
337
|
});
|
|
244
|
-
flash(c, 'notice', savedMessage(kind, document, saved));
|
|
338
|
+
flash(c, 'notice', savedMessage(kind, document, saved, store.now()));
|
|
245
339
|
return c.redirect(editorPath(kind, saved.slug), 303);
|
|
246
340
|
}
|
|
247
341
|
/** What the flash says after a save, which depends on what the save did. */
|
|
248
|
-
function savedMessage(kind, previous, saved) {
|
|
342
|
+
function savedMessage(kind, previous, saved, now) {
|
|
249
343
|
if (saved.draft)
|
|
250
344
|
return `Draft saved: ${saved.title}`;
|
|
345
|
+
// A date in the future is not a refusal to publish, it is an instruction
|
|
346
|
+
// about when, and the flash has to say so or the author will think the
|
|
347
|
+
// Publish button did nothing.
|
|
348
|
+
if (scheduledFor(saved, now) !== undefined)
|
|
349
|
+
return `Scheduled: ${saved.title}`;
|
|
251
350
|
if (previous === undefined || previous.draft)
|
|
252
351
|
return `Published: ${saved.title}`;
|
|
253
352
|
return `Updated: ${saved.title}`;
|
|
@@ -257,6 +356,21 @@ function documentPath(input) {
|
|
|
257
356
|
const relative = contentFilePath({ type: input.kind.type, slug: input.slug, date: input.date });
|
|
258
357
|
return input.trashed ? `${TRASH_DIRECTORY}/${relative}` : relative;
|
|
259
358
|
}
|
|
359
|
+
/**
|
|
360
|
+
* The document whose permalink has already been promised, or `undefined` when
|
|
361
|
+
* nothing has been promised yet.
|
|
362
|
+
*
|
|
363
|
+
* A published post, and only a published post. decision-13 makes its permalink
|
|
364
|
+
* its ActivityStreams object id, so the URL is a name its followers, its
|
|
365
|
+
* replies and its feed subscribers are all holding; a draft, a trashed post
|
|
366
|
+
* and one whose date has not arrived have been shown to nobody, and a page
|
|
367
|
+
* federates nothing at all.
|
|
368
|
+
*/
|
|
369
|
+
function promisedDocument(kind, document, now) {
|
|
370
|
+
if (document === undefined || kind.type !== 'post')
|
|
371
|
+
return undefined;
|
|
372
|
+
return isPublicDocument(document, now) ? document : undefined;
|
|
373
|
+
}
|
|
260
374
|
/**
|
|
261
375
|
* The permalink to write.
|
|
262
376
|
*
|
|
@@ -276,20 +390,60 @@ function resolvePermalink(input) {
|
|
|
276
390
|
if (submitted === undefined)
|
|
277
391
|
return fallback;
|
|
278
392
|
const document = input.document;
|
|
279
|
-
if (document !== undefined &&
|
|
393
|
+
if (document !== undefined &&
|
|
394
|
+
submitted === previousDefaultPermalink(input.kind, document, input.timezone)) {
|
|
280
395
|
return fallback;
|
|
281
396
|
}
|
|
282
397
|
return submitted;
|
|
283
398
|
}
|
|
284
|
-
/**
|
|
285
|
-
|
|
399
|
+
/**
|
|
400
|
+
* The permalink a document would have had if it had never been customised:
|
|
401
|
+
* its own slug over the day it is filed under, which is the day in its
|
|
402
|
+
* filename rather than one re-derived from a setting that may have moved.
|
|
403
|
+
*/
|
|
404
|
+
function previousDefaultPermalink(kind, document, timezone) {
|
|
286
405
|
try {
|
|
287
|
-
return defaultPermalink({
|
|
406
|
+
return defaultPermalink({
|
|
407
|
+
type: kind.type,
|
|
408
|
+
slug: document.slug,
|
|
409
|
+
date: filedDay({ date: document.date, document, timezone }),
|
|
410
|
+
});
|
|
288
411
|
}
|
|
289
412
|
catch {
|
|
290
413
|
return undefined;
|
|
291
414
|
}
|
|
292
415
|
}
|
|
416
|
+
/**
|
|
417
|
+
* The calendar day a document is filed under, which is what its filename and
|
|
418
|
+
* its `/{yyyy}/{mm}/` permalink are cut from.
|
|
419
|
+
*
|
|
420
|
+
* For a new document it is the day the site's own zone was on at its date, so
|
|
421
|
+
* a post published at half past midnight on 1 October in Berlin is filed under
|
|
422
|
+
* October rather than the September UTC was still on.
|
|
423
|
+
*
|
|
424
|
+
* For a document whose date has not moved it is the day already in its
|
|
425
|
+
* filename. That is the whole of decision-11's promise that changing the
|
|
426
|
+
* timezone setting cannot move an existing URL: the instant is the same, the
|
|
427
|
+
* zone is a lens, and the day this post was filed under was decided once, when
|
|
428
|
+
* it was written, and is on disk where no setting can reach it.
|
|
429
|
+
*/
|
|
430
|
+
function filedDay(input) {
|
|
431
|
+
const { document } = input;
|
|
432
|
+
const date = input.date === undefined ? undefined : toUtcInstant(input.date, input.timezone);
|
|
433
|
+
if (date === undefined)
|
|
434
|
+
return undefined;
|
|
435
|
+
const was = document?.date === undefined ? undefined : toUtcInstant(document.date, input.timezone);
|
|
436
|
+
if (was === date) {
|
|
437
|
+
const existing = /(?:^|\/)(\d{4}-\d{2}-\d{2})-/.exec(document?.path ?? '')?.[1];
|
|
438
|
+
if (existing !== undefined)
|
|
439
|
+
return existing;
|
|
440
|
+
}
|
|
441
|
+
return calendarDayIn(date, input.timezone) ?? date;
|
|
442
|
+
}
|
|
443
|
+
/** The site's time zone, which is what every offset-less date in the admin means. */
|
|
444
|
+
function siteTimezone(c) {
|
|
445
|
+
return readSiteSettings(c.var.config.contentDir).timezone;
|
|
446
|
+
}
|
|
293
447
|
/** A submitted permalink as a URL path, or `undefined` when the field is empty. */
|
|
294
448
|
function normalizePermalink(value) {
|
|
295
449
|
const trimmed = value.trim();
|
|
@@ -314,17 +468,58 @@ function normalizePermalink(value) {
|
|
|
314
468
|
* the `false` is written, because a key somebody wrote by hand is not the
|
|
315
469
|
* editor's to delete.
|
|
316
470
|
*/
|
|
317
|
-
function resolveExtra(kind, document,
|
|
471
|
+
function resolveExtra(kind, document, form) {
|
|
318
472
|
const extra = { ...(document?.extra ?? {}) };
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
extra[
|
|
473
|
+
// The post's own answer about comments, or none at all: "site default" is
|
|
474
|
+
// the absence of the key rather than a value, because that is what every
|
|
475
|
+
// reader of it — the CMS, an Eleventy build, a person looking at the file —
|
|
476
|
+
// already understands, and writing `comments: null` would say nothing new.
|
|
477
|
+
if (form.comments === COMMENT_SETTINGS.open)
|
|
478
|
+
extra[COMMENTS_FRONT_MATTER_KEY] = true;
|
|
479
|
+
else if (form.comments === COMMENT_SETTINGS.closed)
|
|
480
|
+
extra[COMMENTS_FRONT_MATTER_KEY] = false;
|
|
481
|
+
else
|
|
482
|
+
delete extra[COMMENTS_FRONT_MATTER_KEY];
|
|
483
|
+
if (kind.excludable) {
|
|
484
|
+
if (form.exclude)
|
|
485
|
+
extra[EXCLUDE_KEY] = true;
|
|
486
|
+
else if (EXCLUDE_KEY in extra)
|
|
487
|
+
extra[EXCLUDE_KEY] = false;
|
|
488
|
+
}
|
|
489
|
+
if (kind.navigable) {
|
|
490
|
+
if (form.navigation) {
|
|
491
|
+
extra[NAVIGATION_KEY] = true;
|
|
492
|
+
if (form.navigationOrder === '')
|
|
493
|
+
delete extra[NAVIGATION_ORDER_KEY];
|
|
494
|
+
else
|
|
495
|
+
extra[NAVIGATION_ORDER_KEY] = Number(form.navigationOrder);
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
// Both keys go rather than being written `false`, which is where this
|
|
499
|
+
// parts company with `eleventyExcludeFromCollections` above. That one is
|
|
500
|
+
// Eleventy's key and a site may have written it by hand for a build of
|
|
501
|
+
// its own, so a `false` says something; these two are the CMS's own, and
|
|
502
|
+
// absent and false mean the same thing to everything that reads them. An
|
|
503
|
+
// order on a page that is not in the menu means nothing at all.
|
|
504
|
+
delete extra[NAVIGATION_KEY];
|
|
505
|
+
delete extra[NAVIGATION_ORDER_KEY];
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
if (kind.contactable) {
|
|
509
|
+
// Written or removed, never `false`, for the reason the menu keys are: it
|
|
510
|
+
// is the CMS's own key, and absent and false mean the same thing to
|
|
511
|
+
// everything that reads it (TASK-56).
|
|
512
|
+
if (form.contact)
|
|
513
|
+
extra[CONTACT_FRONT_MATTER_KEY] = true;
|
|
514
|
+
else
|
|
515
|
+
delete extra[CONTACT_FRONT_MATTER_KEY];
|
|
516
|
+
}
|
|
325
517
|
return extra;
|
|
326
518
|
}
|
|
327
|
-
/**
|
|
519
|
+
/**
|
|
520
|
+
* A comma-separated taxonomy field as a list, without the blanks and the
|
|
521
|
+
* repeats. Tags and categories are both entered this way.
|
|
522
|
+
*/
|
|
328
523
|
export function splitTags(value) {
|
|
329
524
|
const tags = [];
|
|
330
525
|
for (const tag of value.split(',')) {
|
|
@@ -339,7 +534,62 @@ function currentUsername(c) {
|
|
|
339
534
|
const userId = c.var.session?.userId;
|
|
340
535
|
if (userId == null)
|
|
341
536
|
return undefined;
|
|
342
|
-
return c.var.
|
|
537
|
+
return findUserById(c.var.config.dataDir, userId)?.username;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* What a save writes into the front matter's `author`.
|
|
541
|
+
*
|
|
542
|
+
* The submitted value is resolved through the same rule the public site reads
|
|
543
|
+
* it by ({@link userForAuthor}), and what is written is that user's login: so
|
|
544
|
+
* a file carrying a display name from before decision-14 is rewritten as a
|
|
545
|
+
* username the first time somebody saves it, which is exactly the "until it is
|
|
546
|
+
* next saved" doc-2 promises.
|
|
547
|
+
*
|
|
548
|
+
* A value naming nobody this site has changes nothing. There is no form this
|
|
549
|
+
* CMS renders that could submit one — the select only ever offers the users
|
|
550
|
+
* and, for a file that names a stranger, that file's own value — so the case
|
|
551
|
+
* is either a hand-made request or a user deleted between the load and the
|
|
552
|
+
* save, and neither is a reason to reattribute somebody's post.
|
|
553
|
+
*/
|
|
554
|
+
function chosenAuthor(c, submitted, document) {
|
|
555
|
+
const named = userForAuthor(listUsers(c.var.config.dataDir), submitted);
|
|
556
|
+
if (named !== undefined)
|
|
557
|
+
return named.username;
|
|
558
|
+
return document?.author ?? currentUsername(c);
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* The Author select: every user, whoever the document names, and — for a file
|
|
562
|
+
* naming somebody with no account here — that name too.
|
|
563
|
+
*
|
|
564
|
+
* The stranger's option is what keeps the editor honest. Without it, opening a
|
|
565
|
+
* post written by a colleague whose account has gone and pressing Update would
|
|
566
|
+
* quietly move the post to whoever happened to be first in the list; with it,
|
|
567
|
+
* the form submits back what the file says and changing the attribution stays
|
|
568
|
+
* a thing somebody chose to do.
|
|
569
|
+
*
|
|
570
|
+
* A new document starts on the signed-in user, which is what doc-5 says the
|
|
571
|
+
* editor does and what {@link blankForm} deliberately leaves to a request.
|
|
572
|
+
*/
|
|
573
|
+
export function authorChoices(c, current) {
|
|
574
|
+
const users = listUsers(c.var.config.dataDir);
|
|
575
|
+
const named = userForAuthor(users, current);
|
|
576
|
+
const chosen = named?.username ?? (current === '' ? currentUsername(c) : current);
|
|
577
|
+
const choices = users.map((user) => ({
|
|
578
|
+
value: user.username,
|
|
579
|
+
label: authorLabel(user),
|
|
580
|
+
chosen: user.username === chosen,
|
|
581
|
+
}));
|
|
582
|
+
// A name the file holds that is nobody here: offered last, and marked, so it
|
|
583
|
+
// is plain that the post is attributed to somebody this site cannot reach.
|
|
584
|
+
if (named === undefined && current !== '') {
|
|
585
|
+
choices.push({ value: current, label: `${current} (no account here)`, chosen: true });
|
|
586
|
+
}
|
|
587
|
+
return choices;
|
|
588
|
+
}
|
|
589
|
+
/** How one user reads in the select: their name, and the login behind it. */
|
|
590
|
+
function authorLabel(user) {
|
|
591
|
+
const displayName = user.profile?.displayName;
|
|
592
|
+
return displayName === undefined ? user.username : `${displayName} (${user.username})`;
|
|
343
593
|
}
|
|
344
594
|
/**
|
|
345
595
|
* Whether the file has moved on since the form loaded, per doc-1: files win,
|
|
@@ -385,16 +635,19 @@ function renderConflict(c, options) {
|
|
|
385
635
|
...(form.date === '' ? {} : { date: form.date }),
|
|
386
636
|
permalink: form.permalink === '' ? document.permalink : form.permalink,
|
|
387
637
|
tags: kind.tagged ? splitTags(form.tags) : [],
|
|
638
|
+
categories: kind.categorised ? splitTags(form.categories) : [],
|
|
388
639
|
draft: form.draft,
|
|
389
640
|
...(form.description === '' ? {} : { description: form.description }),
|
|
390
641
|
...optional('author', document.author),
|
|
391
642
|
...optional('activitypub', document.activitypub),
|
|
392
|
-
extra: resolveExtra(kind, document, form
|
|
643
|
+
extra: resolveExtra(kind, document, form),
|
|
393
644
|
body: form.body,
|
|
394
645
|
});
|
|
395
646
|
c.status(409);
|
|
396
647
|
return options.render(c, ADMIN_TEMPLATES.documentConflict, {
|
|
397
648
|
section: kind.section,
|
|
649
|
+
// Editing something that exists, so the listing is where the menu stands.
|
|
650
|
+
child: 'all',
|
|
398
651
|
kind,
|
|
399
652
|
form,
|
|
400
653
|
// The hash the file has now, so resubmitting this form is a deliberate
|
|
@@ -485,32 +738,60 @@ function optional(key, value) {
|
|
|
485
738
|
function text(value) {
|
|
486
739
|
return typeof value === 'string' ? value : '';
|
|
487
740
|
}
|
|
488
|
-
/**
|
|
489
|
-
|
|
741
|
+
/**
|
|
742
|
+
* The editor for a document that does not exist yet.
|
|
743
|
+
*
|
|
744
|
+
* The date field is filled in with the clock as the site's own zone reads it,
|
|
745
|
+
* not with an instant: what a form offers is what a form takes back, and per
|
|
746
|
+
* decision-11 an offset-less date in this field means the site's zone.
|
|
747
|
+
*/
|
|
748
|
+
export function blankForm(kind, timezone = DEFAULT_TIMEZONE, now = new Date()) {
|
|
490
749
|
return {
|
|
491
750
|
title: '',
|
|
492
751
|
slug: '',
|
|
493
752
|
permalink: '',
|
|
494
|
-
date: kind.dated ?
|
|
753
|
+
date: kind.dated ? wallClockIn(now, timezone) : '',
|
|
495
754
|
tags: '',
|
|
755
|
+
categories: '',
|
|
496
756
|
description: '',
|
|
757
|
+
// Empty rather than the signed-in user: `blankForm` is a pure function
|
|
758
|
+
// over a kind and a clock, and who is signed in is a fact about a request.
|
|
759
|
+
// {@link authorChoices} is where the default is applied.
|
|
760
|
+
author: '',
|
|
497
761
|
draft: false,
|
|
498
762
|
exclude: false,
|
|
763
|
+
navigation: false,
|
|
764
|
+
navigationOrder: '',
|
|
765
|
+
contact: false,
|
|
766
|
+
comments: COMMENT_SETTINGS.site,
|
|
499
767
|
body: '',
|
|
500
768
|
hash: '',
|
|
501
769
|
};
|
|
502
770
|
}
|
|
503
|
-
/**
|
|
504
|
-
|
|
771
|
+
/**
|
|
772
|
+
* The editor for a document that does.
|
|
773
|
+
*
|
|
774
|
+
* The stored instant is shown as the clock in the site's zone reads it, and
|
|
775
|
+
* {@link wallClockIn} keeps whatever precision the instant has, so a form
|
|
776
|
+
* submitted with the field untouched writes back the very instant it was
|
|
777
|
+
* filled in from.
|
|
778
|
+
*/
|
|
779
|
+
export function formFor(document, timezone = DEFAULT_TIMEZONE) {
|
|
505
780
|
return {
|
|
506
781
|
title: document.title,
|
|
507
782
|
slug: document.slug,
|
|
508
783
|
permalink: document.permalink,
|
|
509
|
-
date: document.date
|
|
784
|
+
date: document.date === undefined ? '' : wallClockIn(document.date, timezone),
|
|
510
785
|
tags: document.tags.join(', '),
|
|
786
|
+
categories: document.categories.join(', '),
|
|
511
787
|
description: document.description ?? '',
|
|
788
|
+
author: document.author ?? '',
|
|
512
789
|
draft: document.draft,
|
|
513
790
|
exclude: document.extra[EXCLUDE_KEY] === true,
|
|
791
|
+
navigation: document.extra[NAVIGATION_KEY] === true,
|
|
792
|
+
navigationOrder: navigationOrder(document)?.toString() ?? '',
|
|
793
|
+
contact: document.extra[CONTACT_FRONT_MATTER_KEY] === true,
|
|
794
|
+
comments: commentSettingOf(document),
|
|
514
795
|
body: document.body,
|
|
515
796
|
hash: document.hash,
|
|
516
797
|
};
|
|
@@ -526,6 +807,11 @@ export function formFor(document) {
|
|
|
526
807
|
function renderEditor(c, options) {
|
|
527
808
|
const { kind, document, form } = options;
|
|
528
809
|
const trashed = document !== undefined && isTrashedPath(document.path);
|
|
810
|
+
const now = c.var.store.now();
|
|
811
|
+
const timezone = siteTimezone(c);
|
|
812
|
+
// Printed in the site's own time zone rather than in UTC: an author who
|
|
813
|
+
// scheduled a post for nine in the morning meant their own morning.
|
|
814
|
+
const scheduledAt = document === undefined || trashed || document.draft ? undefined : scheduledFor(document, now);
|
|
529
815
|
const actions = [];
|
|
530
816
|
if (document === undefined || document.draft) {
|
|
531
817
|
actions.push({ value: 'save-draft', label: 'Save draft' });
|
|
@@ -542,16 +828,26 @@ function renderEditor(c, options) {
|
|
|
542
828
|
c.status(options.status);
|
|
543
829
|
return options.render(c, ADMIN_TEMPLATES.documentEditor, {
|
|
544
830
|
section: kind.section,
|
|
831
|
+
// The blank form is Add new; editing one that exists is still All posts,
|
|
832
|
+
// the way WordPress leaves the listing marked while you are in the editor.
|
|
833
|
+
child: document === undefined ? 'new' : 'all',
|
|
545
834
|
kind,
|
|
546
835
|
form,
|
|
547
836
|
actions,
|
|
548
837
|
trashed,
|
|
838
|
+
commentSettings: COMMENT_SETTINGS,
|
|
839
|
+
// Who this can be attributed to, and who it is attributed to now.
|
|
840
|
+
authors: authorChoices(c, form.author),
|
|
549
841
|
heading: document === undefined ? `Add ${kind.singular}` : `Edit ${kind.singular}: ${document.title}`,
|
|
550
842
|
saveUrl: document === undefined ? newEditorPath(kind) : editorPath(kind, document.slug),
|
|
551
843
|
listUrl: kind.basePath,
|
|
552
844
|
previewUrl: PREVIEW_PATH,
|
|
553
845
|
uploadUrl: UPLOADS_PATH,
|
|
554
|
-
viewUrl: document !== undefined && isPublicDocument(document) ? document.permalink : undefined,
|
|
846
|
+
viewUrl: document !== undefined && isPublicDocument(document, now) ? document.permalink : undefined,
|
|
847
|
+
// Named beside the date field, because a wall clock with no zone on it is
|
|
848
|
+
// exactly the ambiguity decision-11 exists to remove.
|
|
849
|
+
...(kind.dated ? { dateZone: zoneLabel(form.date === '' ? now : form.date, timezone) } : {}),
|
|
850
|
+
...(scheduledAt === undefined ? {} : { scheduledFor: formatInTimezone(scheduledAt, timezone) }),
|
|
555
851
|
...(options.error === undefined ? {} : { error: options.error }),
|
|
556
852
|
});
|
|
557
853
|
}
|
|
@@ -576,13 +872,33 @@ export function findBySlug(store, kind, slug) {
|
|
|
576
872
|
}
|
|
577
873
|
return undefined;
|
|
578
874
|
}
|
|
579
|
-
|
|
580
|
-
|
|
875
|
+
/**
|
|
876
|
+
* WordPress's own two labels for the pages the Reading setting names, beside
|
|
877
|
+
* the title on the pages screen, so it is plain from the list which page is
|
|
878
|
+
* the front page and which carries the posts.
|
|
879
|
+
*/
|
|
880
|
+
export const PAGE_ROLE_LABELS = { homepage: 'Front Page', postsPage: 'Posts Page' };
|
|
881
|
+
/** What one row's page is to the site, if anything. */
|
|
882
|
+
function pageRole(kind, document, c) {
|
|
883
|
+
if (kind.type !== 'page')
|
|
884
|
+
return undefined;
|
|
885
|
+
const settings = readSiteSettings(c.var.config.contentDir);
|
|
886
|
+
if (settings.homepage === '')
|
|
887
|
+
return undefined;
|
|
888
|
+
if (document.slug === settings.homepage)
|
|
889
|
+
return PAGE_ROLE_LABELS.homepage;
|
|
890
|
+
if (document.slug === settings.postsPage)
|
|
891
|
+
return PAGE_ROLE_LABELS.postsPage;
|
|
892
|
+
return undefined;
|
|
893
|
+
}
|
|
894
|
+
function listRow(kind, document, now, role) {
|
|
895
|
+
const isPublic = isPublicDocument(document, now);
|
|
581
896
|
return {
|
|
582
897
|
title: document.title,
|
|
583
898
|
slug: document.slug,
|
|
584
899
|
author: document.author,
|
|
585
900
|
tags: document.tags.join(', '),
|
|
901
|
+
categories: document.categories.join(', '),
|
|
586
902
|
date: document.date,
|
|
587
903
|
// Both come out of the index, so the listing costs no reads of its own.
|
|
588
904
|
// A page that has never been saved through the admin has no `updated`, and
|
|
@@ -590,13 +906,16 @@ function listRow(kind, document) {
|
|
|
590
906
|
updated: document.updated ?? document.date,
|
|
591
907
|
draft: document.draft,
|
|
592
908
|
trashed: isTrashedPath(document.path),
|
|
909
|
+
scheduled: scheduledFor(document, now) !== undefined,
|
|
593
910
|
editUrl: editorPath(kind, document.slug),
|
|
594
911
|
viewUrl: isPublic ? document.permalink : undefined,
|
|
912
|
+
role,
|
|
595
913
|
};
|
|
596
914
|
}
|
|
597
915
|
const FILTER_LABELS = {
|
|
598
916
|
all: 'All',
|
|
599
917
|
published: 'Published',
|
|
918
|
+
scheduled: 'Scheduled',
|
|
600
919
|
draft: 'Drafts',
|
|
601
920
|
trash: 'Trash',
|
|
602
921
|
};
|