@jant/core 0.6.15 → 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 +67 -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-C-oi_t8W.js → app-K_Aa1MMn.js} +52623 -13193
- 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-CsFx6F_M.js → github-sync-BPAvT999.js} +2343 -110
- 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__/mise-config.test.ts +22 -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 +524 -2
- package/src/client/__tests__/compose-launch.test.ts +62 -1
- package/src/client/__tests__/compose-shortcuts.test.ts +57 -8
- 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 +88 -1
- 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__/compose-format-convert.test.ts +0 -19
- 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 +79 -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 +3283 -389
- package/src/client/components/__tests__/jant-compose-editor.test.ts +581 -86
- package/src/client/components/__tests__/jant-compose-fullscreen.test.ts +34 -89
- 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-format-convert.ts +5 -1
- package/src/client/components/compose-types.ts +121 -3
- 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 +106 -49
- package/src/client/components/jant-compose-dialog.ts +2757 -1194
- package/src/client/components/jant-compose-editor.ts +866 -397
- package/src/client/components/jant-compose-fullscreen.ts +53 -47
- 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 +1142 -268
- 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 +336 -242
- package/src/client/compose-launch.ts +89 -2
- package/src/client/compose-shortcuts.ts +9 -7
- 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/post-refresh.ts +135 -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/__tests__/link-input-rules.test.ts +121 -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-input-rules.ts +4 -4
- package/src/client/tiptap/link-toolbar.ts +22 -9
- package/src/client/toast.ts +143 -38
- 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__/backfill-thread-activity.test.ts +234 -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/__tests__/thread-activity.test.ts +113 -0
- package/src/db/backfills/0005_split_thread_activity_from_quiet_replies.sql +68 -0
- package/src/db/backfills/0006_clear_mirrored_page_nav_labels.sql +31 -0
- package/src/db/migrations/0031_many_ego.sql +3 -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/0031_snapshot.json +2562 -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 +28 -0
- package/src/db/migrations/pg/0029_rare_hairball.sql +3 -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/0029_snapshot.json +3289 -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 +28 -0
- package/src/db/pg/schema.ts +213 -27
- package/src/db/post-visibility.ts +117 -0
- package/src/db/schema.ts +242 -27
- package/src/db/thread-activity.ts +101 -0
- 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 +568 -168
- package/src/i18n/locales/public/en.ts +1 -1
- package/src/i18n/locales/public/zh-Hans.po +562 -162
- package/src/i18n/locales/public/zh-Hans.ts +1 -1
- package/src/i18n/locales/public/zh-Hant.po +562 -162
- 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 +1691 -12
- 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__/markdown.test.ts +16 -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 +88 -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__/translit.test.ts +87 -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 +93 -34
- 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 +1021 -66
- 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 +21 -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/link-preview.ts +25 -0
- package/src/lib/markdown-manager.ts +6 -1
- 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-display.ts +42 -9
- 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 +81 -10
- package/src/lib/tiptap-render.ts +5 -4
- package/src/lib/translit.ts +288 -0
- package/src/lib/upload.ts +16 -13
- package/src/lib/url.ts +188 -24
- package/src/lib/version.ts +10 -8
- package/src/lib/view-language.ts +436 -0
- package/src/lib/view.ts +79 -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__/palette.test.ts +44 -0
- 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 +172 -9
- package/src/routes/api/public/__tests__/archive.test.ts +111 -0
- package/src/routes/api/public/__tests__/posts.test.ts +38 -0
- package/src/routes/api/public/archive.ts +77 -81
- package/src/routes/api/public/posts.ts +30 -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 +11 -2
- 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/__tests__/sitemap.test.ts +68 -1
- 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 +657 -1
- 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__/featured.test.ts +6 -2
- 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__/preview.test.ts +3 -1
- 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 +507 -357
- 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 +183 -19
- 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 +139 -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-timeline.test.ts +142 -11
- package/src/services/__tests__/post.test.ts +323 -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 +330 -47
- 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 +281 -24
- 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 +225 -7
- package/src/services/post.ts +1318 -252
- package/src/services/search.ts +48 -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 -1585
- package/src/styles/site-media.css +20 -6
- package/src/styles/tokens.css +144 -13
- package/src/styles/ui-author.css +7602 -0
- package/src/styles/ui.css +1224 -7276
- 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 +92 -1
- package/src/types/operations.ts +64 -2
- package/src/types/props.ts +168 -30
- package/src/types/views.ts +61 -1
- package/src/ui/__tests__/font-themes.test.ts +52 -12
- package/src/ui/compose/ComposeDialog.tsx +215 -21
- 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/LinkPreview.tsx +2 -7
- package/src/ui/feed/NoteCard.tsx +9 -4
- package/src/ui/feed/PostStatusBadges.tsx +103 -17
- 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 +401 -301
- 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 +122 -3
- 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/DraftPreviewBar.tsx +25 -9
- 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 +55 -23
- 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/custom-icons.ts +5 -0
- package/src/ui/shared/navigation-labels.ts +45 -71
- package/src/ui/shared/post-article-attributes.ts +8 -0
- package/src/ui/shared/smart-collection-labels.ts +343 -0
- package/dist/app-BxCOR3Uc.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-pLre2DM_.js +0 -1
- package/dist/client/_assets/client-B_eGKN5p.css +0 -2
- package/dist/client/_assets/client-DxY5BFe8.js +0 -296
- package/dist/client/_assets/client-auth-CakPESv9.js +0 -5533
- package/dist/env-OHRKGcMj.js +0 -281
- package/dist/github-api-BgSiE71w.js +0 -176
- package/dist/github-app-BbklkFmU.js +0 -275
- package/dist/github-sync-Cq1pzzOI.js +0 -431
- package/dist/github-sync-ppWXN3jb.js +0 -4
- package/dist/url-BMYO-Zlt.js +0 -395
- 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
|
@@ -13,12 +13,27 @@ import type { FC } from "hono/jsx";
|
|
|
13
13
|
import { MAX_THREAD_POSTS, type Collection } from "../../types.js";
|
|
14
14
|
import { useLingui } from "../../i18n/context.js";
|
|
15
15
|
import { getCollectionFormLabels } from "../shared/collection-management-labels.js";
|
|
16
|
-
import type {
|
|
16
|
+
import type {
|
|
17
|
+
ComposeLabels,
|
|
18
|
+
ComposeLanguage,
|
|
19
|
+
} from "../../client/components/compose-types.js";
|
|
17
20
|
|
|
18
21
|
export interface ComposeDialogProps {
|
|
19
22
|
collections?: Collection[];
|
|
20
23
|
uploadMaxFileSize?: number;
|
|
21
24
|
slashCommandDiscovered?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Languages the site publishes. Empty on a single-language site, and the
|
|
27
|
+
* composer then shows no language UI at all — an author who never turned
|
|
28
|
+
* multilingual content on should not meet it.
|
|
29
|
+
*/
|
|
30
|
+
languages?: ComposeLanguage[];
|
|
31
|
+
/**
|
|
32
|
+
* Content language of the page the composer opens from. A post left on
|
|
33
|
+
* automatic publishes in this language until detection reads the writing as
|
|
34
|
+
* another one, which the composer says on the button beside Post.
|
|
35
|
+
*/
|
|
36
|
+
contextLanguage?: string | null;
|
|
22
37
|
}
|
|
23
38
|
|
|
24
39
|
export interface ComposeFormProps extends ComposeDialogProps {
|
|
@@ -31,6 +46,8 @@ export const ComposeForm: FC<ComposeFormProps> = ({
|
|
|
31
46
|
collections,
|
|
32
47
|
uploadMaxFileSize,
|
|
33
48
|
slashCommandDiscovered = false,
|
|
49
|
+
languages,
|
|
50
|
+
contextLanguage,
|
|
34
51
|
pageMode = false,
|
|
35
52
|
closeHref,
|
|
36
53
|
autoRestoreDraft = false,
|
|
@@ -41,7 +58,15 @@ export const ComposeForm: FC<ComposeFormProps> = ({
|
|
|
41
58
|
cancel: i18n._(
|
|
42
59
|
msg({
|
|
43
60
|
message: "Cancel",
|
|
44
|
-
comment:
|
|
61
|
+
comment:
|
|
62
|
+
"@context: Back out of the attached-text sub-editor, paired with Done. Leaving the composer itself says Close instead — it may keep the work as a draft, so nothing is being cancelled.",
|
|
63
|
+
}),
|
|
64
|
+
),
|
|
65
|
+
close: i18n._(
|
|
66
|
+
msg({
|
|
67
|
+
message: "Close",
|
|
68
|
+
comment:
|
|
69
|
+
"@context: Leaves the composer — the × on a single post, and the button in a thread. Prompts to save a draft first if there is unsaved work.",
|
|
45
70
|
}),
|
|
46
71
|
),
|
|
47
72
|
imageNotRehosted: i18n._(
|
|
@@ -126,8 +151,9 @@ export const ComposeForm: FC<ComposeFormProps> = ({
|
|
|
126
151
|
),
|
|
127
152
|
titlePlaceholder: i18n._(
|
|
128
153
|
msg({
|
|
129
|
-
message: "
|
|
130
|
-
comment:
|
|
154
|
+
message: "Untitled",
|
|
155
|
+
comment:
|
|
156
|
+
"@context: Compose note title placeholder. States what the note is while the field is empty rather than asking for a title — untitled notes are a normal kind of note here, and Archive files them under this same word.",
|
|
131
157
|
}),
|
|
132
158
|
),
|
|
133
159
|
bodyPlaceholder: i18n._(
|
|
@@ -237,7 +263,7 @@ export const ComposeForm: FC<ComposeFormProps> = ({
|
|
|
237
263
|
title: i18n._(
|
|
238
264
|
msg({
|
|
239
265
|
message: "Title",
|
|
240
|
-
comment: "@context: Compose toolbar - title
|
|
266
|
+
comment: "@context: Compose toolbar - show or hide the title field",
|
|
241
267
|
}),
|
|
242
268
|
),
|
|
243
269
|
fullscreen: i18n._(
|
|
@@ -321,12 +347,39 @@ export const ComposeForm: FC<ComposeFormProps> = ({
|
|
|
321
347
|
comment: "@context: Button to remove an uploaded attachment in compose",
|
|
322
348
|
}),
|
|
323
349
|
),
|
|
350
|
+
moveAttachmentEarlier: i18n._(
|
|
351
|
+
msg({
|
|
352
|
+
message: "Move attachment earlier",
|
|
353
|
+
comment:
|
|
354
|
+
"@context: Button that moves an attachment one place toward the start in compose",
|
|
355
|
+
}),
|
|
356
|
+
),
|
|
357
|
+
moveAttachmentLater: i18n._(
|
|
358
|
+
msg({
|
|
359
|
+
message: "Move attachment later",
|
|
360
|
+
comment:
|
|
361
|
+
"@context: Button that moves an attachment one place toward the end in compose",
|
|
362
|
+
}),
|
|
363
|
+
),
|
|
324
364
|
uploading: i18n._(
|
|
325
365
|
msg({
|
|
326
366
|
message: "Uploading...",
|
|
327
367
|
comment: "@context: Toast shown during background upload",
|
|
328
368
|
}),
|
|
329
369
|
),
|
|
370
|
+
publishing: i18n._(
|
|
371
|
+
msg({
|
|
372
|
+
message: "Publishing...",
|
|
373
|
+
comment: "@context: Toast shown while a post is being published",
|
|
374
|
+
}),
|
|
375
|
+
),
|
|
376
|
+
saving: i18n._(
|
|
377
|
+
msg({
|
|
378
|
+
message: "Saving...",
|
|
379
|
+
comment:
|
|
380
|
+
"@context: Toast shown while a draft or an edited post is being saved",
|
|
381
|
+
}),
|
|
382
|
+
),
|
|
330
383
|
loadingPost: i18n._(
|
|
331
384
|
msg({
|
|
332
385
|
message: "Loading post...",
|
|
@@ -390,9 +443,9 @@ export const ComposeForm: FC<ComposeFormProps> = ({
|
|
|
390
443
|
),
|
|
391
444
|
confirmCloseCancel: i18n._(
|
|
392
445
|
msg({
|
|
393
|
-
message: "
|
|
446
|
+
message: "Keep editing",
|
|
394
447
|
comment:
|
|
395
|
-
"@context: Confirm close action sheet -
|
|
448
|
+
"@context: Confirm close action sheet - dismiss the sheet and return to the editor. Says what it does rather than 'Cancel', which the composer already spends on leaving.",
|
|
396
449
|
}),
|
|
397
450
|
),
|
|
398
451
|
confirmCloseDiscard: i18n._(
|
|
@@ -509,6 +562,20 @@ export const ComposeForm: FC<ComposeFormProps> = ({
|
|
|
509
562
|
"@context: Toast when publish fails and post is auto-saved as draft",
|
|
510
563
|
}),
|
|
511
564
|
),
|
|
565
|
+
publishFailed: i18n._(
|
|
566
|
+
msg({
|
|
567
|
+
message: "Couldn't publish. Try again.",
|
|
568
|
+
comment:
|
|
569
|
+
"@context: Toast when publish fails and the server gave no reason",
|
|
570
|
+
}),
|
|
571
|
+
),
|
|
572
|
+
publishFailedOffline: i18n._(
|
|
573
|
+
msg({
|
|
574
|
+
message: "Couldn't reach the server. Try again.",
|
|
575
|
+
comment:
|
|
576
|
+
"@context: Toast when a publish request never reached the server",
|
|
577
|
+
}),
|
|
578
|
+
),
|
|
512
579
|
uploadFailedDraft: i18n._(
|
|
513
580
|
msg({
|
|
514
581
|
message: "Some uploads failed. Saved as draft.",
|
|
@@ -649,9 +716,9 @@ export const ComposeForm: FC<ComposeFormProps> = ({
|
|
|
649
716
|
),
|
|
650
717
|
publishDateSummaryNow: i18n._(
|
|
651
718
|
msg({
|
|
652
|
-
message: "
|
|
719
|
+
message: "Now",
|
|
653
720
|
comment:
|
|
654
|
-
"@context:
|
|
721
|
+
"@context: Value shown on a post's date control when it will publish at the current time",
|
|
655
722
|
}),
|
|
656
723
|
),
|
|
657
724
|
publishDateSummaryAction: i18n._(
|
|
@@ -688,9 +755,9 @@ export const ComposeForm: FC<ComposeFormProps> = ({
|
|
|
688
755
|
),
|
|
689
756
|
publishSlugSummaryAuto: i18n._(
|
|
690
757
|
msg({
|
|
691
|
-
message: "
|
|
758
|
+
message: "/…",
|
|
692
759
|
comment:
|
|
693
|
-
"@context:
|
|
760
|
+
"@context: Value shown on a post's permalink control when the link is generated automatically — a stand-in for the path the server will assign. Sits next to real permalinks rendered as /my-post, so keep the leading slash",
|
|
694
761
|
}),
|
|
695
762
|
),
|
|
696
763
|
publishSlugSummaryAction: i18n._(
|
|
@@ -794,24 +861,24 @@ export const ComposeForm: FC<ComposeFormProps> = ({
|
|
|
794
861
|
"@context: Toast shown when a local draft is restored on compose open",
|
|
795
862
|
}),
|
|
796
863
|
),
|
|
797
|
-
|
|
864
|
+
draftStoreFailed: i18n._(
|
|
798
865
|
msg({
|
|
799
|
-
message: "
|
|
866
|
+
message: "This browser can't keep a local copy. Save as a draft.",
|
|
800
867
|
comment:
|
|
801
|
-
"@context:
|
|
868
|
+
"@context: Toast shown when the composer cannot write its local draft to browser storage",
|
|
802
869
|
}),
|
|
803
870
|
),
|
|
804
|
-
|
|
871
|
+
editing: i18n._(
|
|
805
872
|
msg({
|
|
806
|
-
message: "
|
|
873
|
+
message: "Editing",
|
|
807
874
|
comment:
|
|
808
|
-
"@context:
|
|
875
|
+
"@context: Marker above the composer when changing a post that is already published",
|
|
809
876
|
}),
|
|
810
877
|
),
|
|
811
|
-
|
|
878
|
+
composeDialogLabel: i18n._(
|
|
812
879
|
msg({
|
|
813
|
-
message: "
|
|
814
|
-
comment: "@context:
|
|
880
|
+
message: "Compose",
|
|
881
|
+
comment: "@context: Accessible name for the compose dialog",
|
|
815
882
|
}),
|
|
816
883
|
),
|
|
817
884
|
slashHint: i18n._(
|
|
@@ -896,10 +963,132 @@ export const ComposeForm: FC<ComposeFormProps> = ({
|
|
|
896
963
|
}),
|
|
897
964
|
),
|
|
898
965
|
},
|
|
966
|
+
languageLabel: i18n._(
|
|
967
|
+
msg({
|
|
968
|
+
message: "Language",
|
|
969
|
+
comment: "@context: Compose field for the post's content language",
|
|
970
|
+
}),
|
|
971
|
+
),
|
|
972
|
+
languageAuto: i18n._(
|
|
973
|
+
msg({
|
|
974
|
+
message: "Detect",
|
|
975
|
+
comment:
|
|
976
|
+
"@context: Compose language option that leaves detection to Jant",
|
|
977
|
+
}),
|
|
978
|
+
),
|
|
979
|
+
languageAutoHint: i18n._(
|
|
980
|
+
msg({
|
|
981
|
+
message: "Read from what you write",
|
|
982
|
+
comment: "@context: Help text under the compose language field",
|
|
983
|
+
}),
|
|
984
|
+
),
|
|
985
|
+
languageAutoDetected: i18n._(
|
|
986
|
+
msg({
|
|
987
|
+
message: "Read from what you write — looks like {language}",
|
|
988
|
+
comment:
|
|
989
|
+
"@context: Help text under the compose language field once a language has been detected",
|
|
990
|
+
}),
|
|
991
|
+
// Detected in the browser from the current text; see `translationOf`.
|
|
992
|
+
{ language: "{language}" },
|
|
993
|
+
),
|
|
994
|
+
languageAutoPending: i18n._(
|
|
995
|
+
msg({
|
|
996
|
+
message: "Not enough text to tell yet — publishes in {language}",
|
|
997
|
+
comment:
|
|
998
|
+
"@context: Help text under the compose language field before there is enough writing to read a language out of; {language} is the one it would publish in meanwhile, which is the language of the page the composer was opened from",
|
|
999
|
+
}),
|
|
1000
|
+
// Only known in the browser; see `translationOf`.
|
|
1001
|
+
{ language: "{language}" },
|
|
1002
|
+
),
|
|
1003
|
+
languageTriggerLabel: i18n._(
|
|
1004
|
+
msg({
|
|
1005
|
+
message: "Language: {language}",
|
|
1006
|
+
comment:
|
|
1007
|
+
"@context: Accessible name of the composer's language button, which sits beside Post and names the language this post would publish in",
|
|
1008
|
+
}),
|
|
1009
|
+
// Filled in the browser with whichever language that is; see
|
|
1010
|
+
// `translationOf`.
|
|
1011
|
+
{ language: "{language}" },
|
|
1012
|
+
),
|
|
1013
|
+
translationOf: i18n._(
|
|
1014
|
+
msg({
|
|
1015
|
+
message: "Translation of “{title}”",
|
|
1016
|
+
comment:
|
|
1017
|
+
"@context: Compose banner shown while writing a translation of an existing post",
|
|
1018
|
+
}),
|
|
1019
|
+
// The post being translated is only known in the browser, and Lingui
|
|
1020
|
+
// resolves an ICU message completely at `i18n._()` time — formatted with
|
|
1021
|
+
// no value, this slot would come out empty. Passing the placeholder back
|
|
1022
|
+
// as the value leaves it intact for the component to fill.
|
|
1023
|
+
{ title: "{title}" },
|
|
1024
|
+
),
|
|
1025
|
+
translationContext: i18n._(
|
|
1026
|
+
msg({
|
|
1027
|
+
message: "Translating",
|
|
1028
|
+
comment:
|
|
1029
|
+
"@context: Divider between the original post and the editor writing its translation, when the target language is not known yet",
|
|
1030
|
+
}),
|
|
1031
|
+
),
|
|
1032
|
+
translationContextInLanguage: i18n._(
|
|
1033
|
+
msg({
|
|
1034
|
+
message: "Translating into {language}",
|
|
1035
|
+
comment:
|
|
1036
|
+
"@context: Divider between the original post above and the editor below, naming the language being written",
|
|
1037
|
+
}),
|
|
1038
|
+
// Filled in the browser from the chosen language; see `translationOf`.
|
|
1039
|
+
{ language: "{language}" },
|
|
1040
|
+
),
|
|
1041
|
+
translationContextOpen: i18n._(
|
|
1042
|
+
msg({
|
|
1043
|
+
message: "Open the original in a new tab",
|
|
1044
|
+
comment:
|
|
1045
|
+
"@context: Tooltip on the source post link above the compose editor while writing a translation",
|
|
1046
|
+
}),
|
|
1047
|
+
),
|
|
1048
|
+
translationContextOriginal: i18n._(
|
|
1049
|
+
msg({
|
|
1050
|
+
message: "The original",
|
|
1051
|
+
comment:
|
|
1052
|
+
"@context: Accessible name of the scrollable panel holding the post being translated",
|
|
1053
|
+
}),
|
|
1054
|
+
),
|
|
1055
|
+
translationContextHide: i18n._(
|
|
1056
|
+
msg({
|
|
1057
|
+
message: "Hide",
|
|
1058
|
+
comment:
|
|
1059
|
+
"@context: Button that folds away the original while writing its translation. Sits right after the words “Translating into …”, which is what makes it clear what gets hidden — the accessible name spells it out",
|
|
1060
|
+
}),
|
|
1061
|
+
),
|
|
1062
|
+
translationContextHideLong: i18n._(
|
|
1063
|
+
msg({
|
|
1064
|
+
message: "Hide the original",
|
|
1065
|
+
comment:
|
|
1066
|
+
"@context: Accessible name of the button that folds away the post being translated",
|
|
1067
|
+
}),
|
|
1068
|
+
),
|
|
1069
|
+
translationContextShow: i18n._(
|
|
1070
|
+
msg({
|
|
1071
|
+
message: "Show",
|
|
1072
|
+
comment:
|
|
1073
|
+
"@context: Button that brings back the folded-away original while writing its translation",
|
|
1074
|
+
}),
|
|
1075
|
+
),
|
|
1076
|
+
translationContextShowLong: i18n._(
|
|
1077
|
+
msg({
|
|
1078
|
+
message: "Show the original",
|
|
1079
|
+
comment:
|
|
1080
|
+
"@context: Accessible name of the button that brings back the folded-away post being translated",
|
|
1081
|
+
}),
|
|
1082
|
+
),
|
|
899
1083
|
collectionFormLabels: getCollectionFormLabels(i18n),
|
|
900
1084
|
} satisfies ComposeLabels;
|
|
901
1085
|
const labels = JSON.stringify(labelsObject).replace(/</g, "\\u003c");
|
|
902
1086
|
|
|
1087
|
+
const languagesJson = JSON.stringify(languages ?? []).replace(
|
|
1088
|
+
/</g,
|
|
1089
|
+
"\\u003c",
|
|
1090
|
+
);
|
|
1091
|
+
|
|
903
1092
|
const collectionsJson = JSON.stringify(
|
|
904
1093
|
(collections ?? []).map((c) => ({
|
|
905
1094
|
id: c.id,
|
|
@@ -911,6 +1100,8 @@ export const ComposeForm: FC<ComposeFormProps> = ({
|
|
|
911
1100
|
return (
|
|
912
1101
|
<jant-compose-dialog
|
|
913
1102
|
collections={collectionsJson}
|
|
1103
|
+
languages={languagesJson}
|
|
1104
|
+
{...(contextLanguage ? { "context-language": contextLanguage } : {})}
|
|
914
1105
|
labels={labels}
|
|
915
1106
|
upload-max-file-size={uploadMaxFileSize ?? 500}
|
|
916
1107
|
{...(pageMode ? { "page-mode": "" } : {})}
|
|
@@ -920,7 +1111,6 @@ export const ComposeForm: FC<ComposeFormProps> = ({
|
|
|
920
1111
|
>
|
|
921
1112
|
{/* SSR fallback skeleton */}
|
|
922
1113
|
<div class="compose-dialog-inner">
|
|
923
|
-
<div class="compose-dialog-header" />
|
|
924
1114
|
<div class="compose-body skel-section-md" />
|
|
925
1115
|
</div>
|
|
926
1116
|
</jant-compose-dialog>
|
|
@@ -931,6 +1121,8 @@ export const ComposeDialog: FC<ComposeDialogProps> = ({
|
|
|
931
1121
|
collections,
|
|
932
1122
|
uploadMaxFileSize,
|
|
933
1123
|
slashCommandDiscovered = false,
|
|
1124
|
+
languages,
|
|
1125
|
+
contextLanguage,
|
|
934
1126
|
}) => {
|
|
935
1127
|
return (
|
|
936
1128
|
<dialog id="compose-dialog" class="compose-dialog">
|
|
@@ -938,6 +1130,8 @@ export const ComposeDialog: FC<ComposeDialogProps> = ({
|
|
|
938
1130
|
collections={collections}
|
|
939
1131
|
uploadMaxFileSize={uploadMaxFileSize}
|
|
940
1132
|
slashCommandDiscovered={slashCommandDiscovered}
|
|
1133
|
+
languages={languages}
|
|
1134
|
+
contextLanguage={contextLanguage}
|
|
941
1135
|
/>
|
|
942
1136
|
</dialog>
|
|
943
1137
|
);
|
|
@@ -25,11 +25,7 @@ export const ComposePrompt: FC<ComposePromptProps> = ({
|
|
|
25
25
|
composeOpenShortcutDiscovered ? "true" : "false"
|
|
26
26
|
}
|
|
27
27
|
>
|
|
28
|
-
<button
|
|
29
|
-
type="button"
|
|
30
|
-
class="compose-prompt-trigger"
|
|
31
|
-
data-on:click="document.getElementById('compose-dialog')?.querySelector('jant-compose-dialog')?.openNew()"
|
|
32
|
-
>
|
|
28
|
+
<button type="button" class="compose-prompt-trigger" data-compose-open>
|
|
33
29
|
<span class="compose-prompt-avatar">
|
|
34
30
|
<svg
|
|
35
31
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compose dialog labels.
|
|
3
|
+
*
|
|
4
|
+
* The composer fills two labels in the browser, from values only it knows: the
|
|
5
|
+
* post being translated and the detected language. Lingui resolves an ICU
|
|
6
|
+
* message completely at `i18n._()` time, so those slots have to be carried
|
|
7
|
+
* through deliberately — a label formatted with no value renders as an empty
|
|
8
|
+
* string, which reads as a missing title rather than as a bug.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Context } from "hono";
|
|
12
|
+
import { renderToString } from "hono/jsx/dom/server";
|
|
13
|
+
import { describe, expect, it } from "vitest";
|
|
14
|
+
import { I18nProvider } from "../../../i18n/context.js";
|
|
15
|
+
import { createI18n } from "../../../i18n/i18n.js";
|
|
16
|
+
import { ComposeForm } from "../ComposeDialog.js";
|
|
17
|
+
|
|
18
|
+
function renderComposeLabels(): Record<string, string> {
|
|
19
|
+
const i18n = createI18n("en");
|
|
20
|
+
const c = {
|
|
21
|
+
get(key: string) {
|
|
22
|
+
return key === "i18n" ? i18n : undefined;
|
|
23
|
+
},
|
|
24
|
+
} as unknown as Context;
|
|
25
|
+
I18nProvider({ c, children: "" });
|
|
26
|
+
|
|
27
|
+
const html = renderToString(
|
|
28
|
+
ComposeForm({
|
|
29
|
+
languages: [
|
|
30
|
+
{ tag: "zh-Hans", label: "简体中文" },
|
|
31
|
+
{ tag: "en", label: "English" },
|
|
32
|
+
],
|
|
33
|
+
}),
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const match = /labels="([^"]*)"/.exec(html);
|
|
37
|
+
if (!match?.[1]) throw new Error("expected a labels attribute");
|
|
38
|
+
const decoded = match[1]
|
|
39
|
+
.replace(/"/g, '"')
|
|
40
|
+
.replace(/&/g, "&")
|
|
41
|
+
.replace(/</g, "<")
|
|
42
|
+
.replace(/>/g, ">")
|
|
43
|
+
.replace(/'/g, "'");
|
|
44
|
+
return JSON.parse(decoded) as Record<string, string>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
describe("ComposeForm labels", () => {
|
|
48
|
+
it("leaves the slots the browser fills", () => {
|
|
49
|
+
const labels = renderComposeLabels();
|
|
50
|
+
|
|
51
|
+
expect(labels.translationOf).toContain("{title}");
|
|
52
|
+
expect(labels.translationContextInLanguage).toContain("{language}");
|
|
53
|
+
expect(labels.languageAutoDetected).toContain("{language}");
|
|
54
|
+
expect(labels.languageAutoPending).toContain("{language}");
|
|
55
|
+
expect(labels.languageTriggerLabel).toContain("{language}");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("never ships an unresolved ICU construct", () => {
|
|
59
|
+
for (const [key, value] of Object.entries(renderComposeLabels())) {
|
|
60
|
+
if (typeof value !== "string") continue;
|
|
61
|
+
expect(value, key).not.toContain("plural,");
|
|
62
|
+
expect(value, key).not.toContain("NaN");
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("passes the site's languages to the component", () => {
|
|
67
|
+
const i18n = createI18n("en");
|
|
68
|
+
const c = {
|
|
69
|
+
get(key: string) {
|
|
70
|
+
return key === "i18n" ? i18n : undefined;
|
|
71
|
+
},
|
|
72
|
+
} as unknown as Context;
|
|
73
|
+
I18nProvider({ c, children: "" });
|
|
74
|
+
|
|
75
|
+
const html = renderToString(
|
|
76
|
+
ComposeForm({
|
|
77
|
+
languages: [{ tag: "en", label: "English" }],
|
|
78
|
+
}),
|
|
79
|
+
);
|
|
80
|
+
expect(html).toContain("languages=");
|
|
81
|
+
expect(html).toContain("English");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("hands the component the page's language as the automatic default", () => {
|
|
85
|
+
const i18n = createI18n("en");
|
|
86
|
+
const c = {
|
|
87
|
+
get(key: string) {
|
|
88
|
+
return key === "i18n" ? i18n : undefined;
|
|
89
|
+
},
|
|
90
|
+
} as unknown as Context;
|
|
91
|
+
I18nProvider({ c, children: "" });
|
|
92
|
+
|
|
93
|
+
const html = renderToString(
|
|
94
|
+
ComposeForm({
|
|
95
|
+
languages: [
|
|
96
|
+
{ tag: "zh-Hans", label: "简体中文" },
|
|
97
|
+
{ tag: "ja", label: "日本語" },
|
|
98
|
+
],
|
|
99
|
+
contextLanguage: "ja",
|
|
100
|
+
}),
|
|
101
|
+
);
|
|
102
|
+
expect(html).toContain('context-language="ja"');
|
|
103
|
+
|
|
104
|
+
// Without a page language the attribute stays off, and the component
|
|
105
|
+
// falls back to the primary language on its own.
|
|
106
|
+
expect(
|
|
107
|
+
renderToString(
|
|
108
|
+
ComposeForm({ languages: [{ tag: "en", label: "English" }] }),
|
|
109
|
+
),
|
|
110
|
+
).not.toContain("context-language");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("sends an empty list on a single-language site", () => {
|
|
114
|
+
const i18n = createI18n("en");
|
|
115
|
+
const c = {
|
|
116
|
+
get(key: string) {
|
|
117
|
+
return key === "i18n" ? i18n : undefined;
|
|
118
|
+
},
|
|
119
|
+
} as unknown as Context;
|
|
120
|
+
I18nProvider({ c, children: "" });
|
|
121
|
+
|
|
122
|
+
// The composer renders no language UI at all in that case.
|
|
123
|
+
expect(renderToString(ComposeForm({}))).toContain('languages="[]"');
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
import { msg } from "@lingui/core/macro";
|
|
6
6
|
import { useLingui } from "../../../i18n/context.js";
|
|
7
|
+
import { getJantDocsUrl } from "../../../lib/jant-docs.js";
|
|
7
8
|
import { toPublicPath } from "../../../lib/url.js";
|
|
8
9
|
|
|
9
|
-
const THEMING_DOCS_URL =
|
|
10
|
-
"https://github.com/jant-me/jant/blob/main/docs/theming.md";
|
|
10
|
+
const THEMING_DOCS_URL = getJantDocsUrl("theming");
|
|
11
11
|
|
|
12
12
|
export function AdvancedContent({
|
|
13
13
|
customCSS,
|
|
@@ -33,11 +33,7 @@ export function CodeInjectionContent({
|
|
|
33
33
|
data-indicator="_codeLoading"
|
|
34
34
|
class="max-w-form"
|
|
35
35
|
>
|
|
36
|
-
<div
|
|
37
|
-
role="note"
|
|
38
|
-
class="alert alert-destructive mb-6"
|
|
39
|
-
style="display:flex;gap:.75rem;align-items:flex-start"
|
|
40
|
-
>
|
|
36
|
+
<div role="note" class="alert-destructive mb-6">
|
|
41
37
|
<svg
|
|
42
38
|
xmlns="http://www.w3.org/2000/svg"
|
|
43
39
|
width="20"
|
|
@@ -54,16 +50,16 @@ export function CodeInjectionContent({
|
|
|
54
50
|
<path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
|
|
55
51
|
<path d="M12 17h.01" />
|
|
56
52
|
</svg>
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
<p
|
|
53
|
+
<strong>
|
|
54
|
+
{i18n._(
|
|
55
|
+
msg({
|
|
56
|
+
message: "This code runs on every page of your site.",
|
|
57
|
+
comment: "@context: Code Injection security warning headline",
|
|
58
|
+
}),
|
|
59
|
+
)}
|
|
60
|
+
</strong>
|
|
61
|
+
<section>
|
|
62
|
+
<p>
|
|
67
63
|
{i18n._(
|
|
68
64
|
msg({
|
|
69
65
|
message:
|
|
@@ -72,7 +68,7 @@ export function CodeInjectionContent({
|
|
|
72
68
|
}),
|
|
73
69
|
)}
|
|
74
70
|
</p>
|
|
75
|
-
</
|
|
71
|
+
</section>
|
|
76
72
|
</div>
|
|
77
73
|
|
|
78
74
|
<fieldset class="mb-6">
|