@jant/core 0.6.16 → 0.7.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 +11 -11
- package/bin/commands/assets/upload.js +192 -15
- package/bin/commands/import-site.js +60 -4
- package/bin/commands/reset-password.js +21 -8
- package/bin/commands/site/snapshot/export.js +1 -1
- package/bin/commands/site/snapshot/import.js +1 -1
- package/bin/lib/d1-query.js +5 -16
- package/bin/lib/node-env.js +40 -4
- package/bin/lib/site-selection.js +85 -29
- package/bin/lib/wrangler-cli.js +28 -2
- package/bin/lib/wrangler-json.js +35 -0
- package/dist/{app-C7_4oab9.js → app-K_Aa1MMn.js} +52476 -13330
- package/dist/client/.vite/manifest.json +255 -90
- package/dist/client/_assets/chunks/confirm-D7GrwsCN.js +45 -0
- package/dist/client/_assets/chunks/create-editor-CD3FhrOB.js +257 -0
- package/dist/client/_assets/chunks/{native-DpcrFAPh.js → emoji-mart-C4RpRKcU.js} +716 -1
- package/dist/client/_assets/chunks/footnote-rail-CmeoVtnU.js +1 -0
- package/dist/client/_assets/chunks/heic-to-CuP2Qlsw.js +1 -0
- package/dist/client/_assets/chunks/jant-locale-picker-DL6mIOT5.js +69 -0
- package/dist/client/_assets/chunks/lit-DW8VmJAT.js +2 -0
- package/dist/client/_assets/chunks/mediabunny-DRaCQ1r-.js +31 -0
- package/dist/client/_assets/chunks/rolldown-runtime-hePW80VL.js +1 -0
- package/dist/client/_assets/chunks/settings-paths-BcdySNx6.js +84 -0
- package/dist/client/_assets/chunks/site-header-nav-DzXsFk05.js +1 -0
- package/dist/client/_assets/chunks/slug-format-CRXO1AL5.js +1 -0
- package/dist/client/_assets/chunks/slugify-373citbs.js +1 -0
- package/dist/client/_assets/chunks/sortable-list-CgaL2jCs.js +2 -0
- package/dist/client/_assets/chunks/types-D5iF3H1a.js +1 -0
- package/dist/client/_assets/chunks/unsafe-html-B5ZEXaxg.js +1 -0
- package/dist/client/_assets/chunks/unsafe-svg-0QCkP0vZ.js +2 -0
- package/dist/client/_assets/client-GiYENVw8.css +2 -0
- package/dist/client/_assets/client-VnFxJN7G.js +295 -0
- package/dist/client/_assets/client-auth-k8gJ6QJj.js +828 -0
- package/dist/client/_assets/client-author-DQ8R-8KR.css +2 -0
- package/dist/client/_assets/client-compose-B_kDtWkW.js +2004 -0
- package/dist/client/_assets/client-manage-M90aSTOk.js +2170 -0
- package/dist/client/_assets/client-settings-DfYs9n1F.js +1112 -0
- package/dist/{export-Dl5KCiEs.js → github-sync-BPAvT999.js} +2254 -107
- package/dist/index.js +2 -5
- package/dist/node.js +5 -7
- package/package.json +3 -3
- package/src/__tests__/auth-session-freshness.test.ts +57 -0
- package/src/__tests__/basecoat-variants.test.ts +121 -0
- package/src/__tests__/bin/assets-upload.test.ts +68 -0
- package/src/__tests__/export-hugo-build.test.ts +260 -0
- package/src/__tests__/export-service.test.ts +231 -0
- package/src/__tests__/helpers/component-css.ts +91 -0
- package/src/__tests__/helpers/db.ts +33 -0
- package/src/__tests__/helpers/export-fixtures.ts +3 -0
- package/src/__tests__/stylesheet-audience.test.ts +159 -0
- package/src/__tests__/stylesheet-breakpoints.test.ts +183 -0
- package/src/app.tsx +71 -16
- package/src/auth.ts +18 -1
- package/src/client/__tests__/collection-page-actions.test.ts +51 -2
- package/src/client/__tests__/compose-bridge-image-upload.test.ts +196 -0
- package/src/client/__tests__/compose-bridge-video-poster.test.ts +159 -0
- package/src/client/__tests__/compose-bridge.test.ts +272 -0
- package/src/client/__tests__/compose-launch.test.ts +62 -1
- package/src/client/__tests__/compose-shortcuts.test.ts +38 -9
- package/src/client/__tests__/compose-triggers.test.ts +90 -0
- package/src/client/__tests__/copy-field.test.ts +162 -0
- package/src/client/__tests__/custom-url-menu.test.ts +127 -6
- package/src/client/__tests__/image-processor.test.ts +324 -2
- package/src/client/__tests__/lazy-entries.test.ts +92 -0
- package/src/client/__tests__/media-scroll-hint.test.ts +155 -0
- package/src/client/__tests__/runtime-paths.test.ts +84 -0
- package/src/client/__tests__/smart-collection-page-actions.test.ts +158 -0
- package/src/client/__tests__/toast.test.ts +23 -0
- package/src/client/__tests__/video-processor-probe.test.ts +175 -0
- package/src/client/__tests__/video-processor.test.ts +181 -0
- package/src/client/audio-processor.ts +24 -15
- package/src/client/audio-waveform.ts +49 -0
- package/src/client/collection-dialog-host.ts +72 -0
- package/src/client/collection-navigation.ts +51 -16
- package/src/client/collection-page-actions.ts +26 -0
- package/src/client/components/__tests__/jant-collection-dialog.test.ts +329 -0
- package/src/client/components/__tests__/jant-collection-directory.test.ts +274 -10
- package/src/client/components/__tests__/jant-collection-form.test.ts +59 -178
- package/src/client/components/__tests__/jant-command-palette.test.ts +28 -0
- package/src/client/components/__tests__/jant-compose-dialog-draft-storage.test.ts +340 -0
- package/src/client/components/__tests__/jant-compose-dialog.test.ts +1250 -53
- package/src/client/components/__tests__/jant-compose-editor.test.ts +544 -40
- package/src/client/components/__tests__/jant-compose-fullscreen.test.ts +0 -1
- package/src/client/components/__tests__/jant-locale-picker.test.ts +207 -0
- package/src/client/components/__tests__/jant-nav-manager.test.ts +234 -15
- package/src/client/components/__tests__/jant-post-menu.test.ts +413 -2
- package/src/client/components/__tests__/jant-post-picker.test.ts +197 -0
- package/src/client/components/__tests__/jant-settings-avatar.test.ts +15 -12
- package/src/client/components/__tests__/jant-settings-general.test.ts +541 -172
- package/src/client/components/__tests__/jant-settings-language.test.ts +851 -0
- package/src/client/components/__tests__/jant-smart-collection-dialog.test.ts +665 -0
- package/src/client/components/collection-dialog-types.ts +49 -0
- package/src/client/components/collection-manager-types.ts +32 -1
- package/src/client/components/collection-types.ts +1 -15
- package/src/client/components/compose-types.ts +75 -1
- package/src/client/components/jant-collection-dialog.ts +722 -0
- package/src/client/components/jant-collection-directory.ts +567 -182
- package/src/client/components/jant-collection-form.ts +53 -232
- package/src/client/components/jant-command-palette.ts +100 -49
- package/src/client/components/jant-compose-dialog.ts +1486 -707
- package/src/client/components/jant-compose-editor.ts +673 -336
- package/src/client/components/jant-compose-fullscreen.ts +51 -43
- package/src/client/components/jant-config-editor.ts +65 -53
- package/src/client/components/jant-confirm-dialog.ts +13 -11
- package/src/client/components/jant-locale-picker.ts +418 -0
- package/src/client/components/jant-media-lightbox.ts +146 -136
- package/src/client/components/jant-nav-manager.ts +690 -366
- package/src/client/components/jant-post-menu.ts +1086 -282
- package/src/client/components/jant-post-picker.ts +324 -0
- package/src/client/components/jant-repo-picker.ts +138 -106
- package/src/client/components/jant-settings-avatar.ts +31 -27
- package/src/client/components/jant-settings-general.ts +617 -543
- package/src/client/components/jant-settings-language.ts +1087 -0
- package/src/client/components/jant-smart-collection-dialog.ts +1021 -0
- package/src/client/components/jant-text-preview.ts +94 -86
- package/src/client/components/nav-manager-types.ts +62 -1
- package/src/client/components/settings-types.ts +14 -29
- package/src/client/components/smart-collection-conditions.ts +285 -0
- package/src/client/components/smart-collection-dialog-types.ts +68 -0
- package/src/client/compose-bridge.ts +214 -141
- package/src/client/compose-launch.ts +76 -2
- package/src/client/compose-shortcuts.ts +6 -8
- package/src/client/compose-triggers.ts +50 -0
- package/src/client/copy-field.ts +108 -0
- package/src/client/custom-url-menu.ts +60 -4
- package/src/client/icons.ts +14 -0
- package/src/client/image-plan.ts +165 -0
- package/src/client/image-processor.ts +195 -117
- package/src/client/image-worker-client.ts +45 -0
- package/src/client/image-worker.ts +135 -0
- package/src/client/lazy-entries.ts +95 -0
- package/src/client/lazy-slugify.ts +2 -2
- package/src/client/media-scroll-hint.ts +43 -2
- package/src/client/mediabunny.ts +29 -0
- package/src/client/post-picker.ts +41 -0
- package/src/client/runtime-paths.ts +74 -1
- package/src/client/settings-bridge.ts +4 -10
- package/src/client/site-header-nav.js +18 -6
- package/src/client/smart-collection-dialog-host.ts +116 -0
- package/src/client/smart-collection-page-actions.ts +208 -0
- package/src/client/tiptap/__tests__/bubble-menu.test.ts +110 -0
- package/src/client/tiptap/__tests__/floating-position.test.ts +136 -1
- package/src/client/tiptap/__tests__/inline-image-upload.test.ts +37 -0
- package/src/client/tiptap/bubble-menu.ts +47 -16
- package/src/client/tiptap/floating-position.ts +216 -2
- package/src/client/tiptap/inline-image-upload.ts +7 -3
- package/src/client/tiptap/link-toolbar.ts +22 -9
- package/src/client/toast.ts +13 -0
- package/src/client/types/vite-worker.d.ts +12 -0
- package/src/client/upload-with-metadata.ts +3 -13
- package/src/client/video-processor.ts +351 -107
- package/src/client-auth.ts +14 -31
- package/src/client-compose.ts +19 -0
- package/src/client-manage.ts +13 -0
- package/src/client-settings.ts +14 -0
- package/src/client-site.ts +10 -3
- package/src/client.ts +4 -0
- package/src/db/__tests__/backfill-nav-label-mirrors.test.ts +149 -0
- package/src/db/__tests__/schema-enum-sources.test.ts +33 -0
- package/src/db/__tests__/smart-collection-placement.test.ts +402 -0
- package/src/db/backfills/0006_clear_mirrored_page_nav_labels.sql +31 -0
- package/src/db/migrations/0032_married_tomas.sql +3 -0
- package/src/db/migrations/0033_busy_johnny_storm.sql +198 -0
- package/src/db/migrations/0034_cheerful_rumiko_fujikawa.sql +35 -0
- package/src/db/migrations/meta/0032_snapshot.json +2582 -0
- package/src/db/migrations/meta/0033_snapshot.json +2816 -0
- package/src/db/migrations/meta/0034_snapshot.json +2816 -0
- package/src/db/migrations/meta/_journal.json +21 -0
- package/src/db/migrations/pg/0030_abandoned_nighthawk.sql +3 -0
- package/src/db/migrations/pg/0031_strong_ultimatum.sql +128 -0
- package/src/db/migrations/pg/0032_furry_multiple_man.sql +6 -0
- package/src/db/migrations/pg/meta/0030_snapshot.json +3329 -0
- package/src/db/migrations/pg/meta/0031_snapshot.json +3660 -0
- package/src/db/migrations/pg/meta/0032_snapshot.json +3660 -0
- package/src/db/migrations/pg/meta/_journal.json +21 -0
- package/src/db/pg/schema.ts +195 -27
- package/src/db/post-visibility.ts +117 -0
- package/src/db/schema.ts +222 -27
- package/src/i18n/__tests__/detect.test.ts +26 -81
- package/src/i18n/__tests__/supported-locales.test.ts +83 -0
- package/src/i18n/context.tsx +12 -2
- package/src/i18n/detect.ts +7 -66
- package/src/i18n/locales/glossary.zh-Hans.yml +44 -4
- package/src/i18n/locales/glossary.zh-Hant.yml +44 -4
- package/src/i18n/locales/public/en.po +490 -158
- package/src/i18n/locales/public/en.ts +1 -1
- package/src/i18n/locales/public/zh-Hans.po +487 -155
- package/src/i18n/locales/public/zh-Hans.ts +1 -1
- package/src/i18n/locales/public/zh-Hant.po +487 -155
- package/src/i18n/locales/public/zh-Hant.ts +1 -1
- package/src/i18n/locales/settings/en.po +551 -69
- package/src/i18n/locales/settings/en.ts +1 -1
- package/src/i18n/locales/settings/zh-Hans.po +597 -115
- package/src/i18n/locales/settings/zh-Hans.ts +1 -1
- package/src/i18n/locales/settings/zh-Hant.po +610 -128
- package/src/i18n/locales/settings/zh-Hant.ts +1 -1
- package/src/i18n/locales.ts +94 -0
- package/src/i18n/middleware.ts +12 -2
- package/src/i18n/supported-locales.ts +80 -0
- package/src/lib/__tests__/api-settings.test.ts +11 -2
- package/src/lib/__tests__/asset-path.test.ts +92 -0
- package/src/lib/__tests__/deferred.test.ts +90 -0
- package/src/lib/__tests__/discover-ping.test.ts +89 -0
- package/src/lib/__tests__/discover.test.ts +410 -0
- package/src/lib/__tests__/feed-policy.test.ts +26 -0
- package/src/lib/__tests__/feed.test.ts +1526 -15
- package/src/lib/__tests__/filter-dimensions.test.ts +341 -0
- package/src/lib/__tests__/hosted-signin.test.ts +1 -1
- package/src/lib/__tests__/http-cache.test.ts +162 -0
- package/src/lib/__tests__/jant-docs-dev.test.ts +21 -0
- package/src/lib/__tests__/jant-docs.test.ts +23 -0
- package/src/lib/__tests__/lang-detect.test.ts +231 -0
- package/src/lib/__tests__/media-helpers.test.ts +81 -0
- package/src/lib/__tests__/navigation.test.ts +135 -1
- package/src/lib/__tests__/resolve-config.test.ts +64 -3
- package/src/lib/__tests__/schemas.test.ts +42 -4
- package/src/lib/__tests__/site-unavailable-page.test.ts +25 -0
- package/src/lib/__tests__/slug.test.ts +70 -0
- package/src/lib/__tests__/slugify.test.ts +85 -0
- package/src/lib/__tests__/storage.test.ts +32 -0
- package/src/lib/__tests__/thread-fold.test.ts +113 -0
- package/src/lib/__tests__/upload-sideload.test.ts +14 -0
- package/src/lib/__tests__/url-fetch.test.ts +1 -2
- package/src/lib/__tests__/url.test.ts +78 -72
- package/src/lib/__tests__/view-language.test.ts +413 -0
- package/src/lib/__tests__/worker-response-cache.test.ts +90 -0
- package/src/lib/address.ts +57 -0
- package/src/lib/api-posts.ts +12 -0
- package/src/lib/asset-path.ts +98 -1
- package/src/lib/build-env.ts +16 -0
- package/src/lib/collection-groups.ts +5 -1
- package/src/lib/collection-paths.ts +3 -10
- package/src/lib/constants.ts +28 -3
- package/src/lib/copy-field.ts +36 -0
- package/src/lib/crypto.ts +40 -0
- package/src/lib/csp-builder.ts +2 -1
- package/src/lib/deferred.ts +79 -0
- package/src/lib/discover-ping.ts +141 -0
- package/src/lib/discover.ts +437 -0
- package/src/lib/env.ts +134 -0
- package/src/lib/errors.ts +33 -0
- package/src/lib/feed-policy.ts +236 -2
- package/src/lib/feed.ts +926 -73
- package/src/lib/filter-dimensions.ts +1349 -0
- package/src/lib/github-sync-site-config.ts +3 -0
- package/src/lib/hosted-signin.ts +1 -1
- package/src/lib/http-cache.ts +148 -0
- package/src/lib/hugo-markdown.ts +16 -0
- package/src/lib/icons.ts +9 -2
- package/src/lib/ids.ts +3 -0
- package/src/lib/jant-docs.ts +42 -0
- package/src/lib/lang-detect.ts +308 -0
- package/src/lib/media-helpers.ts +13 -1
- package/src/lib/navigation.ts +78 -11
- package/src/lib/pagination.ts +28 -24
- package/src/lib/per-language-surfaces.ts +67 -0
- package/src/lib/post-meta.ts +19 -0
- package/src/lib/render.tsx +55 -7
- package/src/lib/resolve-config.ts +53 -5
- package/src/lib/schemas.ts +201 -10
- package/src/lib/site-header-fragment.tsx +2 -1
- package/src/lib/site-unavailable-page.ts +47 -0
- package/src/lib/slug.ts +51 -7
- package/src/lib/slugify.ts +113 -0
- package/src/lib/startup-config.ts +4 -6
- package/src/lib/storage.ts +7 -0
- package/src/lib/summary.ts +50 -0
- package/src/lib/thread-fold.ts +161 -0
- package/src/lib/time.ts +32 -0
- package/src/lib/timeline.ts +42 -1
- package/src/lib/tiptap-render.ts +1 -2
- package/src/lib/upload.ts +16 -13
- package/src/lib/url.ts +139 -86
- package/src/lib/version.ts +10 -8
- package/src/lib/view-language.ts +436 -0
- package/src/lib/view.ts +51 -23
- package/src/lib/viewer-context.ts +62 -0
- package/src/middleware/__tests__/auth.test.ts +70 -2
- package/src/middleware/__tests__/cache-control.test.ts +71 -3
- package/src/middleware/__tests__/onboarding.test.ts +76 -5
- package/src/middleware/__tests__/secure-headers.test.ts +1 -1
- package/src/middleware/__tests__/session.test.ts +181 -33
- package/src/middleware/auth.ts +50 -31
- package/src/middleware/cache-control.ts +75 -10
- package/src/middleware/config.ts +6 -6
- package/src/middleware/error-handler.ts +12 -0
- package/src/middleware/onboarding.ts +32 -10
- package/src/middleware/secure-headers.ts +1 -1
- package/src/middleware/session.ts +96 -8
- package/src/node/__tests__/cli-migrate.test.ts +21 -19
- package/src/node/__tests__/cli-reset-password.test.ts +81 -8
- package/src/node/__tests__/cli-runtime-target.test.ts +48 -1
- package/src/node/__tests__/cli-site-selection.test.ts +128 -38
- package/src/node/__tests__/runtime.test.ts +37 -0
- package/src/node/index.ts +1 -0
- package/src/preset.css +76 -22
- package/src/routes/__tests__/feed-validator.test.ts +156 -0
- package/src/routes/api/__tests__/collections.test.ts +114 -0
- package/src/routes/api/__tests__/discover.test.ts +222 -0
- package/src/routes/api/__tests__/nav-items.test.ts +212 -2
- package/src/routes/api/__tests__/post-translations.test.ts +829 -0
- package/src/routes/api/__tests__/settings.test.ts +24 -3
- package/src/routes/api/__tests__/telegram.test.ts +6 -5
- package/src/routes/api/collections.ts +49 -6
- package/src/routes/api/custom-urls.ts +0 -1
- package/src/routes/api/discover.ts +95 -0
- package/src/routes/api/export.ts +3 -0
- package/src/routes/api/internal/__tests__/sites.test.ts +42 -2
- package/src/routes/api/nav-items.ts +55 -8
- package/src/routes/api/posts.ts +159 -0
- package/src/routes/api/public/__tests__/archive.test.ts +111 -0
- package/src/routes/api/public/archive.ts +77 -81
- package/src/routes/api/public/posts.ts +23 -6
- package/src/routes/api/smart-collections.ts +132 -0
- package/src/routes/api/telegram.ts +2 -40
- package/src/routes/api/uploads.ts +1 -2
- package/src/routes/auth/__tests__/setup-auth.test.ts +137 -0
- package/src/routes/auth/__tests__/setup-discover.test.ts +204 -0
- package/src/routes/auth/__tests__/setup-flow.test.ts +270 -0
- package/src/routes/auth/__tests__/setup-page.test.tsx +329 -0
- package/src/routes/auth/__tests__/setup-steps.test.ts +310 -0
- package/src/routes/auth/__tests__/setup.test.ts +278 -26
- package/src/routes/auth/__tests__/signin.test.ts +135 -0
- package/src/routes/auth/setup.tsx +934 -186
- package/src/routes/auth/signin.tsx +10 -8
- package/src/routes/compose.tsx +5 -0
- package/src/routes/dash/__tests__/custom-urls-archive.test.ts +44 -0
- package/src/routes/dash/__tests__/custom-urls-page.test.ts +49 -0
- package/src/routes/dash/__tests__/delete-account.test.ts +106 -0
- package/src/routes/dash/__tests__/settings-discover.test.ts +213 -0
- package/src/routes/dash/custom-urls.tsx +1 -37
- package/src/routes/dash/settings.tsx +502 -41
- package/src/routes/discover-announce.ts +96 -0
- package/src/routes/feed/__tests__/feed.test.ts +165 -2
- package/src/routes/feed/feed.ts +69 -40
- package/src/routes/feed/sitemap.ts +95 -11
- package/src/routes/pages/__tests__/archive-indexing.test.ts +200 -0
- package/src/routes/pages/__tests__/archive-params.test.ts +370 -6
- package/src/routes/pages/__tests__/collection-routing.test.ts +16 -0
- package/src/routes/pages/__tests__/collections-feed-links.test.ts +72 -0
- package/src/routes/pages/__tests__/collections.test.ts +9 -3
- package/src/routes/pages/__tests__/custom-archive-url.test.ts +119 -0
- package/src/routes/pages/__tests__/feed-autodiscovery.test.ts +148 -0
- package/src/routes/pages/__tests__/language-routing.test.ts +679 -0
- package/src/routes/pages/__tests__/post-preview-partial.test.ts +96 -0
- package/src/routes/pages/__tests__/smart-collection.test.ts +298 -0
- package/src/routes/pages/__tests__/subscribe.test.ts +248 -0
- package/src/routes/pages/archive.tsx +471 -369
- package/src/routes/pages/collection.tsx +94 -96
- package/src/routes/pages/collections.tsx +38 -50
- package/src/routes/pages/featured.tsx +32 -13
- package/src/routes/pages/home.tsx +25 -6
- package/src/routes/pages/language.tsx +113 -0
- package/src/routes/pages/latest.tsx +26 -16
- package/src/routes/pages/new.tsx +3 -0
- package/src/routes/pages/page.tsx +178 -17
- package/src/routes/pages/partials.tsx +41 -0
- package/src/routes/pages/search.tsx +18 -3
- package/src/routes/pages/smart-collection.tsx +340 -0
- package/src/routes/pages/subscribe.tsx +182 -0
- package/src/runtime/__tests__/index.test.ts +19 -0
- package/src/runtime/__tests__/node.test.ts +129 -4
- package/src/runtime/cloudflare.ts +21 -2
- package/src/runtime/index.ts +27 -1
- package/src/runtime/node.ts +18 -1
- package/src/runtime/site.ts +95 -24
- package/src/services/__tests__/auth.test.ts +116 -7
- package/src/services/__tests__/collection.test.ts +108 -4
- package/src/services/__tests__/language.test.ts +495 -0
- package/src/services/__tests__/navigation.test.ts +213 -10
- package/src/services/__tests__/path.test.ts +180 -0
- package/src/services/__tests__/post-language.test.ts +830 -0
- package/src/services/__tests__/post.test.ts +46 -9
- package/src/services/__tests__/settings.test.ts +228 -17
- package/src/services/__tests__/site-admin.test.ts +5 -5
- package/src/services/__tests__/smart-collection.test.ts +651 -0
- package/src/services/about-page.ts +22 -1
- package/src/services/auth.ts +51 -49
- package/src/services/bootstrap.ts +188 -38
- package/src/services/collection-directory-position.ts +76 -0
- package/src/services/collection.ts +331 -46
- package/src/services/custom-url.ts +27 -22
- package/src/services/export-theme/assets/client-site.css +1 -1
- package/src/services/export-theme/assets/client-site.js +123 -123
- package/src/services/export-theme/layouts/_default/rss.xml +77 -1
- package/src/services/export-theme/layouts/partials/feed-post-content.xml +105 -2
- package/src/services/export-theme/layouts/partials/media-gallery.html +35 -21
- package/src/services/export-theme/layouts/partials/pagination.html +14 -13
- package/src/services/export-theme/layouts/partials/post-card.html +8 -4
- package/src/services/export-theme/layouts/partials/reply.html +2 -1
- package/src/services/export-theme/layouts/partials/thread-preview.html +40 -30
- package/src/services/export-theme/styles/main.css +13 -1
- package/src/services/export.ts +278 -19
- package/src/services/index.ts +34 -3
- package/src/services/language.ts +412 -0
- package/src/services/mcp.ts +3 -1
- package/src/services/media.ts +14 -6
- package/src/services/navigation.ts +429 -67
- package/src/services/path.ts +221 -6
- package/src/services/post.ts +1021 -152
- package/src/services/search.ts +39 -2
- package/src/services/settings.ts +238 -43
- package/src/services/site-admin.ts +24 -7
- package/src/services/site.ts +77 -1
- package/src/services/smart-collection.ts +636 -0
- package/src/services/telegram.ts +20 -22
- package/src/services/upload-session.ts +1 -3
- package/src/style-author.css +27 -0
- package/src/styles/components-author.css +1622 -0
- package/src/styles/components.css +24 -1571
- package/src/styles/site-media.css +16 -2
- package/src/styles/tokens.css +82 -12
- package/src/styles/ui-author.css +7602 -0
- package/src/styles/ui.css +1087 -7219
- package/src/types/app-context.ts +7 -0
- package/src/types/bindings.ts +3 -0
- package/src/types/config.ts +94 -15
- package/src/types/constants.ts +188 -16
- package/src/types/entities.ts +87 -1
- package/src/types/operations.ts +64 -2
- package/src/types/props.ts +157 -31
- package/src/types/views.ts +55 -1
- package/src/ui/__tests__/font-themes.test.ts +52 -12
- package/src/ui/compose/ComposeDialog.tsx +201 -7
- package/src/ui/compose/ComposePrompt.tsx +1 -5
- package/src/ui/compose/__tests__/ComposeDialog.test.tsx +125 -0
- package/src/ui/dash/appearance/AdvancedContent.tsx +2 -2
- package/src/ui/dash/appearance/CodeInjectionContent.tsx +12 -16
- package/src/ui/dash/appearance/NavigationContent.tsx +117 -16
- package/src/ui/dash/appearance/__tests__/NavigationContent.test.tsx +33 -11
- package/src/ui/dash/appearance/__tests__/system-nav-descriptions.test.ts +44 -0
- package/src/ui/dash/appearance/system-nav-descriptions.ts +75 -0
- package/src/ui/dash/settings/AccountMenuContent.tsx +2 -2
- package/src/ui/dash/settings/ApiTokensContent.tsx +2 -1
- package/src/ui/dash/settings/ConfigEditorContent.tsx +35 -16
- package/src/ui/dash/settings/GeneralContent.tsx +275 -113
- package/src/ui/dash/settings/LanguageContent.tsx +409 -0
- package/src/ui/dash/settings/SettingsRootContent.tsx +19 -1
- package/src/ui/dash/settings/__tests__/GeneralContent.test.tsx +324 -4
- package/src/ui/dash/settings/__tests__/LanguageContent.test.tsx +144 -0
- package/src/ui/dash/settings/__tests__/discover-copy.test.ts +66 -0
- package/src/ui/dash/settings/discover-copy.ts +116 -0
- package/src/ui/feed/LinkCard.tsx +55 -45
- package/src/ui/feed/NoteCard.tsx +9 -4
- package/src/ui/feed/PostStatusBadges.tsx +90 -43
- package/src/ui/feed/QuoteCard.tsx +55 -30
- package/src/ui/feed/ThreadPreview.tsx +6 -2
- package/src/ui/feed/__tests__/thread-preview.test.ts +13 -16
- package/src/ui/feed/__tests__/timeline-cards.test.ts +314 -49
- package/src/ui/feed/thread-preview-state.ts +20 -6
- package/src/ui/font-themes.ts +39 -29
- package/src/ui/layouts/BaseLayout.tsx +155 -10
- package/src/ui/layouts/SiteLayout.tsx +192 -34
- package/src/ui/layouts/__tests__/BaseLayout.test.tsx +196 -17
- package/src/ui/layouts/__tests__/SiteLayout.test.tsx +109 -85
- package/src/ui/pages/ArchivePage.tsx +282 -289
- package/src/ui/pages/CollectionPage.tsx +86 -76
- package/src/ui/pages/CollectionsPage.tsx +5 -0
- package/src/ui/pages/ComposePage.tsx +8 -0
- package/src/ui/pages/PostPage.tsx +47 -0
- package/src/ui/pages/SearchPage.tsx +3 -3
- package/src/ui/pages/SmartCollectionPage.tsx +434 -0
- package/src/ui/pages/SubscribePage.tsx +236 -0
- package/src/ui/pages/__tests__/ArchivePage.test.tsx +65 -9
- package/src/ui/pages/__tests__/collections-directory-rows.test.tsx +92 -0
- package/src/ui/pages/__tests__/collections-view-links.test.tsx +81 -0
- package/src/ui/shared/CollectionDirectory.tsx +178 -3
- package/src/ui/shared/CollectionsManager.tsx +70 -17
- package/src/ui/shared/CopyField.tsx +127 -0
- package/src/ui/shared/EmptyPostContent.tsx +23 -0
- package/src/ui/shared/MediaGallery.tsx +125 -46
- package/src/ui/shared/Pagination.tsx +20 -5
- package/src/ui/shared/PostFooter.tsx +20 -11
- package/src/ui/shared/__tests__/archive-labels.test.ts +100 -0
- package/src/ui/shared/__tests__/media-gallery.test.ts +210 -2
- package/src/ui/shared/__tests__/navigation-labels.test.ts +16 -22
- package/src/ui/shared/__tests__/pagination.test.ts +38 -24
- package/src/ui/shared/__tests__/post-footer.test.ts +32 -0
- package/src/ui/shared/archive-labels.ts +98 -0
- package/src/ui/shared/collection-management-labels.ts +94 -16
- package/src/ui/shared/navigation-labels.ts +45 -71
- package/src/ui/shared/post-article-attributes.ts +2 -0
- package/src/ui/shared/smart-collection-labels.ts +343 -0
- package/dist/app-C75Zc8dD.js +0 -6
- package/dist/client/_assets/chunks/heic-to-DUUaO23q.js +0 -1
- package/dist/client/_assets/chunks/module-DcsAZQZ_.js +0 -716
- package/dist/client/_assets/chunks/url-CU9pEbk5.js +0 -1
- package/dist/client/_assets/client-Bq0vre8Y.js +0 -296
- package/dist/client/_assets/client-D3VZyG4L.css +0 -2
- package/dist/client/_assets/client-auth-F2rb9WfF.js +0 -5571
- package/dist/env-BPYViDJJ.js +0 -281
- package/dist/github-api-BNF35Lkx.js +0 -176
- package/dist/github-app-DdiD-bC4.js +0 -275
- package/dist/github-sync-Bqg62IvV.js +0 -4
- package/dist/github-sync-HdK2EgvJ.js +0 -431
- package/dist/url-CbLAtlZe.js +0 -900
- package/src/client/__tests__/collection-created-notice.test.ts +0 -36
- package/src/client/__tests__/collection-form-bridge.test.ts +0 -216
- package/src/client/__tests__/post-form-bridge.test.ts +0 -82
- package/src/client/collection-created-notice.ts +0 -66
- package/src/client/collection-form-bridge.ts +0 -191
- package/src/client/components/__tests__/jant-post-form.test.ts +0 -193
- package/src/client/components/jant-post-form.ts +0 -422
- package/src/client/components/post-form-template.ts +0 -352
- package/src/client/components/post-form-types.ts +0 -96
- package/src/client/media-metadata.ts +0 -247
- package/src/client/post-form-bridge.ts +0 -193
- package/src/ui/pages/CollectionEditorPage.tsx +0 -175
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { msg } from "@lingui/core/macro";
|
|
2
|
+
import type { I18n } from "../../i18n/i18n.js";
|
|
3
|
+
import type {
|
|
4
|
+
DimensionContext,
|
|
5
|
+
PostFilterSelection,
|
|
6
|
+
} from "../../lib/filter-dimensions.js";
|
|
7
|
+
import {
|
|
8
|
+
describeFilterSelection,
|
|
9
|
+
hasFilterSelection,
|
|
10
|
+
} from "../../lib/filter-dimensions.js";
|
|
11
|
+
|
|
12
|
+
type Translator = Pick<I18n, "_">;
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
getFormatLabelPlural,
|
|
16
|
+
getMediaKindLabel,
|
|
17
|
+
getVisibilityLabel,
|
|
18
|
+
} from "../../lib/filter-dimensions.js";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The name of the unfiltered archive, shared by the page heading and the
|
|
22
|
+
* document title so both resolve to one Lingui hash and can never drift into
|
|
23
|
+
* two different words for the same surface.
|
|
24
|
+
*/
|
|
25
|
+
export const ARCHIVE_ALL_POSTS_LABEL = msg({
|
|
26
|
+
message: "All posts",
|
|
27
|
+
comment:
|
|
28
|
+
"@context: Archive page heading and document title when no filter is active. Names the surface, not the current selection — the nav calls the same destination 'All'.",
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
/** Whether any filter dimension is active. `sort` and `layout` are not filters. */
|
|
32
|
+
export function hasActiveArchiveFilter(
|
|
33
|
+
selection: PostFilterSelection,
|
|
34
|
+
): boolean {
|
|
35
|
+
return hasFilterSelection(selection);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The active filters reduced to the words a reader sees, most identifying
|
|
40
|
+
* first.
|
|
41
|
+
*
|
|
42
|
+
* The words themselves come from the dimension registry, which owns the
|
|
43
|
+
* vocabulary. What lives here is the archive's *composition* of them: the
|
|
44
|
+
* ordering, and the one place a dimension absorbs another.
|
|
45
|
+
*
|
|
46
|
+
* This is the vocabulary only — every surface composes it differently, because
|
|
47
|
+
* their constraints are opposite. A feed name lives for years in someone's
|
|
48
|
+
* reader with no UI to inspect it, so it takes the whole list; a browser tab
|
|
49
|
+
* truncates from the right, so it takes the first two and stops. The registry
|
|
50
|
+
* order is what makes that truncation safe: a collection title identifies a view
|
|
51
|
+
* far better than one of three format names, so it leads.
|
|
52
|
+
*
|
|
53
|
+
* @param selection - Active filter selection
|
|
54
|
+
* @param i18n - Translator
|
|
55
|
+
* @param ctx - Collection vocabulary, for naming a selected collection
|
|
56
|
+
* @returns Labels in priority order; empty when nothing is filtered
|
|
57
|
+
* @example
|
|
58
|
+
* describeArchiveFilters({ format: "quote" }, i18n, {}); // ["Quotes"]
|
|
59
|
+
*/
|
|
60
|
+
export function describeArchiveFilters(
|
|
61
|
+
selection: PostFilterSelection,
|
|
62
|
+
i18n: Translator,
|
|
63
|
+
ctx: DimensionContext = {},
|
|
64
|
+
): string[] {
|
|
65
|
+
// Title presence absorbs the format it refines, mirroring the filter chip —
|
|
66
|
+
// `Untitled` says everything `Notes, without title` would. The registry lists
|
|
67
|
+
// `format` immediately before `title`, so dropping one leaves the other in
|
|
68
|
+
// exactly the right place.
|
|
69
|
+
const composed =
|
|
70
|
+
selection.title !== undefined
|
|
71
|
+
? { ...selection, format: undefined }
|
|
72
|
+
: selection;
|
|
73
|
+
return describeFilterSelection(composed, i18n, ctx);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** How many parts a browser tab can carry before it truncates to noise. */
|
|
77
|
+
const TITLE_PART_LIMIT = 2;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Name for a filtered archive view where no surrounding UI explains it —
|
|
81
|
+
* a browser tab, a bookmark, a shared link's preview.
|
|
82
|
+
*
|
|
83
|
+
* @param selection - Active filter selection
|
|
84
|
+
* @param i18n - Translator
|
|
85
|
+
* @param ctx - Collection vocabulary, for naming a selected collection
|
|
86
|
+
* @returns Capped description, or the unfiltered name when nothing is filtered
|
|
87
|
+
* @example
|
|
88
|
+
* getArchiveViewTitle({ year: 2024 }, i18n, {}); // "2024"
|
|
89
|
+
*/
|
|
90
|
+
export function getArchiveViewTitle(
|
|
91
|
+
selection: PostFilterSelection,
|
|
92
|
+
i18n: Translator,
|
|
93
|
+
ctx: DimensionContext = {},
|
|
94
|
+
): string {
|
|
95
|
+
const parts = describeArchiveFilters(selection, i18n, ctx);
|
|
96
|
+
if (parts.length === 0) return i18n._(ARCHIVE_ALL_POSTS_LABEL);
|
|
97
|
+
return parts.slice(0, TITLE_PART_LIMIT).join(", ");
|
|
98
|
+
}
|
|
@@ -55,6 +55,28 @@ const collectionFormMessages = {
|
|
|
55
55
|
message: "Collection created.",
|
|
56
56
|
comment: "@context: Confirmation shown after creating a collection",
|
|
57
57
|
}),
|
|
58
|
+
cancelLabel: msg({
|
|
59
|
+
message: "Cancel",
|
|
60
|
+
comment: "@context: Button to cancel form",
|
|
61
|
+
}),
|
|
62
|
+
} as const;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The editing dialog's own strings.
|
|
66
|
+
*
|
|
67
|
+
* The address and validation wording it shares with the quick-create form
|
|
68
|
+
* stays in {@link collectionFormMessages}; only what the dialog alone says
|
|
69
|
+
* lives here.
|
|
70
|
+
*/
|
|
71
|
+
const collectionDialogMessages = {
|
|
72
|
+
createHeading: msg({
|
|
73
|
+
message: "New Collection",
|
|
74
|
+
comment: "@context: Title of the dialog that creates a collection",
|
|
75
|
+
}),
|
|
76
|
+
editHeading: msg({
|
|
77
|
+
message: "Edit Collection",
|
|
78
|
+
comment: "@context: Title of the dialog that edits an existing collection",
|
|
79
|
+
}),
|
|
58
80
|
descriptionLabel: msg({
|
|
59
81
|
message: "Description (optional)",
|
|
60
82
|
comment: "@context: Collection form field",
|
|
@@ -63,9 +85,9 @@ const collectionFormMessages = {
|
|
|
63
85
|
message: "What's this collection about?",
|
|
64
86
|
comment: "@context: Collection description placeholder",
|
|
65
87
|
}),
|
|
66
|
-
|
|
67
|
-
message: "
|
|
68
|
-
comment: "@context: Collection
|
|
88
|
+
orderBy: msg({
|
|
89
|
+
message: "Order by",
|
|
90
|
+
comment: "@context: Collection editing dialog field",
|
|
69
91
|
}),
|
|
70
92
|
sortNewest: msg({
|
|
71
93
|
message: "Newest first",
|
|
@@ -79,17 +101,40 @@ const collectionFormMessages = {
|
|
|
79
101
|
message: "Highest rated",
|
|
80
102
|
comment: "@context: Collection sort order option",
|
|
81
103
|
}),
|
|
82
|
-
|
|
83
|
-
message: "
|
|
84
|
-
comment: "@context:
|
|
104
|
+
loadFailed: msg({
|
|
105
|
+
message: "Could not open this collection. Try again.",
|
|
106
|
+
comment: "@context: Collection dialog load failure",
|
|
85
107
|
}),
|
|
86
|
-
|
|
87
|
-
message: "
|
|
88
|
-
comment: "@context:
|
|
108
|
+
titleAndLinkRequired: msg({
|
|
109
|
+
message: "A collection needs a title and a link.",
|
|
110
|
+
comment: "@context: Collection dialog validation message",
|
|
111
|
+
}),
|
|
112
|
+
} as const;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Address wording both editing dialogs share.
|
|
116
|
+
*
|
|
117
|
+
* A collection and a smart collection take the same kind of address out of the
|
|
118
|
+
* same namespace, so a clash and a move read the same in both.
|
|
119
|
+
*/
|
|
120
|
+
const collectionLinkMessages = {
|
|
121
|
+
linkTaken: msg({
|
|
122
|
+
message: "This link is taken. Choose another.",
|
|
123
|
+
comment:
|
|
124
|
+
"@context: Collection editing dialog — the typed collection link is already in use",
|
|
125
|
+
}),
|
|
126
|
+
linkMovesWarning: msg({
|
|
127
|
+
message: "Changing the link breaks the old one immediately.",
|
|
128
|
+
comment:
|
|
129
|
+
"@context: Collection editing dialog warning shown when editing moves an existing collection link",
|
|
89
130
|
}),
|
|
90
131
|
} as const;
|
|
91
132
|
|
|
92
133
|
const collectionMutationMessages = {
|
|
134
|
+
save: msg({
|
|
135
|
+
message: "Save",
|
|
136
|
+
comment: "@context: Button to save collection",
|
|
137
|
+
}),
|
|
93
138
|
edit: msg({
|
|
94
139
|
message: "Edit",
|
|
95
140
|
comment: "@context: Per-collection edit action",
|
|
@@ -222,17 +267,50 @@ export const getCollectionFormLabels = (i18n: Translator) => ({
|
|
|
222
267
|
quickHint: i18n._(collectionFormMessages.quickHint),
|
|
223
268
|
quickSubmitLabel: i18n._(collectionFormMessages.quickSubmitLabel),
|
|
224
269
|
createdLabel: i18n._(collectionFormMessages.createdLabel),
|
|
225
|
-
descriptionLabel: i18n._(collectionFormMessages.descriptionLabel),
|
|
226
|
-
descriptionPlaceholder: i18n._(collectionFormMessages.descriptionPlaceholder),
|
|
227
|
-
sortOrderLabel: i18n._(collectionFormMessages.sortOrderLabel),
|
|
228
|
-
sortNewest: i18n._(collectionFormMessages.sortNewest),
|
|
229
|
-
sortOldest: i18n._(collectionFormMessages.sortOldest),
|
|
230
|
-
sortRatingDesc: i18n._(collectionFormMessages.sortRatingDesc),
|
|
231
|
-
submitLabel: i18n._(collectionFormMessages.submitLabel),
|
|
232
270
|
cancelLabel: i18n._(collectionFormMessages.cancelLabel),
|
|
233
271
|
});
|
|
234
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Every string the editing dialog renders, translated on the server.
|
|
275
|
+
*
|
|
276
|
+
* The dialog is a Lit component and cannot reach the i18n catalogs itself, so
|
|
277
|
+
* whichever page can open it hands them down \u2014 the same arrangement the
|
|
278
|
+
* smart collection dialog uses.
|
|
279
|
+
*/
|
|
280
|
+
export const getCollectionDialogLabels = (i18n: Translator) => ({
|
|
281
|
+
createHeading: i18n._(collectionDialogMessages.createHeading),
|
|
282
|
+
editHeading: i18n._(collectionDialogMessages.editHeading),
|
|
283
|
+
title: i18n._(collectionFormMessages.titleLabel),
|
|
284
|
+
titlePlaceholder: i18n._(collectionFormMessages.titlePlaceholder),
|
|
285
|
+
link: i18n._(collectionFormMessages.slugLabel),
|
|
286
|
+
linkHelp: i18n._(collectionFormMessages.slugHelp),
|
|
287
|
+
editLink: i18n._(collectionFormMessages.editSlugLabel),
|
|
288
|
+
resetLink: i18n._(collectionFormMessages.resetSlugLabel),
|
|
289
|
+
linkInvalid: i18n._(collectionFormMessages.slugInvalidHelp),
|
|
290
|
+
linkReserved: i18n._(collectionFormMessages.slugReservedHelp),
|
|
291
|
+
linkTooLong: i18n._(collectionFormMessages.slugTooLongHelp),
|
|
292
|
+
linkTaken: i18n._(collectionLinkMessages.linkTaken),
|
|
293
|
+
linkMovesWarning: i18n._(collectionLinkMessages.linkMovesWarning),
|
|
294
|
+
description: i18n._(collectionDialogMessages.descriptionLabel),
|
|
295
|
+
descriptionPlaceholder: i18n._(
|
|
296
|
+
collectionDialogMessages.descriptionPlaceholder,
|
|
297
|
+
),
|
|
298
|
+
orderBy: i18n._(collectionDialogMessages.orderBy),
|
|
299
|
+
sortOptions: {
|
|
300
|
+
newest: i18n._(collectionDialogMessages.sortNewest),
|
|
301
|
+
oldest: i18n._(collectionDialogMessages.sortOldest),
|
|
302
|
+
rating_desc: i18n._(collectionDialogMessages.sortRatingDesc),
|
|
303
|
+
},
|
|
304
|
+
cancel: i18n._(collectionMutationMessages.cancel),
|
|
305
|
+
save: i18n._(collectionMutationMessages.save),
|
|
306
|
+
saved: i18n._(collectionMutationMessages.saved),
|
|
307
|
+
saveFailed: i18n._(collectionMutationMessages.saveFailed),
|
|
308
|
+
loadFailed: i18n._(collectionDialogMessages.loadFailed),
|
|
309
|
+
titleAndLinkRequired: i18n._(collectionDialogMessages.titleAndLinkRequired),
|
|
310
|
+
});
|
|
311
|
+
|
|
235
312
|
export const getCollectionMutationLabels = (i18n: Translator) => ({
|
|
313
|
+
save: i18n._(collectionMutationMessages.save),
|
|
236
314
|
edit: i18n._(collectionMutationMessages.edit),
|
|
237
315
|
addToNavigation: i18n._(collectionMutationMessages.addToNavigation),
|
|
238
316
|
addingToNavigation: i18n._(collectionMutationMessages.addingToNavigation),
|
|
@@ -11,6 +11,7 @@ type NavigationLabelItem = {
|
|
|
11
11
|
systemKey?: SystemNavKey;
|
|
12
12
|
label: string;
|
|
13
13
|
url: string;
|
|
14
|
+
targetTitle?: string;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
// `context: "nav"` gives these site-header labels a distinct Lingui hash so
|
|
@@ -35,9 +36,10 @@ const BUILTIN_NAV_LABELS = {
|
|
|
35
36
|
comment: "@context: Built-in navigation label for the collections page",
|
|
36
37
|
}),
|
|
37
38
|
archive: msg({
|
|
38
|
-
message: "
|
|
39
|
+
message: "All",
|
|
39
40
|
context: "nav",
|
|
40
|
-
comment:
|
|
41
|
+
comment:
|
|
42
|
+
"@context: Built-in navigation label for the archive page. Reads as the widest of Featured / Latest / All rather than 'old posts' — the page is the complete index, and its URL stays /archive.",
|
|
41
43
|
}),
|
|
42
44
|
settings: msg({
|
|
43
45
|
message: "Settings",
|
|
@@ -45,9 +47,16 @@ const BUILTIN_NAV_LABELS = {
|
|
|
45
47
|
comment: "@context: Built-in navigation label for settings",
|
|
46
48
|
}),
|
|
47
49
|
rss: msg({
|
|
48
|
-
message: "
|
|
50
|
+
message: "RSS",
|
|
51
|
+
context: "nav",
|
|
52
|
+
comment:
|
|
53
|
+
"@context: Built-in navigation label for the feed. Keep the acronym in every locale — it is what readers scan for. The document /feed serves is Atom, but RSS is the category name readers and feed apps use, and it matches the vocabulary the rest of the product already speaks (systemKey `rss`, `mainRssFeed`). 'Feed' would collide with Featured/Latest/All, which are feeds too.",
|
|
54
|
+
}),
|
|
55
|
+
subscribe: msg({
|
|
56
|
+
message: "Subscribe",
|
|
49
57
|
context: "nav",
|
|
50
|
-
comment:
|
|
58
|
+
comment:
|
|
59
|
+
"@context: Built-in navigation label for the page that explains the site's feeds. Names what the reader wants to do, unlike the sibling RSS entry which names the format and links at the Atom document itself.",
|
|
51
60
|
}),
|
|
52
61
|
signIn: msg({
|
|
53
62
|
message: "Sign in",
|
|
@@ -70,42 +79,21 @@ const BUILTIN_NAV_LABELS = {
|
|
|
70
79
|
*/
|
|
71
80
|
export const NAV_MORE_LABEL = BUILTIN_NAV_LABELS.more;
|
|
72
81
|
|
|
73
|
-
|
|
82
|
+
/**
|
|
83
|
+
* The default label for every system nav entry.
|
|
84
|
+
*
|
|
85
|
+
* Total on purpose: this is the map both the settings toggle list and the
|
|
86
|
+
* rendered navigation read, so a new `SystemNavKey` without an entry here is a
|
|
87
|
+
* compile error rather than a nav item that renders blank.
|
|
88
|
+
*/
|
|
89
|
+
const SYSTEM_NAV_TITLES: Record<SystemNavKey, MessageDescriptor> = {
|
|
74
90
|
latest: BUILTIN_NAV_LABELS.latest,
|
|
75
91
|
featured: BUILTIN_NAV_LABELS.featured,
|
|
76
92
|
collections: BUILTIN_NAV_LABELS.collections,
|
|
77
93
|
archive: BUILTIN_NAV_LABELS.archive,
|
|
78
94
|
settings: BUILTIN_NAV_LABELS.settings,
|
|
79
95
|
rss: BUILTIN_NAV_LABELS.rss,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const SYSTEM_NAV_DESCRIPTIONS: Record<SystemNavKey, MessageDescriptor> = {
|
|
83
|
-
latest: msg({
|
|
84
|
-
message: "Link to your latest posts. Your homepage shows this feed.",
|
|
85
|
-
comment: "@context: Description for the latest system navigation toggle",
|
|
86
|
-
}),
|
|
87
|
-
featured: msg({
|
|
88
|
-
message: "Link to posts you've marked as featured.",
|
|
89
|
-
comment: "@context: Description for the featured system navigation toggle",
|
|
90
|
-
}),
|
|
91
|
-
rss: msg({
|
|
92
|
-
message:
|
|
93
|
-
"Add a link to your main RSS feed. Change what /feed returns in General.",
|
|
94
|
-
comment: "@context: Description for the RSS system navigation toggle",
|
|
95
|
-
}),
|
|
96
|
-
settings: msg({
|
|
97
|
-
message: "Shows 'Settings' when logged in, 'Sign in' when logged out",
|
|
98
|
-
comment: "@context: Description for the settings system navigation toggle",
|
|
99
|
-
}),
|
|
100
|
-
collections: msg({
|
|
101
|
-
message: "Link to your collections page",
|
|
102
|
-
comment:
|
|
103
|
-
"@context: Description for the collections system navigation toggle",
|
|
104
|
-
}),
|
|
105
|
-
archive: msg({
|
|
106
|
-
message: "Link to the post archive",
|
|
107
|
-
comment: "@context: Description for the archive system navigation toggle",
|
|
108
|
-
}),
|
|
96
|
+
subscribe: BUILTIN_NAV_LABELS.subscribe,
|
|
109
97
|
};
|
|
110
98
|
|
|
111
99
|
function getInternalNavPath(url: string, sitePathPrefix = ""): string | null {
|
|
@@ -133,26 +121,8 @@ function getBuiltinNavLabelDescriptor(
|
|
|
133
121
|
): MessageDescriptor | null {
|
|
134
122
|
if (item.type !== "system" || !item.systemKey) return null;
|
|
135
123
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (item.systemKey === "latest") {
|
|
141
|
-
return BUILTIN_NAV_LABELS.latest;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (item.systemKey === "featured") {
|
|
145
|
-
return BUILTIN_NAV_LABELS.featured;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (item.systemKey === "archive") {
|
|
149
|
-
return BUILTIN_NAV_LABELS.archive;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (item.systemKey === "rss") {
|
|
153
|
-
return BUILTIN_NAV_LABELS.rss;
|
|
154
|
-
}
|
|
155
|
-
|
|
124
|
+
// Settings is the one entry whose label depends on where it currently
|
|
125
|
+
// points, so it cannot be read from the key alone.
|
|
156
126
|
if (item.systemKey === "settings") {
|
|
157
127
|
const path = getInternalNavPath(item.url, sitePathPrefix);
|
|
158
128
|
return path === "/signin"
|
|
@@ -160,35 +130,39 @@ function getBuiltinNavLabelDescriptor(
|
|
|
160
130
|
: BUILTIN_NAV_LABELS.settings;
|
|
161
131
|
}
|
|
162
132
|
|
|
163
|
-
return null;
|
|
133
|
+
return SYSTEM_NAV_TITLES[item.systemKey] ?? null;
|
|
164
134
|
}
|
|
165
135
|
|
|
136
|
+
/**
|
|
137
|
+
* The text a nav item shows.
|
|
138
|
+
*
|
|
139
|
+
* A stored label is always the author's own words, so it wins outright. An
|
|
140
|
+
* empty one means the item follows what it points at: a built-in destination
|
|
141
|
+
* shows its translated default, a page or collection shows that row's current
|
|
142
|
+
* title — which is also how a nav entry ends up in the reader's language once
|
|
143
|
+
* a language view has resolved it to a translated page.
|
|
144
|
+
*
|
|
145
|
+
* @param item - Nav item, view or raw
|
|
146
|
+
* @param i18n - Translator for built-in destinations
|
|
147
|
+
* @param sitePathPrefix - Deployment path prefix, such as `/blog`
|
|
148
|
+
* @returns Label to render
|
|
149
|
+
*/
|
|
166
150
|
export function getNavItemDisplayLabel(
|
|
167
151
|
item: NavigationLabelItem,
|
|
168
152
|
i18n: Translator,
|
|
169
153
|
sitePathPrefix = "",
|
|
170
154
|
): string {
|
|
171
|
-
if (item.
|
|
172
|
-
|
|
173
|
-
// Empty label means "use the i18n-translated default".
|
|
174
|
-
if (item.label) {
|
|
175
|
-
return item.label;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
155
|
+
if (item.label) return item.label;
|
|
156
|
+
|
|
178
157
|
const descriptor = getBuiltinNavLabelDescriptor(item, sitePathPrefix);
|
|
179
|
-
|
|
180
|
-
}
|
|
158
|
+
if (descriptor) return i18n._(descriptor);
|
|
181
159
|
|
|
182
|
-
|
|
183
|
-
key: SystemNavKey,
|
|
184
|
-
i18n: Translator,
|
|
185
|
-
): string {
|
|
186
|
-
return i18n._(SYSTEM_NAV_TITLES[key] ?? BUILTIN_NAV_LABELS.rss);
|
|
160
|
+
return item.targetTitle?.trim() || item.label;
|
|
187
161
|
}
|
|
188
162
|
|
|
189
|
-
export function
|
|
163
|
+
export function getSystemNavDisplayLabel(
|
|
190
164
|
key: SystemNavKey,
|
|
191
165
|
i18n: Translator,
|
|
192
166
|
): string {
|
|
193
|
-
return i18n._(
|
|
167
|
+
return i18n._(SYSTEM_NAV_TITLES[key]);
|
|
194
168
|
}
|
|
@@ -13,6 +13,7 @@ type PostArticleAttributeSource = Pick<
|
|
|
13
13
|
| "pinnedInCollection"
|
|
14
14
|
| "featured"
|
|
15
15
|
| "draftTailId"
|
|
16
|
+
| "language"
|
|
16
17
|
>;
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -47,6 +48,7 @@ export function getPostArticleAttributes(post: PostArticleAttributeSource) {
|
|
|
47
48
|
? { "data-thread-draft-tail-id": post.draftTailId }
|
|
48
49
|
: {}),
|
|
49
50
|
"data-post-visibility": post.visibility,
|
|
51
|
+
...(post.language ? { "data-post-language": post.language } : {}),
|
|
50
52
|
...(isChildPost ? { "data-post-reply": "" } : {}),
|
|
51
53
|
};
|
|
52
54
|
}
|