@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
|
@@ -11,12 +11,29 @@ import { useLingui } from "../../i18n/context.js";
|
|
|
11
11
|
import type {
|
|
12
12
|
ArchivePageProps,
|
|
13
13
|
ArchiveFilters,
|
|
14
|
-
|
|
14
|
+
ArchiveLayout,
|
|
15
|
+
ArchiveSort,
|
|
15
16
|
ArchiveVisibility,
|
|
17
|
+
Format,
|
|
16
18
|
MediaKind,
|
|
17
19
|
} from "../../types.js";
|
|
18
20
|
import type { PostView } from "../../types/views.js";
|
|
19
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
ARCHIVE_VISIBILITIES,
|
|
23
|
+
FORMATS,
|
|
24
|
+
MEDIA_KINDS,
|
|
25
|
+
PUBLIC_ARCHIVE_VISIBILITIES,
|
|
26
|
+
} from "../../types.js";
|
|
27
|
+
import type {
|
|
28
|
+
DimensionContext,
|
|
29
|
+
FilterDimensionValues,
|
|
30
|
+
MediaSelection,
|
|
31
|
+
} from "../../lib/filter-dimensions.js";
|
|
32
|
+
import {
|
|
33
|
+
buildCollectionVocabulary,
|
|
34
|
+
FILTER_DIMENSIONS,
|
|
35
|
+
serializePostFilterSelection,
|
|
36
|
+
} from "../../lib/filter-dimensions.js";
|
|
20
37
|
import { getFeaturedIconSvg } from "../../lib/featured-icons.js";
|
|
21
38
|
import { getIconSvg } from "../../lib/icons.js";
|
|
22
39
|
import { toPublicPath } from "../../lib/url.js";
|
|
@@ -24,50 +41,60 @@ import { toMediaKind } from "../../lib/upload.js";
|
|
|
24
41
|
import { PagePagination } from "../shared/Pagination.js";
|
|
25
42
|
import { TimelineFeedItem } from "../feed/TimelineFeed.js";
|
|
26
43
|
import { DecorativeQuoteMark } from "../shared/DecorativeQuoteMark.js";
|
|
44
|
+
import {
|
|
45
|
+
ARCHIVE_ALL_POSTS_LABEL,
|
|
46
|
+
getFormatLabelPlural as getSharedFormatLabelPlural,
|
|
47
|
+
getMediaKindLabel as getSharedMediaKindLabel,
|
|
48
|
+
getVisibilityLabel as getSharedVisibilityLabel,
|
|
49
|
+
hasActiveArchiveFilter,
|
|
50
|
+
} from "../shared/archive-labels.js";
|
|
27
51
|
|
|
28
52
|
// =============================================================================
|
|
29
53
|
// URL Builder
|
|
30
54
|
// =============================================================================
|
|
31
55
|
|
|
56
|
+
/**
|
|
57
|
+
* One chip's edit to the current view.
|
|
58
|
+
*
|
|
59
|
+
* Dimensions are named exactly as the shared registry names them, so a chip
|
|
60
|
+
* cannot spell a filter the route is unable to read back. An explicit
|
|
61
|
+
* `undefined` clears a dimension, the same way spreading it does.
|
|
62
|
+
*/
|
|
63
|
+
type FilterUpdates = Partial<FilterDimensionValues> & {
|
|
64
|
+
layout?: ArchiveLayout;
|
|
65
|
+
sort?: ArchiveSort;
|
|
66
|
+
/** Drop every selection and return to the bare archive. */
|
|
67
|
+
clear?: boolean;
|
|
68
|
+
};
|
|
69
|
+
|
|
32
70
|
/** Build an archive URL preserving existing filter params, overriding with updates. */
|
|
33
71
|
function buildFilterUrl(
|
|
34
72
|
current: ArchiveFilters,
|
|
35
|
-
updates:
|
|
36
|
-
|
|
73
|
+
updates: FilterUpdates,
|
|
74
|
+
ctx: DimensionContext,
|
|
75
|
+
basePath = "",
|
|
37
76
|
): string {
|
|
38
|
-
if (updates.clear) return toPublicPath("/archive",
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
const params =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (merged.hasReplies !== undefined) {
|
|
55
|
-
params.set("replies", merged.hasReplies ? "any" : "none");
|
|
56
|
-
}
|
|
57
|
-
if (merged.visibility) {
|
|
58
|
-
// "hidden" is the URL spelling of the internal latest_hidden value
|
|
59
|
-
params.set(
|
|
60
|
-
"visibility",
|
|
61
|
-
merged.visibility === "latest_hidden" ? "hidden" : merged.visibility,
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
if (merged.view && merged.view !== "grid") params.set("view", merged.view);
|
|
65
|
-
if (merged.sort === "updated") params.set("sort", "updated");
|
|
77
|
+
if (updates.clear) return toPublicPath("/archive", basePath);
|
|
78
|
+
|
|
79
|
+
const { layout, sort, clear: _clear, ...selectionUpdates } = updates;
|
|
80
|
+
const params = serializePostFilterSelection(
|
|
81
|
+
{ ...current.selection, ...selectionUpdates },
|
|
82
|
+
ctx,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// Both layouts are written out in full. An absent `layout` means "whatever
|
|
86
|
+
// this site defaults to", so a link shared with a layout chosen keeps that
|
|
87
|
+
// layout even if the site default changes later. Only `layout` is ever
|
|
88
|
+
// emitted; the older `view` spelling is read-only now.
|
|
89
|
+
const mergedLayout = "layout" in updates ? layout : current.layout;
|
|
90
|
+
if (mergedLayout) params.set("layout", mergedLayout);
|
|
91
|
+
const mergedSort = "sort" in updates ? sort : current.sort;
|
|
92
|
+
if (mergedSort === "updated") params.set("sort", "updated");
|
|
66
93
|
|
|
67
94
|
const qs = params.toString();
|
|
68
95
|
return qs
|
|
69
|
-
? toPublicPath(`/archive?${qs}`,
|
|
70
|
-
: toPublicPath("/archive",
|
|
96
|
+
? toPublicPath(`/archive?${qs}`, basePath)
|
|
97
|
+
: toPublicPath("/archive", basePath);
|
|
71
98
|
}
|
|
72
99
|
|
|
73
100
|
// =============================================================================
|
|
@@ -99,29 +126,9 @@ function getFormatLabel(format: string): string {
|
|
|
99
126
|
return labels[format] ?? format;
|
|
100
127
|
}
|
|
101
128
|
|
|
102
|
-
function getFormatLabelPlural(format:
|
|
129
|
+
function getFormatLabelPlural(format: Format): string {
|
|
103
130
|
const { i18n } = useLingui();
|
|
104
|
-
|
|
105
|
-
note: i18n._(
|
|
106
|
-
msg({
|
|
107
|
-
message: "Notes",
|
|
108
|
-
comment: "@context: Post format label plural - notes",
|
|
109
|
-
}),
|
|
110
|
-
),
|
|
111
|
-
link: i18n._(
|
|
112
|
-
msg({
|
|
113
|
-
message: "Links",
|
|
114
|
-
comment: "@context: Post format label plural - links",
|
|
115
|
-
}),
|
|
116
|
-
),
|
|
117
|
-
quote: i18n._(
|
|
118
|
-
msg({
|
|
119
|
-
message: "Quotes",
|
|
120
|
-
comment: "@context: Post format label plural - quotes",
|
|
121
|
-
}),
|
|
122
|
-
),
|
|
123
|
-
};
|
|
124
|
-
return labels[format] ?? format + "s";
|
|
131
|
+
return getSharedFormatLabelPlural(format, i18n);
|
|
125
132
|
}
|
|
126
133
|
|
|
127
134
|
/** Icon name mapping for post formats. */
|
|
@@ -142,39 +149,21 @@ const MEDIA_KIND_ICONS: Record<MediaKind, string> = {
|
|
|
142
149
|
|
|
143
150
|
function getMediaKindLabel(kind: MediaKind): string {
|
|
144
151
|
const { i18n } = useLingui();
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
message: "Audio",
|
|
161
|
-
comment: "@context: Archive media filter - audio",
|
|
162
|
-
}),
|
|
163
|
-
),
|
|
164
|
-
text: i18n._(
|
|
165
|
-
msg({
|
|
166
|
-
message: "Text attachment",
|
|
167
|
-
comment: "@context: Archive media filter - text file attachments",
|
|
168
|
-
}),
|
|
169
|
-
),
|
|
170
|
-
document: i18n._(
|
|
171
|
-
msg({
|
|
172
|
-
message: "Files",
|
|
173
|
-
comment: "@context: Archive media filter - files/documents",
|
|
174
|
-
}),
|
|
175
|
-
),
|
|
176
|
-
};
|
|
177
|
-
return labels[kind] ?? kind;
|
|
152
|
+
return getSharedMediaKindLabel(kind, i18n);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* The kinds a media selection names, or none when it only asks about presence.
|
|
157
|
+
*
|
|
158
|
+
* `any`/`none` and a list of kinds are one value in the shared vocabulary; the
|
|
159
|
+
* chip's multi-select only has something to highlight in the list case.
|
|
160
|
+
*/
|
|
161
|
+
function selectedMediaKinds(
|
|
162
|
+
selection: MediaSelection | undefined,
|
|
163
|
+
): readonly MediaKind[] {
|
|
164
|
+
return selection === undefined || selection === "any" || selection === "none"
|
|
165
|
+
? []
|
|
166
|
+
: selection;
|
|
178
167
|
}
|
|
179
168
|
|
|
180
169
|
// =============================================================================
|
|
@@ -352,28 +341,25 @@ const ChipMediaSelect: FC<{
|
|
|
352
341
|
id: string;
|
|
353
342
|
icon: string;
|
|
354
343
|
filters: ArchiveFilters;
|
|
344
|
+
ctx: DimensionContext;
|
|
355
345
|
activeLabel?: string;
|
|
356
346
|
clearUrl: string;
|
|
357
|
-
|
|
358
|
-
}> = ({ id, icon, filters: f, activeLabel, clearUrl,
|
|
347
|
+
basePath?: string;
|
|
348
|
+
}> = ({ id, icon, filters: f, ctx, activeLabel, clearUrl, basePath = "" }) => {
|
|
359
349
|
const { i18n } = useLingui();
|
|
360
350
|
const isActive = !!activeLabel;
|
|
361
|
-
const activeKinds = f.
|
|
351
|
+
const activeKinds = selectedMediaKinds(f.selection.media);
|
|
362
352
|
|
|
363
353
|
const singleKind = activeKinds.length === 1 ? activeKinds[0] : undefined;
|
|
364
354
|
const activeMediaIcon = isActive
|
|
365
|
-
? f.
|
|
355
|
+
? f.selection.media === "none"
|
|
366
356
|
? "text"
|
|
367
357
|
: singleKind
|
|
368
358
|
? MEDIA_KIND_ICONS[singleKind]
|
|
369
359
|
: icon
|
|
370
360
|
: undefined;
|
|
371
361
|
|
|
372
|
-
const textOnlyUrl = buildFilterUrl(
|
|
373
|
-
{ ...f, mediaKinds: undefined, hasMedia: undefined },
|
|
374
|
-
{ hasMedia: false, mediaKinds: undefined },
|
|
375
|
-
sitePathPrefix,
|
|
376
|
-
);
|
|
362
|
+
const textOnlyUrl = buildFilterUrl(f, { media: "none" }, ctx, basePath);
|
|
377
363
|
const clearLabel = i18n._(
|
|
378
364
|
msg({
|
|
379
365
|
message: "Clear filter",
|
|
@@ -387,7 +373,7 @@ const ChipMediaSelect: FC<{
|
|
|
387
373
|
id={id}
|
|
388
374
|
class="archive-chip-select archive-chip-dropdown archive-chip-media select"
|
|
389
375
|
data-select-initialized
|
|
390
|
-
data-filter-key=
|
|
376
|
+
data-filter-key={FILTER_DIMENSIONS.media.url.param}
|
|
391
377
|
>
|
|
392
378
|
<button
|
|
393
379
|
type="button"
|
|
@@ -420,7 +406,7 @@ const ChipMediaSelect: FC<{
|
|
|
420
406
|
role="option"
|
|
421
407
|
data-value={textOnlyUrl}
|
|
422
408
|
data-navigate="true"
|
|
423
|
-
aria-selected={f.
|
|
409
|
+
aria-selected={f.selection.media === "none" ? "true" : undefined}
|
|
424
410
|
>
|
|
425
411
|
<span class="flex items-center gap-2">
|
|
426
412
|
<Icon name="text" class="[&>svg]:size-4 text-muted-foreground" />
|
|
@@ -487,12 +473,14 @@ const ToggleOption: FC<{
|
|
|
487
473
|
</a>
|
|
488
474
|
);
|
|
489
475
|
|
|
490
|
-
const
|
|
476
|
+
const LayoutToggle: FC<{
|
|
491
477
|
filters: ArchiveFilters;
|
|
492
|
-
|
|
493
|
-
|
|
478
|
+
ctx: DimensionContext;
|
|
479
|
+
defaultLayout: ArchiveLayout;
|
|
480
|
+
basePath?: string;
|
|
481
|
+
}> = ({ filters, ctx, defaultLayout, basePath = "" }) => {
|
|
494
482
|
const { i18n } = useLingui();
|
|
495
|
-
const
|
|
483
|
+
const currentLayout: ArchiveLayout = filters.layout ?? defaultLayout;
|
|
496
484
|
|
|
497
485
|
return (
|
|
498
486
|
<div
|
|
@@ -500,15 +488,15 @@ const ViewToggle: FC<{
|
|
|
500
488
|
role="radiogroup"
|
|
501
489
|
aria-label={i18n._(
|
|
502
490
|
msg({
|
|
503
|
-
message: "
|
|
491
|
+
message: "Layout",
|
|
504
492
|
comment: "@context: Archive grid/list toggle group label",
|
|
505
493
|
}),
|
|
506
494
|
)}
|
|
507
495
|
>
|
|
508
496
|
<ToggleOption
|
|
509
|
-
href={buildFilterUrl(filters, {
|
|
497
|
+
href={buildFilterUrl(filters, { layout: "grid" }, ctx, basePath)}
|
|
510
498
|
icon="layout-grid"
|
|
511
|
-
active={
|
|
499
|
+
active={currentLayout === "grid"}
|
|
512
500
|
label={i18n._(
|
|
513
501
|
msg({
|
|
514
502
|
message: "Show as a grid of tiles",
|
|
@@ -517,9 +505,9 @@ const ViewToggle: FC<{
|
|
|
517
505
|
)}
|
|
518
506
|
/>
|
|
519
507
|
<ToggleOption
|
|
520
|
-
href={buildFilterUrl(filters, {
|
|
508
|
+
href={buildFilterUrl(filters, { layout: "list" }, ctx, basePath)}
|
|
521
509
|
icon="list"
|
|
522
|
-
active={
|
|
510
|
+
active={currentLayout === "list"}
|
|
523
511
|
label={i18n._(
|
|
524
512
|
msg({
|
|
525
513
|
message: "Show as a list with full posts",
|
|
@@ -537,8 +525,9 @@ const ViewToggle: FC<{
|
|
|
537
525
|
*/
|
|
538
526
|
const SortToggle: FC<{
|
|
539
527
|
filters: ArchiveFilters;
|
|
540
|
-
|
|
541
|
-
|
|
528
|
+
ctx: DimensionContext;
|
|
529
|
+
basePath?: string;
|
|
530
|
+
}> = ({ filters, ctx, basePath = "" }) => {
|
|
542
531
|
const { i18n } = useLingui();
|
|
543
532
|
const sortsByActivity = filters.sort === "updated";
|
|
544
533
|
|
|
@@ -554,7 +543,7 @@ const SortToggle: FC<{
|
|
|
554
543
|
)}
|
|
555
544
|
>
|
|
556
545
|
<ToggleOption
|
|
557
|
-
href={buildFilterUrl(filters, { sort: undefined },
|
|
546
|
+
href={buildFilterUrl(filters, { sort: undefined }, ctx, basePath)}
|
|
558
547
|
icon="clock"
|
|
559
548
|
active={!sortsByActivity}
|
|
560
549
|
label={i18n._(
|
|
@@ -565,7 +554,7 @@ const SortToggle: FC<{
|
|
|
565
554
|
)}
|
|
566
555
|
/>
|
|
567
556
|
<ToggleOption
|
|
568
|
-
href={buildFilterUrl(filters, { sort: "updated" },
|
|
557
|
+
href={buildFilterUrl(filters, { sort: "updated" }, ctx, basePath)}
|
|
569
558
|
icon="history"
|
|
570
559
|
active={sortsByActivity}
|
|
571
560
|
label={i18n._(
|
|
@@ -584,43 +573,9 @@ const SortToggle: FC<{
|
|
|
584
573
|
// Filter Bar
|
|
585
574
|
// =============================================================================
|
|
586
575
|
|
|
587
|
-
const ARCHIVE_VISIBILITIES: ArchiveVisibility[] = [
|
|
588
|
-
"public",
|
|
589
|
-
"featured",
|
|
590
|
-
"latest_hidden",
|
|
591
|
-
"private",
|
|
592
|
-
];
|
|
593
|
-
|
|
594
576
|
function getVisibilityLabel(v: ArchiveVisibility): string {
|
|
595
577
|
const { i18n } = useLingui();
|
|
596
|
-
|
|
597
|
-
public: i18n._(
|
|
598
|
-
msg({
|
|
599
|
-
message: "Public",
|
|
600
|
-
comment: "@context: Archive visibility filter - public posts",
|
|
601
|
-
}),
|
|
602
|
-
),
|
|
603
|
-
latest_hidden: i18n._(
|
|
604
|
-
msg({
|
|
605
|
-
message: "Hidden from Latest",
|
|
606
|
-
comment:
|
|
607
|
-
"@context: Archive visibility filter for posts hidden from Latest",
|
|
608
|
-
}),
|
|
609
|
-
),
|
|
610
|
-
private: i18n._(
|
|
611
|
-
msg({
|
|
612
|
-
message: "Private",
|
|
613
|
-
comment: "@context: Archive visibility filter - private posts",
|
|
614
|
-
}),
|
|
615
|
-
),
|
|
616
|
-
featured: i18n._(
|
|
617
|
-
msg({
|
|
618
|
-
message: "Featured",
|
|
619
|
-
comment: "@context: Archive visibility filter - featured posts",
|
|
620
|
-
}),
|
|
621
|
-
),
|
|
622
|
-
};
|
|
623
|
-
return labels[v];
|
|
578
|
+
return getSharedVisibilityLabel(v, i18n);
|
|
624
579
|
}
|
|
625
580
|
|
|
626
581
|
const VISIBILITY_ICONS: Record<ArchiveVisibility, string> = {
|
|
@@ -652,19 +607,27 @@ const THREAD_ICONS = {
|
|
|
652
607
|
|
|
653
608
|
const FilterBar: FC<{
|
|
654
609
|
filters: ArchiveFilters;
|
|
610
|
+
defaultLayout: ArchiveLayout;
|
|
655
611
|
availableYears: number[];
|
|
656
|
-
availableCollections: { slug: string; title: string }[];
|
|
612
|
+
availableCollections: { id: string; slug: string; title: string }[];
|
|
657
613
|
isAuthenticated: boolean;
|
|
658
|
-
|
|
614
|
+
basePath?: string;
|
|
659
615
|
}> = ({
|
|
660
616
|
filters,
|
|
617
|
+
defaultLayout,
|
|
661
618
|
availableYears,
|
|
662
619
|
availableCollections,
|
|
663
620
|
isAuthenticated,
|
|
664
|
-
|
|
621
|
+
basePath = "",
|
|
665
622
|
}) => {
|
|
666
623
|
const { i18n } = useLingui();
|
|
667
|
-
|
|
624
|
+
// Every link on this bar is this page with one dimension edited, so the bar
|
|
625
|
+
// spells them with the same serializer the route parses with.
|
|
626
|
+
const ctx: DimensionContext = {
|
|
627
|
+
collections: buildCollectionVocabulary(availableCollections),
|
|
628
|
+
};
|
|
629
|
+
const currentUrl = buildFilterUrl(filters, {}, ctx, basePath);
|
|
630
|
+
const selection = filters.selection;
|
|
668
631
|
|
|
669
632
|
// --- Year options ---------------------------------------------------------
|
|
670
633
|
|
|
@@ -677,20 +640,24 @@ const FilterBar: FC<{
|
|
|
677
640
|
}),
|
|
678
641
|
),
|
|
679
642
|
icon: FILTER_ICONS.year,
|
|
680
|
-
value: buildFilterUrl(
|
|
681
|
-
{ ...filters, year: undefined },
|
|
682
|
-
{ year: undefined },
|
|
683
|
-
sitePathPrefix,
|
|
684
|
-
),
|
|
643
|
+
value: buildFilterUrl(filters, { year: undefined }, ctx, basePath),
|
|
685
644
|
},
|
|
686
645
|
...availableYears.map((year) => ({
|
|
687
646
|
label: String(year),
|
|
688
|
-
value: buildFilterUrl(filters, { year },
|
|
647
|
+
value: buildFilterUrl(filters, { year }, ctx, basePath),
|
|
689
648
|
})),
|
|
690
649
|
];
|
|
691
650
|
|
|
692
651
|
// --- Collection options ---------------------------------------------------
|
|
693
652
|
|
|
653
|
+
// The chip picks one collection at a time. A URL may name several — the
|
|
654
|
+
// vocabulary supports it and the page renders it — but a dropdown that
|
|
655
|
+
// replaces the selection is the honest control for a single click.
|
|
656
|
+
const selectedCollectionIds = selection.collection ?? [];
|
|
657
|
+
const selectedCollectionTitles = selectedCollectionIds
|
|
658
|
+
.map((id) => ctx.collections?.titleById.get(id))
|
|
659
|
+
.filter((title): title is string => Boolean(title));
|
|
660
|
+
|
|
694
661
|
const collectionOptions: ChipSelectOption[] = [
|
|
695
662
|
{
|
|
696
663
|
label: i18n._(
|
|
@@ -700,52 +667,40 @@ const FilterBar: FC<{
|
|
|
700
667
|
}),
|
|
701
668
|
),
|
|
702
669
|
icon: FILTER_ICONS.collection,
|
|
703
|
-
value: buildFilterUrl(
|
|
704
|
-
{
|
|
705
|
-
...filters,
|
|
706
|
-
collectionSlug: undefined,
|
|
707
|
-
collectionTitle: undefined,
|
|
708
|
-
},
|
|
709
|
-
{ collectionSlug: undefined, collectionTitle: undefined },
|
|
710
|
-
sitePathPrefix,
|
|
711
|
-
),
|
|
670
|
+
value: buildFilterUrl(filters, { collection: undefined }, ctx, basePath),
|
|
712
671
|
},
|
|
713
672
|
...availableCollections.map((col) => ({
|
|
714
673
|
label: col.title,
|
|
715
|
-
value: buildFilterUrl(
|
|
716
|
-
filters,
|
|
717
|
-
{ collectionSlug: col.slug },
|
|
718
|
-
sitePathPrefix,
|
|
719
|
-
),
|
|
674
|
+
value: buildFilterUrl(filters, { collection: [col.id] }, ctx, basePath),
|
|
720
675
|
})),
|
|
721
676
|
];
|
|
722
677
|
|
|
723
678
|
// --- Format options (Notes split into All / Titled / Untitled) -----------
|
|
724
679
|
|
|
725
|
-
const formatActiveLabel =
|
|
726
|
-
?
|
|
680
|
+
const formatActiveLabel = selection.format
|
|
681
|
+
? selection.title === true
|
|
727
682
|
? i18n._(
|
|
728
683
|
msg({
|
|
729
684
|
message: "Titled",
|
|
730
685
|
comment: "@context: Archive filter - notes that have a title",
|
|
731
686
|
}),
|
|
732
687
|
)
|
|
733
|
-
:
|
|
688
|
+
: selection.title === false
|
|
734
689
|
? i18n._(
|
|
735
690
|
msg({
|
|
736
691
|
message: "Untitled",
|
|
737
692
|
comment: "@context: Archive filter - notes without a title",
|
|
738
693
|
}),
|
|
739
694
|
)
|
|
740
|
-
: getFormatLabelPlural(
|
|
695
|
+
: getFormatLabelPlural(selection.format)
|
|
741
696
|
: undefined;
|
|
742
697
|
|
|
743
|
-
const formatActiveIcon =
|
|
744
|
-
?
|
|
698
|
+
const formatActiveIcon = selection.format
|
|
699
|
+
? selection.title === true
|
|
745
700
|
? "type"
|
|
746
|
-
:
|
|
701
|
+
: selection.title === false
|
|
747
702
|
? "text"
|
|
748
|
-
: FORMAT_ICONS[
|
|
703
|
+
: FORMAT_ICONS[selection.format]
|
|
749
704
|
: undefined;
|
|
750
705
|
|
|
751
706
|
const formatOptions: ChipSelectOption[] = [
|
|
@@ -758,9 +713,10 @@ const FilterBar: FC<{
|
|
|
758
713
|
),
|
|
759
714
|
icon: FILTER_ICONS.format,
|
|
760
715
|
value: buildFilterUrl(
|
|
761
|
-
|
|
762
|
-
{ format: undefined,
|
|
763
|
-
|
|
716
|
+
filters,
|
|
717
|
+
{ format: undefined, title: undefined },
|
|
718
|
+
ctx,
|
|
719
|
+
basePath,
|
|
764
720
|
),
|
|
765
721
|
},
|
|
766
722
|
{
|
|
@@ -768,11 +724,9 @@ const FilterBar: FC<{
|
|
|
768
724
|
icon: FORMAT_ICONS.note,
|
|
769
725
|
value: buildFilterUrl(
|
|
770
726
|
filters,
|
|
771
|
-
{
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
},
|
|
775
|
-
sitePathPrefix,
|
|
727
|
+
{ format: "note", title: undefined },
|
|
728
|
+
ctx,
|
|
729
|
+
basePath,
|
|
776
730
|
),
|
|
777
731
|
},
|
|
778
732
|
{
|
|
@@ -786,11 +740,9 @@ const FilterBar: FC<{
|
|
|
786
740
|
indent: true,
|
|
787
741
|
value: buildFilterUrl(
|
|
788
742
|
filters,
|
|
789
|
-
{
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
},
|
|
793
|
-
sitePathPrefix,
|
|
743
|
+
{ format: "note", title: true },
|
|
744
|
+
ctx,
|
|
745
|
+
basePath,
|
|
794
746
|
),
|
|
795
747
|
},
|
|
796
748
|
{
|
|
@@ -804,11 +756,9 @@ const FilterBar: FC<{
|
|
|
804
756
|
indent: true,
|
|
805
757
|
value: buildFilterUrl(
|
|
806
758
|
filters,
|
|
807
|
-
{
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
},
|
|
811
|
-
sitePathPrefix,
|
|
759
|
+
{ format: "note", title: false },
|
|
760
|
+
ctx,
|
|
761
|
+
basePath,
|
|
812
762
|
),
|
|
813
763
|
},
|
|
814
764
|
...FORMATS.filter((f) => f !== "note").map((f) => ({
|
|
@@ -816,25 +766,33 @@ const FilterBar: FC<{
|
|
|
816
766
|
icon: FORMAT_ICONS[f],
|
|
817
767
|
value: buildFilterUrl(
|
|
818
768
|
filters,
|
|
819
|
-
{ format: f,
|
|
820
|
-
|
|
769
|
+
{ format: f, title: undefined },
|
|
770
|
+
ctx,
|
|
771
|
+
basePath,
|
|
821
772
|
),
|
|
822
773
|
})),
|
|
823
774
|
];
|
|
824
775
|
|
|
825
|
-
// --- Visibility options
|
|
826
|
-
|
|
827
|
-
//
|
|
828
|
-
//
|
|
829
|
-
//
|
|
830
|
-
|
|
831
|
-
|
|
776
|
+
// --- Visibility options ------------------------------------------------------
|
|
777
|
+
|
|
778
|
+
// A signed-out reader gets the same dimension minus `private`: the archive
|
|
779
|
+
// already shows them Hidden-from-Latest posts, so those two values name sets
|
|
780
|
+
// they can actually reach. `private` names one they cannot, and the route
|
|
781
|
+
// redirects rather than quietly widening it.
|
|
782
|
+
const selectableVisibilities = isAuthenticated
|
|
783
|
+
? ARCHIVE_VISIBILITIES
|
|
784
|
+
: PUBLIC_ARCHIVE_VISIBILITIES;
|
|
785
|
+
|
|
786
|
+
// "All visibility" is the absence of the parameter, not a value of it. The
|
|
787
|
+
// page once emitted `?visibility=all` here, which read back as exactly the
|
|
788
|
+
// same thing — a second spelling of "nothing selected" that only the parser
|
|
789
|
+
// knew about. It is still read, for URLs already written; it is not written.
|
|
790
|
+
const allVisibilityUrl = buildFilterUrl(
|
|
791
|
+
filters,
|
|
832
792
|
{ visibility: undefined },
|
|
833
|
-
|
|
793
|
+
ctx,
|
|
794
|
+
basePath,
|
|
834
795
|
);
|
|
835
|
-
const allVisibilityUrl = allVisibilityBaseUrl.includes("?")
|
|
836
|
-
? `${allVisibilityBaseUrl}&visibility=all`
|
|
837
|
-
: `${allVisibilityBaseUrl}?visibility=all`;
|
|
838
796
|
|
|
839
797
|
const visibilityOptions: ChipSelectOption[] = [
|
|
840
798
|
{
|
|
@@ -847,21 +805,22 @@ const FilterBar: FC<{
|
|
|
847
805
|
icon: FILTER_ICONS.visibility,
|
|
848
806
|
value: allVisibilityUrl,
|
|
849
807
|
},
|
|
850
|
-
...
|
|
808
|
+
...selectableVisibilities.map((v) => ({
|
|
851
809
|
label: getVisibilityLabel(v),
|
|
852
810
|
...(v === "featured"
|
|
853
811
|
? { iconHtml: FEATURED_VISIBILITY_ICON_HTML }
|
|
854
812
|
: { icon: VISIBILITY_ICONS[v] }),
|
|
855
|
-
value: buildFilterUrl(filters, { visibility: v },
|
|
813
|
+
value: buildFilterUrl(filters, { visibility: v }, ctx, basePath),
|
|
856
814
|
})),
|
|
857
815
|
];
|
|
858
816
|
|
|
859
817
|
// --- Thread options ---------------------------------------------------------
|
|
860
818
|
|
|
861
819
|
const threadClearUrl = buildFilterUrl(
|
|
862
|
-
|
|
863
|
-
{
|
|
864
|
-
|
|
820
|
+
filters,
|
|
821
|
+
{ replies: undefined },
|
|
822
|
+
ctx,
|
|
823
|
+
basePath,
|
|
865
824
|
);
|
|
866
825
|
|
|
867
826
|
const threadsLabel = i18n._(
|
|
@@ -891,31 +850,31 @@ const FilterBar: FC<{
|
|
|
891
850
|
{
|
|
892
851
|
label: threadsLabel,
|
|
893
852
|
icon: THREAD_ICONS.threads,
|
|
894
|
-
value: buildFilterUrl(filters, {
|
|
853
|
+
value: buildFilterUrl(filters, { replies: true }, ctx, basePath),
|
|
895
854
|
},
|
|
896
855
|
{
|
|
897
856
|
label: singlePostsLabel,
|
|
898
857
|
icon: THREAD_ICONS.single,
|
|
899
|
-
value: buildFilterUrl(filters, {
|
|
858
|
+
value: buildFilterUrl(filters, { replies: false }, ctx, basePath),
|
|
900
859
|
},
|
|
901
860
|
];
|
|
902
861
|
|
|
903
862
|
const threadActiveLabel =
|
|
904
|
-
|
|
863
|
+
selection.replies === true
|
|
905
864
|
? threadsLabel
|
|
906
|
-
:
|
|
865
|
+
: selection.replies === false
|
|
907
866
|
? singlePostsLabel
|
|
908
867
|
: undefined;
|
|
909
868
|
const threadActiveIcon =
|
|
910
|
-
|
|
869
|
+
selection.replies === true
|
|
911
870
|
? THREAD_ICONS.threads
|
|
912
|
-
:
|
|
871
|
+
: selection.replies === false
|
|
913
872
|
? THREAD_ICONS.single
|
|
914
873
|
: undefined;
|
|
915
874
|
|
|
916
|
-
const activeKinds =
|
|
875
|
+
const activeKinds = selectedMediaKinds(selection.media);
|
|
917
876
|
const mediaActiveLabel =
|
|
918
|
-
|
|
877
|
+
selection.media === "none"
|
|
919
878
|
? i18n._(
|
|
920
879
|
msg({
|
|
921
880
|
message: "Text",
|
|
@@ -928,11 +887,20 @@ const FilterBar: FC<{
|
|
|
928
887
|
getMediaKindLabel(activeKinds[0]!)
|
|
929
888
|
: activeKinds.length > 1
|
|
930
889
|
? String(activeKinds.length)
|
|
931
|
-
:
|
|
890
|
+
: selection.media === "any"
|
|
891
|
+
? i18n._(
|
|
892
|
+
msg({
|
|
893
|
+
message: "With media",
|
|
894
|
+
comment:
|
|
895
|
+
"@context: Archive filter - posts carrying any media attachment",
|
|
896
|
+
}),
|
|
897
|
+
)
|
|
898
|
+
: undefined;
|
|
932
899
|
const mediaClearUrl = buildFilterUrl(
|
|
933
|
-
|
|
934
|
-
{
|
|
935
|
-
|
|
900
|
+
filters,
|
|
901
|
+
{ media: undefined },
|
|
902
|
+
ctx,
|
|
903
|
+
basePath,
|
|
936
904
|
);
|
|
937
905
|
|
|
938
906
|
return (
|
|
@@ -945,11 +913,12 @@ const FilterBar: FC<{
|
|
|
945
913
|
options={yearOptions}
|
|
946
914
|
currentValue={currentUrl}
|
|
947
915
|
clearUrl={buildFilterUrl(
|
|
948
|
-
|
|
916
|
+
filters,
|
|
949
917
|
{ year: undefined },
|
|
950
|
-
|
|
918
|
+
ctx,
|
|
919
|
+
basePath,
|
|
951
920
|
)}
|
|
952
|
-
activeLabel={
|
|
921
|
+
activeLabel={selection.year ? String(selection.year) : undefined}
|
|
953
922
|
/>
|
|
954
923
|
)}
|
|
955
924
|
{availableCollections.length > 0 && (
|
|
@@ -959,15 +928,16 @@ const FilterBar: FC<{
|
|
|
959
928
|
options={collectionOptions}
|
|
960
929
|
currentValue={currentUrl}
|
|
961
930
|
clearUrl={buildFilterUrl(
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
},
|
|
967
|
-
{ collectionSlug: undefined, collectionTitle: undefined },
|
|
968
|
-
sitePathPrefix,
|
|
931
|
+
filters,
|
|
932
|
+
{ collection: undefined },
|
|
933
|
+
ctx,
|
|
934
|
+
basePath,
|
|
969
935
|
)}
|
|
970
|
-
activeLabel={
|
|
936
|
+
activeLabel={
|
|
937
|
+
selectedCollectionTitles.length > 0
|
|
938
|
+
? selectedCollectionTitles.join(", ")
|
|
939
|
+
: undefined
|
|
940
|
+
}
|
|
971
941
|
iconOnly
|
|
972
942
|
/>
|
|
973
943
|
)}
|
|
@@ -977,9 +947,10 @@ const FilterBar: FC<{
|
|
|
977
947
|
options={formatOptions}
|
|
978
948
|
currentValue={currentUrl}
|
|
979
949
|
clearUrl={buildFilterUrl(
|
|
980
|
-
|
|
981
|
-
{ format: undefined,
|
|
982
|
-
|
|
950
|
+
filters,
|
|
951
|
+
{ format: undefined, title: undefined },
|
|
952
|
+
ctx,
|
|
953
|
+
basePath,
|
|
983
954
|
)}
|
|
984
955
|
activeLabel={formatActiveLabel}
|
|
985
956
|
activeIcon={formatActiveIcon}
|
|
@@ -1001,41 +972,45 @@ const FilterBar: FC<{
|
|
|
1001
972
|
id="af-media"
|
|
1002
973
|
icon={FILTER_ICONS.media}
|
|
1003
974
|
filters={filters}
|
|
975
|
+
ctx={ctx}
|
|
1004
976
|
activeLabel={mediaActiveLabel}
|
|
1005
977
|
clearUrl={mediaClearUrl}
|
|
1006
|
-
|
|
978
|
+
basePath={basePath}
|
|
1007
979
|
/>
|
|
1008
980
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
/>
|
|
1033
|
-
)}
|
|
981
|
+
<ChipSelect
|
|
982
|
+
id="af-visibility"
|
|
983
|
+
icon={FILTER_ICONS.visibility}
|
|
984
|
+
options={visibilityOptions}
|
|
985
|
+
currentValue={currentUrl}
|
|
986
|
+
clearUrl={allVisibilityUrl}
|
|
987
|
+
activeLabel={
|
|
988
|
+
selection.visibility
|
|
989
|
+
? getVisibilityLabel(selection.visibility)
|
|
990
|
+
: undefined
|
|
991
|
+
}
|
|
992
|
+
activeIcon={
|
|
993
|
+
selection.visibility && selection.visibility !== "featured"
|
|
994
|
+
? VISIBILITY_ICONS[selection.visibility]
|
|
995
|
+
: undefined
|
|
996
|
+
}
|
|
997
|
+
activeIconHtml={
|
|
998
|
+
selection.visibility === "featured"
|
|
999
|
+
? FEATURED_VISIBILITY_ICON_HTML
|
|
1000
|
+
: undefined
|
|
1001
|
+
}
|
|
1002
|
+
iconOnly
|
|
1003
|
+
/>
|
|
1034
1004
|
</div>
|
|
1035
1005
|
|
|
1036
1006
|
<div class="archive-toolbar-toggles">
|
|
1037
|
-
<SortToggle filters={filters}
|
|
1038
|
-
<
|
|
1007
|
+
<SortToggle filters={filters} ctx={ctx} basePath={basePath} />
|
|
1008
|
+
<LayoutToggle
|
|
1009
|
+
filters={filters}
|
|
1010
|
+
ctx={ctx}
|
|
1011
|
+
defaultLayout={defaultLayout}
|
|
1012
|
+
basePath={basePath}
|
|
1013
|
+
/>
|
|
1039
1014
|
</div>
|
|
1040
1015
|
</div>
|
|
1041
1016
|
);
|
|
@@ -1333,21 +1308,26 @@ const ArchiveTile: FC<{ post: PostView; timeZone?: string }> = ({
|
|
|
1333
1308
|
export const ArchivePage: FC<ArchivePageProps> = ({
|
|
1334
1309
|
groups,
|
|
1335
1310
|
items,
|
|
1311
|
+
defaultLayout = "list",
|
|
1336
1312
|
totalCount,
|
|
1313
|
+
baselineCount,
|
|
1337
1314
|
currentPage,
|
|
1338
1315
|
totalPages,
|
|
1339
1316
|
filters,
|
|
1340
1317
|
availableYears,
|
|
1341
1318
|
availableCollections,
|
|
1342
1319
|
isAuthenticated,
|
|
1343
|
-
|
|
1320
|
+
basePath = "",
|
|
1344
1321
|
timeZone = "UTC",
|
|
1345
1322
|
feedHref,
|
|
1346
1323
|
}) => {
|
|
1347
1324
|
const { i18n } = useLingui();
|
|
1348
|
-
const
|
|
1325
|
+
const currentLayout: ArchiveLayout = filters.layout ?? defaultLayout;
|
|
1349
1326
|
const sortsByActivity = filters.sort === "updated";
|
|
1350
|
-
const
|
|
1327
|
+
const dimensionCtx: DimensionContext = {
|
|
1328
|
+
collections: buildCollectionVocabulary(availableCollections),
|
|
1329
|
+
};
|
|
1330
|
+
const paginationBaseUrl = buildFilterUrl(filters, {}, dimensionCtx, basePath);
|
|
1351
1331
|
const totalCountUnit =
|
|
1352
1332
|
totalCount === 1
|
|
1353
1333
|
? i18n._(
|
|
@@ -1365,25 +1345,37 @@ export const ArchivePage: FC<ArchivePageProps> = ({
|
|
|
1365
1345
|
}),
|
|
1366
1346
|
);
|
|
1367
1347
|
|
|
1348
|
+
// A reader who arrives on a pre-filtered URL never applied the filter and has
|
|
1349
|
+
// no way to know how much it removed. Naming the seven dimensions back at
|
|
1350
|
+
// them is what the chip bar already does; what it cannot say is how much is
|
|
1351
|
+
// left, so the count carries its own baseline instead.
|
|
1352
|
+
const showsSubset =
|
|
1353
|
+
hasActiveArchiveFilter(filters.selection) &&
|
|
1354
|
+
baselineCount !== undefined &&
|
|
1355
|
+
baselineCount > totalCount;
|
|
1356
|
+
|
|
1357
|
+
const countRemainder = showsSubset
|
|
1358
|
+
? i18n._(
|
|
1359
|
+
msg({
|
|
1360
|
+
message: "of {total} {unit}",
|
|
1361
|
+
comment:
|
|
1362
|
+
"@context: Archive page count when a filter narrows the view, following the matching count — reads as '42 of 1,240 threads'",
|
|
1363
|
+
}),
|
|
1364
|
+
{ total: baselineCount, unit: totalCountUnit },
|
|
1365
|
+
)
|
|
1366
|
+
: totalCountUnit;
|
|
1367
|
+
|
|
1368
|
+
const countSummary = `${totalCount} ${countRemainder}`;
|
|
1369
|
+
|
|
1368
1370
|
return (
|
|
1369
1371
|
<div class="py-6" data-page="archive">
|
|
1370
1372
|
<header class="archive-page-header page-intro">
|
|
1371
1373
|
<div class="page-intro-title-row">
|
|
1372
|
-
<h1 class="page-intro-title">
|
|
1373
|
-
{i18n._(
|
|
1374
|
-
msg({
|
|
1375
|
-
message: "Archive",
|
|
1376
|
-
comment: "@context: Archive page title",
|
|
1377
|
-
}),
|
|
1378
|
-
)}
|
|
1379
|
-
</h1>
|
|
1374
|
+
<h1 class="page-intro-title">{i18n._(ARCHIVE_ALL_POSTS_LABEL)}</h1>
|
|
1380
1375
|
</div>
|
|
1381
|
-
<p
|
|
1382
|
-
class="page-intro-meta archive-page-meta"
|
|
1383
|
-
aria-label={`${totalCount} ${totalCountUnit}`}
|
|
1384
|
-
>
|
|
1376
|
+
<p class="page-intro-meta archive-page-meta" aria-label={countSummary}>
|
|
1385
1377
|
<span class="archive-page-summary-count">{totalCount}</span>{" "}
|
|
1386
|
-
{
|
|
1378
|
+
{countRemainder}
|
|
1387
1379
|
{sortsByActivity && (
|
|
1388
1380
|
<>
|
|
1389
1381
|
{" · "}
|
|
@@ -1400,7 +1392,7 @@ export const ArchivePage: FC<ArchivePageProps> = ({
|
|
|
1400
1392
|
<>
|
|
1401
1393
|
{" "}
|
|
1402
1394
|
<a
|
|
1403
|
-
href={toPublicPath(feedHref,
|
|
1395
|
+
href={toPublicPath(feedHref, basePath)}
|
|
1404
1396
|
class="feed-link"
|
|
1405
1397
|
title={i18n._(
|
|
1406
1398
|
msg({
|
|
@@ -1423,10 +1415,11 @@ export const ArchivePage: FC<ArchivePageProps> = ({
|
|
|
1423
1415
|
|
|
1424
1416
|
<FilterBar
|
|
1425
1417
|
filters={filters}
|
|
1418
|
+
defaultLayout={defaultLayout}
|
|
1426
1419
|
availableYears={availableYears}
|
|
1427
1420
|
availableCollections={availableCollections}
|
|
1428
1421
|
isAuthenticated={isAuthenticated}
|
|
1429
|
-
|
|
1422
|
+
basePath={basePath}
|
|
1430
1423
|
/>
|
|
1431
1424
|
</header>
|
|
1432
1425
|
|
|
@@ -1441,7 +1434,7 @@ export const ArchivePage: FC<ArchivePageProps> = ({
|
|
|
1441
1434
|
}),
|
|
1442
1435
|
)}
|
|
1443
1436
|
</p>
|
|
1444
|
-
) :
|
|
1437
|
+
) : currentLayout === "grid" ? (
|
|
1445
1438
|
<div class="archive-grid-wrapper">
|
|
1446
1439
|
<div class="archive-grid">
|
|
1447
1440
|
{groups.map((group, groupIndex) => (
|