@jant/core 0.6.14 → 0.6.16
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/bin/commands/import-site.js +88 -13
- package/bin/commands/migrate.js +55 -0
- package/bin/commands/posts/rebuild-html.js +184 -0
- package/bin/commands/site/snapshot/import.js +14 -10
- package/bin/lib/d1-query.js +23 -5
- package/bin/lib/migration-runner.js +29 -7
- package/bin/lib/node-database.js +32 -0
- package/bin/lib/site-snapshot.js +347 -46
- package/bin/lib/sql-export.js +1 -1
- package/bin/lib/thread-collection-migration.js +326 -0
- package/dist/app-C75Zc8dD.js +6 -0
- package/dist/{app-2i7-WQHg.js → app-C7_4oab9.js} +7774 -6425
- package/dist/client/.vite/manifest.json +8 -8
- package/dist/client/_assets/chunks/{url-pLre2DM_.js → url-CU9pEbk5.js} +1 -1
- package/dist/client/_assets/{client-BvID5ucz.js → client-Bq0vre8Y.js} +59 -38
- package/dist/client/_assets/client-D3VZyG4L.css +2 -0
- package/dist/client/_assets/client-auth-F2rb9WfF.js +5571 -0
- package/dist/{env-OHRKGcMj.js → env-BPYViDJJ.js} +1 -1
- package/dist/{export-DWn149b7.js → export-Dl5KCiEs.js} +1348 -128
- package/dist/{github-api-BgSiE71w.js → github-api-BNF35Lkx.js} +1 -1
- package/dist/{github-app-BbklkFmU.js → github-app-DdiD-bC4.js} +1 -1
- package/dist/{github-sync-C0zyF6XS.js → github-sync-Bqg62IvV.js} +3 -3
- package/dist/{github-sync-Ckk0sJxK.js → github-sync-HdK2EgvJ.js} +3 -3
- package/dist/index.js +5 -5
- package/dist/node.js +7 -7
- package/dist/{url-BMYO-Zlt.js → url-CbLAtlZe.js} +517 -12
- package/package.json +11 -10
- package/src/__tests__/bin/posts-rebuild-html.test.ts +137 -0
- package/src/__tests__/dev-navigation-defaults.test.ts +22 -0
- package/src/__tests__/export-hugo-build.test.ts +63 -4
- package/src/__tests__/export-import-roundtrip.test.ts +6 -4
- package/src/__tests__/export-service.test.ts +142 -9
- package/src/__tests__/helpers/app.ts +3 -0
- package/src/__tests__/helpers/export-fixtures.ts +2 -0
- package/src/__tests__/import-site-command.test.ts +65 -0
- package/src/__tests__/mise-config.test.ts +22 -0
- package/src/__tests__/vite-config.test.ts +45 -0
- package/src/app.tsx +16 -3
- package/src/client/__tests__/collection-created-notice.test.ts +36 -0
- package/src/client/__tests__/collection-form-bridge.test.ts +10 -1
- package/src/client/__tests__/collection-page-actions.test.ts +71 -2
- package/src/client/__tests__/compose-bridge.test.ts +316 -2
- package/src/client/__tests__/compose-shortcuts.test.ts +20 -0
- package/src/client/__tests__/feed-video-player.test.ts +16 -1
- package/src/client/__tests__/footnote-rail.test.ts +472 -0
- package/src/client/__tests__/hydrate-partial.test.ts +3 -0
- package/src/client/__tests__/toast.test.ts +82 -1
- package/src/client/collection-created-notice.ts +66 -0
- package/src/client/collection-form-bridge.ts +17 -0
- package/src/client/collection-navigation.ts +44 -0
- package/src/client/collection-page-actions.ts +57 -1
- package/src/client/components/__tests__/compose-format-convert.test.ts +0 -19
- package/src/client/components/__tests__/jant-collection-directory.test.ts +155 -6
- package/src/client/components/__tests__/jant-command-palette.test.ts +51 -0
- package/src/client/components/__tests__/jant-compose-dialog.test.ts +2268 -206
- package/src/client/components/__tests__/jant-compose-editor.test.ts +147 -59
- package/src/client/components/__tests__/jant-compose-fullscreen.test.ts +114 -64
- package/src/client/components/__tests__/jant-config-editor.test.ts +405 -0
- package/src/client/components/__tests__/jant-media-lightbox.test.ts +121 -0
- package/src/client/components/__tests__/jant-nav-manager.test.ts +538 -2
- package/src/client/components/__tests__/jant-post-form.test.ts +2 -2
- package/src/client/components/__tests__/jant-post-menu.test.ts +47 -5
- package/src/client/components/__tests__/jant-settings-avatar.test.ts +2 -2
- package/src/client/components/__tests__/jant-settings-general.test.ts +3 -3
- package/src/client/components/collection-manager-types.ts +9 -3
- package/src/client/components/compose-format-convert.ts +5 -1
- package/src/client/components/compose-types.ts +55 -3
- package/src/client/components/jant-collection-directory.ts +165 -30
- package/src/client/components/jant-command-palette.ts +14 -7
- package/src/client/components/jant-compose-dialog.ts +1542 -694
- package/src/client/components/jant-compose-editor.ts +237 -99
- package/src/client/components/jant-compose-fullscreen.ts +27 -9
- package/src/client/components/jant-config-editor.ts +722 -0
- package/src/client/components/jant-media-lightbox.ts +100 -18
- package/src/client/components/jant-nav-manager.ts +1283 -54
- package/src/client/components/jant-post-form.ts +3 -3
- package/src/client/components/jant-post-menu.ts +177 -95
- package/src/client/components/nav-manager-types.ts +51 -2
- package/src/client/components/post-form-types.ts +1 -1
- package/src/client/compose-bridge.ts +147 -123
- package/src/client/compose-launch.ts +13 -0
- package/src/client/compose-shortcuts.ts +5 -1
- package/src/client/feed-video-player.ts +62 -2
- package/src/client/footnote-rail.ts +478 -0
- package/src/client/hydrate-partial.ts +2 -0
- package/src/client/media-lightbox-events.ts +63 -0
- package/src/client/post-refresh.ts +135 -0
- package/src/client/site-header-fragment.ts +38 -0
- package/src/client/tiptap/__tests__/blockquote-editing.test.ts +201 -0
- package/src/client/tiptap/__tests__/clear-formatting.test.ts +168 -0
- package/src/client/tiptap/__tests__/link-input-rules.test.ts +121 -0
- package/src/client/tiptap/__tests__/list-editing.test.ts +447 -0
- package/src/client/tiptap/__tests__/markdown-clipboard.test.ts +727 -4
- package/src/client/tiptap/__tests__/table-controls.test.ts +263 -0
- package/src/client/tiptap/__tests__/table-size-picker.test.ts +179 -0
- package/src/client/tiptap/bubble-menu.ts +88 -10
- package/src/client/tiptap/continuous-lists.ts +102 -0
- package/src/client/tiptap/create-editor.ts +3 -0
- package/src/client/tiptap/extensions.ts +14 -5
- package/src/client/tiptap/link-input-rules.ts +4 -4
- package/src/client/tiptap/markdown-clipboard.ts +608 -11
- package/src/client/tiptap/slash-commands.ts +8 -1
- package/src/client/tiptap/structural-keymap.ts +211 -0
- package/src/client/tiptap/tab-indent.ts +8 -22
- package/src/client/tiptap/table-control-labels.ts +30 -0
- package/src/client/tiptap/table-controls.ts +537 -0
- package/src/client/tiptap/table-size-picker.ts +254 -0
- package/src/client/toast.ts +133 -39
- package/src/client-auth.ts +1 -0
- package/src/client.ts +1 -0
- package/src/db/__tests__/backfill-thread-activity.test.ts +234 -0
- package/src/db/__tests__/d1-query.test.ts +43 -1
- package/src/db/__tests__/migration-runner.test.ts +63 -0
- package/src/db/__tests__/migrations.test.ts +469 -0
- package/src/db/__tests__/thread-activity.test.ts +113 -0
- package/src/db/__tests__/thread-collection-migration.test.ts +364 -0
- package/src/db/backfills/0005_split_thread_activity_from_quiet_replies.sql +68 -0
- package/src/db/migrations/0027_old_blue_blade.sql +39 -0
- package/src/db/migrations/0028_superb_post.sql +2 -0
- package/src/db/migrations/0029_boring_magma.sql +1 -0
- package/src/db/migrations/0030_typical_vivisector.sql +50 -0
- package/src/db/migrations/0031_many_ego.sql +3 -0
- package/src/db/migrations/meta/0027_snapshot.json +2511 -0
- package/src/db/migrations/meta/0028_snapshot.json +2511 -0
- package/src/db/migrations/meta/0029_snapshot.json +2519 -0
- package/src/db/migrations/meta/0030_snapshot.json +2541 -0
- package/src/db/migrations/meta/0031_snapshot.json +2562 -0
- package/src/db/migrations/meta/_journal.json +35 -0
- package/src/db/migrations/pg/0025_moaning_epoch.sql +39 -0
- package/src/db/migrations/pg/0026_talented_killer_shrike.sql +2 -0
- package/src/db/migrations/pg/0027_short_cannonball.sql +1 -0
- package/src/db/migrations/pg/0028_perfect_sharon_carter.sql +27 -0
- package/src/db/migrations/pg/0029_rare_hairball.sql +3 -0
- package/src/db/migrations/pg/meta/0025_snapshot.json +3204 -0
- package/src/db/migrations/pg/meta/0026_snapshot.json +3204 -0
- package/src/db/migrations/pg/meta/0027_snapshot.json +3211 -0
- package/src/db/migrations/pg/meta/0028_snapshot.json +3248 -0
- package/src/db/migrations/pg/meta/0029_snapshot.json +3289 -0
- package/src/db/migrations/pg/meta/_journal.json +35 -0
- package/src/db/pg/schema.ts +46 -20
- package/src/db/rehearsal-fixtures/demo-current.json +39 -4
- package/src/db/rehearsal-fixtures/demo-current.sql +121 -6
- package/src/db/schema.ts +48 -20
- package/src/db/thread-activity.ts +101 -0
- package/src/i18n/__tests__/detect.test.ts +8 -2
- package/src/i18n/detect.ts +14 -5
- package/src/i18n/locales/public/en.po +222 -51
- package/src/i18n/locales/public/en.ts +1 -1
- package/src/i18n/locales/public/zh-Hans.po +216 -45
- package/src/i18n/locales/public/zh-Hans.ts +1 -1
- package/src/i18n/locales/public/zh-Hant.po +216 -45
- package/src/i18n/locales/public/zh-Hant.ts +1 -1
- package/src/i18n/locales/settings/en.po +513 -10
- package/src/i18n/locales/settings/en.ts +1 -1
- package/src/i18n/locales/settings/zh-Hans.po +515 -12
- package/src/i18n/locales/settings/zh-Hans.ts +1 -1
- package/src/i18n/locales/settings/zh-Hant.po +515 -12
- package/src/i18n/locales/settings/zh-Hant.ts +1 -1
- package/src/lib/__tests__/api-settings.test.ts +299 -0
- package/src/lib/__tests__/constants.test.ts +5 -0
- package/src/lib/__tests__/feed-policy.test.ts +25 -0
- package/src/lib/__tests__/feed.test.ts +168 -0
- package/src/lib/__tests__/footnotes-upgrade.test.ts +181 -0
- package/src/lib/__tests__/markdown-roundtrip-embed.test.ts +61 -0
- package/src/lib/__tests__/markdown-to-tiptap.test.ts +32 -4
- package/src/lib/__tests__/markdown.test.ts +24 -6
- package/src/lib/__tests__/navigation.test.ts +59 -2
- package/src/lib/__tests__/post-body-html.test.ts +176 -0
- package/src/lib/__tests__/post-display.test.ts +64 -0
- package/src/lib/__tests__/resolve-config.test.ts +113 -1
- package/src/lib/__tests__/slug.test.ts +18 -0
- package/src/lib/__tests__/summary.test.ts +82 -0
- package/src/lib/__tests__/timeline.test.ts +109 -70
- package/src/lib/__tests__/timezones.test.ts +31 -3
- package/src/lib/__tests__/tiptap-render.test.ts +268 -9
- package/src/lib/__tests__/tiptap-to-markdown.test.ts +6 -0
- package/src/lib/__tests__/translit.test.ts +87 -0
- package/src/lib/__tests__/url.test.ts +53 -0
- package/src/lib/__tests__/view.test.ts +53 -0
- package/src/lib/__tests__/worker-response-cache.test.ts +18 -1
- package/src/lib/api-settings.ts +239 -12
- package/src/lib/collection-sort.ts +7 -5
- package/src/lib/constants.ts +2 -0
- package/src/lib/feed-path.ts +25 -0
- package/src/lib/feed-policy.ts +64 -0
- package/src/lib/feed.ts +113 -11
- package/src/lib/footnotes.ts +264 -0
- package/src/lib/github-sync-site-config.ts +2 -0
- package/src/lib/hugo-markdown.ts +15 -3
- package/src/lib/jant-branding.ts +1 -0
- package/src/lib/link-preview.ts +25 -0
- package/src/lib/markdown-manager.ts +193 -5
- package/src/lib/markdown.ts +10 -3
- package/src/lib/navigation.ts +16 -3
- package/src/lib/post-body-html.ts +131 -0
- package/src/lib/post-display.ts +47 -8
- package/src/lib/render.tsx +9 -2
- package/src/lib/resolve-config.ts +100 -16
- package/src/lib/schemas.ts +133 -1
- package/src/lib/settings-paths.ts +5 -0
- package/src/lib/site-skill.ts +78 -0
- package/src/lib/summary.ts +16 -5
- package/src/lib/timeline.ts +137 -131
- package/src/lib/timezones.ts +54 -14
- package/src/lib/tiptap-render.ts +359 -83
- package/src/lib/translit.ts +288 -0
- package/src/lib/url.ts +123 -12
- package/src/lib/view.ts +58 -20
- package/src/lib/worker-response-cache.ts +11 -18
- package/src/middleware/__tests__/public-content-access.test.ts +91 -0
- package/src/middleware/config.ts +2 -2
- package/src/middleware/public-content-access.ts +87 -0
- package/src/node/__tests__/cli-export.test.ts +14 -0
- package/src/node/__tests__/cli-migrate.test.ts +6 -0
- package/src/node/__tests__/cli-site-snapshot.test.ts +205 -2
- package/src/node/__tests__/cli-snapshot-meta.test.ts +100 -0
- package/src/node/index.ts +2 -1
- package/src/preset.css +16 -2
- package/src/routes/__tests__/compose.test.ts +51 -0
- package/src/routes/__tests__/site-skill.test.ts +112 -0
- package/src/routes/api/__tests__/collections.test.ts +91 -19
- package/src/routes/api/__tests__/mcp.test.ts +65 -1
- package/src/routes/api/__tests__/nav-items.test.ts +91 -0
- package/src/routes/api/__tests__/palette.test.ts +44 -0
- package/src/routes/api/__tests__/public-access.test.ts +81 -0
- package/src/routes/api/__tests__/settings.test.ts +217 -0
- package/src/routes/api/collections.ts +22 -26
- package/src/routes/api/export.ts +2 -0
- package/src/routes/api/internal/__tests__/post-body-html.test.ts +163 -0
- package/src/routes/api/internal/__tests__/sites.test.ts +35 -2
- package/src/routes/api/internal/post-body-html.ts +43 -0
- package/src/routes/api/internal/sites.ts +24 -0
- package/src/routes/api/nav-items.ts +24 -1
- package/src/routes/api/posts.ts +14 -10
- package/src/routes/api/public/__tests__/archive.test.ts +35 -0
- package/src/routes/api/public/__tests__/posts.test.ts +246 -0
- package/src/routes/api/public/archive.ts +4 -0
- package/src/routes/api/public/posts.ts +48 -24
- package/src/routes/api/search.ts +3 -0
- package/src/routes/api/settings.ts +33 -0
- package/src/routes/auth/__tests__/setup.test.ts +7 -4
- package/src/routes/compose.tsx +8 -3
- package/src/routes/dash/settings.tsx +45 -2
- package/src/routes/feed/__tests__/feed.test.ts +210 -6
- package/src/routes/feed/__tests__/sitemap.test.ts +68 -1
- package/src/routes/feed/feed.ts +23 -14
- package/src/routes/pages/__tests__/archive-params.test.ts +384 -3
- package/src/routes/pages/__tests__/collection-routing.test.ts +63 -5
- package/src/routes/pages/__tests__/collections.test.ts +9 -9
- package/src/routes/pages/__tests__/featured.test.ts +6 -2
- package/src/routes/pages/__tests__/preview.test.ts +176 -0
- package/src/routes/pages/__tests__/search.test.ts +69 -0
- package/src/routes/pages/archive.tsx +90 -22
- package/src/routes/pages/collection.tsx +32 -19
- package/src/routes/pages/collections.tsx +6 -1
- package/src/routes/pages/page.tsx +86 -11
- package/src/routes/site-skill.ts +18 -0
- package/src/services/__tests__/auth.test.ts +7 -5
- package/src/services/__tests__/collection.test.ts +190 -44
- package/src/services/__tests__/navigation.test.ts +229 -21
- package/src/services/__tests__/post-timeline.test.ts +249 -39
- package/src/services/__tests__/post.test.ts +844 -5
- package/src/services/__tests__/search.test.ts +48 -1
- package/src/services/__tests__/settings.test.ts +8 -0
- package/src/services/__tests__/site-admin.test.ts +121 -1
- package/src/services/auth.ts +2 -2
- package/src/services/bootstrap.ts +3 -2
- package/src/services/collection.ts +224 -167
- package/src/services/export-theme/assets/client-site.css +1 -1
- package/src/services/export-theme/assets/client-site.js +46 -25
- package/src/services/export-theme/layouts/_default/list.html +18 -4
- package/src/services/export-theme/layouts/_default/rss.xml +8 -12
- package/src/services/export-theme/layouts/featured/list.html +5 -4
- package/src/services/export-theme/layouts/partials/featured-thread.html +56 -0
- package/src/services/export-theme/layouts/partials/footer.html +1 -1
- package/src/services/export-theme/layouts/partials/media-gallery.html +1 -0
- package/src/services/export-theme/styles/main.css +30 -2
- package/src/services/export.ts +94 -85
- package/src/services/mcp.ts +37 -27
- package/src/services/media.ts +1 -1
- package/src/services/navigation.ts +185 -46
- package/src/services/path.ts +4 -1
- package/src/services/post.ts +1142 -342
- package/src/services/search.ts +17 -2
- package/src/services/settings.ts +2 -10
- package/src/services/site-admin.ts +63 -43
- package/src/style-cjk-jp.css +1 -1
- package/src/style-cjk-kr.css +1 -1
- package/src/style-cjk-tc.css +1 -1
- package/src/style-cjk.css +1 -1
- package/src/styles/components.css +540 -14
- package/src/styles/site-media.css +111 -19
- package/src/styles/tokens.css +76 -10
- package/src/styles/ui.css +2227 -1347
- package/src/types/bindings.ts +3 -0
- package/src/types/config.ts +243 -12
- package/src/types/constants.ts +22 -1
- package/src/types/entities.ts +14 -8
- package/src/types/operations.ts +18 -10
- package/src/types/props.ts +20 -2
- package/src/types/raw-assets.d.ts +5 -0
- package/src/types/views.ts +22 -4
- package/src/ui/__tests__/font-themes.test.ts +42 -30
- package/src/ui/compose/ComposeDialog.tsx +109 -19
- package/src/ui/dash/appearance/NavigationContent.tsx +332 -4
- package/src/ui/dash/appearance/__tests__/NavigationContent.test.tsx +23 -0
- package/src/ui/dash/settings/ConfigEditorContent.tsx +578 -0
- package/src/ui/dash/settings/GeneralContent.tsx +15 -5
- package/src/ui/dash/settings/SettingsRootContent.tsx +21 -1
- package/src/ui/dash/settings/__tests__/ConfigEditorContent.test.tsx +98 -0
- package/src/ui/dash/settings/__tests__/SettingsRootContent.test.tsx +15 -0
- package/src/ui/feed/CuratedThreadPreview.tsx +16 -4
- package/src/ui/feed/LinkCard.tsx +2 -12
- package/src/ui/feed/LinkPreview.tsx +2 -7
- package/src/ui/feed/NoteCard.tsx +10 -20
- package/src/ui/feed/PostStatusBadges.tsx +42 -3
- package/src/ui/feed/QuoteCard.tsx +2 -12
- package/src/ui/feed/ThreadPreview.tsx +26 -34
- package/src/ui/feed/TimelineFeed.tsx +2 -2
- package/src/ui/feed/__tests__/thread-preview.test.ts +197 -56
- package/src/ui/feed/__tests__/timeline-cards.test.ts +178 -3
- package/src/ui/feed/thread-preview-state.ts +5 -7
- package/src/ui/font-themes.ts +74 -26
- package/src/ui/layouts/BaseLayout.tsx +22 -8
- package/src/ui/layouts/__tests__/BaseLayout.test.tsx +64 -1
- package/src/ui/pages/ArchivePage.tsx +131 -24
- package/src/ui/pages/CollectionPage.tsx +101 -22
- package/src/ui/pages/CollectionsPage.tsx +3 -1
- package/src/ui/pages/PostPage.tsx +39 -12
- package/src/ui/pages/SearchPage.tsx +6 -14
- package/src/ui/pages/__tests__/ArchivePage.test.tsx +70 -0
- package/src/ui/pages/__tests__/PostPage.test.tsx +88 -0
- package/src/ui/shared/CollectionDirectory.tsx +13 -9
- package/src/ui/shared/CollectionsManager.tsx +17 -7
- package/src/ui/shared/DraftPreviewBar.tsx +49 -0
- package/src/ui/shared/HomePageBranding.tsx +2 -2
- package/src/ui/shared/MediaGallery.tsx +1 -0
- package/src/ui/shared/PostFooter.tsx +38 -13
- package/src/ui/shared/__tests__/home-page-branding.test.tsx +1 -1
- package/src/ui/shared/__tests__/media-gallery.test.ts +1 -0
- package/src/ui/shared/__tests__/navigation-labels.test.ts +2 -2
- package/src/ui/shared/__tests__/post-footer.test.ts +15 -0
- package/src/ui/shared/collection-management-labels.ts +33 -2
- package/src/ui/shared/custom-icons.ts +5 -0
- package/src/ui/shared/navigation-labels.ts +2 -4
- package/src/ui/shared/post-article-attributes.ts +52 -0
- package/dist/app-DZDlmh7C.js +0 -6
- package/dist/client/_assets/client-Cevfpm8H.css +0 -2
- package/dist/client/_assets/client-auth-v3yvhbgZ.js +0 -4736
- package/src/client/tiptap/wrapping-input-rules.ts +0 -102
|
@@ -26,6 +26,7 @@ import type {
|
|
|
26
26
|
ComposeFormat,
|
|
27
27
|
ComposeLabels,
|
|
28
28
|
ComposeAttachment,
|
|
29
|
+
ComposeRowStatus,
|
|
29
30
|
AttachedTextItem,
|
|
30
31
|
ComposeEditorSelection,
|
|
31
32
|
ComposeFullscreenOpenDetail,
|
|
@@ -97,43 +98,44 @@ const COMPOSE_TOOLBAR_ICONS = {
|
|
|
97
98
|
/>
|
|
98
99
|
<path
|
|
99
100
|
d="m9 1.95 2.08 4.21 4.65.67-3.36 3.29.8 4.63L9 12.55l-4.17 2.2.8-4.63-3.36-3.29 4.65-.67z"
|
|
100
|
-
stroke-width="1.6"
|
|
101
101
|
/>
|
|
102
102
|
`,
|
|
103
|
+
/* The one filled glyph in the row, so its bars are cut to the weight the
|
|
104
|
+
stroked icons read at — a 2.05 bar beside a 1.42 stroke looks bold. */
|
|
103
105
|
title: `
|
|
104
106
|
<rect
|
|
105
107
|
x="3.35"
|
|
106
|
-
y="3.
|
|
108
|
+
y="3.37"
|
|
107
109
|
width="11.3"
|
|
108
|
-
height="
|
|
109
|
-
rx="0.
|
|
110
|
+
height="1.72"
|
|
111
|
+
rx="0.6"
|
|
110
112
|
fill="currentColor"
|
|
111
113
|
stroke="none"
|
|
112
114
|
/>
|
|
113
115
|
<rect
|
|
114
|
-
x="7.
|
|
116
|
+
x="7.99"
|
|
115
117
|
y="4.6"
|
|
116
|
-
width="2.
|
|
118
|
+
width="2.02"
|
|
117
119
|
height="9.45"
|
|
118
|
-
rx="0.
|
|
120
|
+
rx="0.68"
|
|
119
121
|
fill="currentColor"
|
|
120
122
|
stroke="none"
|
|
121
123
|
/>
|
|
122
124
|
<rect
|
|
123
125
|
x="6.75"
|
|
124
|
-
y="13.
|
|
126
|
+
y="13.32"
|
|
125
127
|
width="4.5"
|
|
126
|
-
height="
|
|
127
|
-
rx="0.
|
|
128
|
+
height="0.95"
|
|
129
|
+
rx="0.48"
|
|
128
130
|
fill="currentColor"
|
|
129
131
|
stroke="none"
|
|
130
132
|
/>
|
|
131
133
|
`,
|
|
132
134
|
fullscreen: `
|
|
133
|
-
<path d="M5.85 3H3v2.85"
|
|
134
|
-
<path d="M12.15 3H15v2.85"
|
|
135
|
-
<path d="M3 12.15V15h2.85"
|
|
136
|
-
<path d="M15 12.15V15h-2.85"
|
|
135
|
+
<path d="M5.85 3H3v2.85" />
|
|
136
|
+
<path d="M12.15 3H15v2.85" />
|
|
137
|
+
<path d="M3 12.15V15h2.85" />
|
|
138
|
+
<path d="M15 12.15V15h-2.85" />
|
|
137
139
|
`,
|
|
138
140
|
} as const;
|
|
139
141
|
|
|
@@ -147,7 +149,6 @@ function renderComposeToolbarIcon(
|
|
|
147
149
|
viewBox="0 0 18 18"
|
|
148
150
|
fill="none"
|
|
149
151
|
stroke="currentColor"
|
|
150
|
-
stroke-width="1.55"
|
|
151
152
|
stroke-linecap="round"
|
|
152
153
|
stroke-linejoin="round"
|
|
153
154
|
aria-hidden="true"
|
|
@@ -189,6 +190,10 @@ export class JantComposeEditor extends LitElement {
|
|
|
189
190
|
threadItem: { type: Boolean, attribute: "thread-item" },
|
|
190
191
|
removable: { type: Boolean },
|
|
191
192
|
inlineFormat: { type: Boolean, attribute: "inline-format" },
|
|
193
|
+
titleByDefault: { type: Boolean, attribute: "title-by-default" },
|
|
194
|
+
positionLabel: { type: String, attribute: "position-label" },
|
|
195
|
+
badgeLabel: { type: String, attribute: "badge-label" },
|
|
196
|
+
headerExtra: { attribute: false },
|
|
192
197
|
slashCommandDiscovered: { type: Boolean },
|
|
193
198
|
_title: { state: true },
|
|
194
199
|
_bodyJson: { state: true },
|
|
@@ -215,6 +220,29 @@ export class JantComposeEditor extends LitElement {
|
|
|
215
220
|
declare threadItem: boolean;
|
|
216
221
|
declare removable: boolean;
|
|
217
222
|
declare inlineFormat: boolean;
|
|
223
|
+
/**
|
|
224
|
+
* Whether a note's title field starts visible. A post that opens a thread is
|
|
225
|
+
* usually the one worth naming, so it defaults on there; a reply or a
|
|
226
|
+
* continuation post carries the thread's title already, so it defaults off.
|
|
227
|
+
* On a new single post the owner narrows it further with the author's own
|
|
228
|
+
* remembered answer. Either way the `T` tool overrides it, and a post that
|
|
229
|
+
* arrives with a title always shows the field.
|
|
230
|
+
*/
|
|
231
|
+
declare titleByDefault: boolean;
|
|
232
|
+
/**
|
|
233
|
+
* "1/3"-style position marker shown before the format selector. Empty for a
|
|
234
|
+
* single post, where there is no "which one" to answer.
|
|
235
|
+
*/
|
|
236
|
+
declare positionLabel: string;
|
|
237
|
+
/** Status marker for the header row, e.g. "Editing". Mutually exclusive with
|
|
238
|
+
* `positionLabel` in practice — a thread post is never an edit. */
|
|
239
|
+
declare badgeLabel: string;
|
|
240
|
+
/**
|
|
241
|
+
* Owner-supplied content for the right side of the format header — the
|
|
242
|
+
* dialog's per-post date/permalink control. Passed in rather than built here
|
|
243
|
+
* because publish metadata belongs to the dialog, not to the editor.
|
|
244
|
+
*/
|
|
245
|
+
declare headerExtra: unknown;
|
|
218
246
|
declare slashCommandDiscovered: boolean;
|
|
219
247
|
declare _title: string;
|
|
220
248
|
declare _bodyJson: JSONContent | null;
|
|
@@ -243,7 +271,6 @@ export class JantComposeEditor extends LitElement {
|
|
|
243
271
|
private _emojiContainer: HTMLElement | null = null;
|
|
244
272
|
private readonly _urlStatusId = `compose-url-status-${randomUUID()}`;
|
|
245
273
|
private _onDocClickBound = this._onDocumentClick.bind(this);
|
|
246
|
-
private _scrollBufferApplied = false;
|
|
247
274
|
private _filePickerCleanup: (() => void) | null = null;
|
|
248
275
|
private _suppressAttachedTextOpenUntil = 0;
|
|
249
276
|
/**
|
|
@@ -273,6 +300,10 @@ export class JantComposeEditor extends LitElement {
|
|
|
273
300
|
this.threadItem = false;
|
|
274
301
|
this.removable = false;
|
|
275
302
|
this.inlineFormat = false;
|
|
303
|
+
this.titleByDefault = true;
|
|
304
|
+
this.positionLabel = "";
|
|
305
|
+
this.badgeLabel = "";
|
|
306
|
+
this.headerExtra = null;
|
|
276
307
|
this.slashCommandDiscovered = false;
|
|
277
308
|
this._title = "";
|
|
278
309
|
this._bodyJson = null;
|
|
@@ -280,7 +311,7 @@ export class JantComposeEditor extends LitElement {
|
|
|
280
311
|
this._quoteText = "";
|
|
281
312
|
this._quoteAuthor = "";
|
|
282
313
|
this._rating = 0;
|
|
283
|
-
this._showTitle =
|
|
314
|
+
this._showTitle = true;
|
|
284
315
|
this._showRating = false;
|
|
285
316
|
this._attachedTexts = [];
|
|
286
317
|
this._attachments = [];
|
|
@@ -778,9 +809,90 @@ export class JantComposeEditor extends LitElement {
|
|
|
778
809
|
}
|
|
779
810
|
}
|
|
780
811
|
|
|
812
|
+
/**
|
|
813
|
+
* What this row contributes to the composer's submit state.
|
|
814
|
+
*
|
|
815
|
+
* The editor owns these fields, so it owns the answer: the dialog reduces
|
|
816
|
+
* `getStatus()` over the rows it has rather than reading editors back out of
|
|
817
|
+
* the DOM, which during a render still holds the row it is about to remove.
|
|
818
|
+
*
|
|
819
|
+
* @returns Whether the row holds anything worth keeping, and whether it is
|
|
820
|
+
* complete enough to publish
|
|
821
|
+
* @example
|
|
822
|
+
* editor.getStatus(); // { hasContent: true, publishable: false } — link, no URL yet
|
|
823
|
+
*/
|
|
824
|
+
getStatus(): ComposeRowStatus {
|
|
825
|
+
const data = this.getData();
|
|
826
|
+
const hasContent =
|
|
827
|
+
!!data.body ||
|
|
828
|
+
!!data.title.trim() ||
|
|
829
|
+
!!data.url.trim() ||
|
|
830
|
+
!!data.quoteText.trim() ||
|
|
831
|
+
!!data.quoteAuthor.trim() ||
|
|
832
|
+
data.rating > 0 ||
|
|
833
|
+
data.attachments.length > 0 ||
|
|
834
|
+
data.attachedTexts.length > 0;
|
|
835
|
+
const fieldsValid =
|
|
836
|
+
!this.getUrlValidationMessage() && !this.getLinkTitleValidationMessage();
|
|
837
|
+
|
|
838
|
+
let publishable: boolean;
|
|
839
|
+
switch (this.format) {
|
|
840
|
+
// A link is its URL and title, both of which the validators already
|
|
841
|
+
// require — nothing else has to be filled in.
|
|
842
|
+
case "link":
|
|
843
|
+
publishable = fieldsValid;
|
|
844
|
+
break;
|
|
845
|
+
case "quote":
|
|
846
|
+
publishable = fieldsValid && !!data.quoteText.trim();
|
|
847
|
+
break;
|
|
848
|
+
default:
|
|
849
|
+
publishable = fieldsValid && hasContent;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
return { hasContent, publishable };
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
#lastStatus: ComposeRowStatus | null = null;
|
|
856
|
+
|
|
857
|
+
/** Tell the owner when — and only when — this row's answer changes. */
|
|
858
|
+
#notifyStatus() {
|
|
859
|
+
const status = this.getStatus();
|
|
860
|
+
if (
|
|
861
|
+
this.#lastStatus?.hasContent === status.hasContent &&
|
|
862
|
+
this.#lastStatus?.publishable === status.publishable
|
|
863
|
+
) {
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
this.#lastStatus = status;
|
|
867
|
+
this.dispatchEvent(
|
|
868
|
+
new CustomEvent<ComposeRowStatus>("jant:compose-status", {
|
|
869
|
+
bubbles: true,
|
|
870
|
+
detail: status,
|
|
871
|
+
}),
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/**
|
|
876
|
+
* Set the title toggle's default and apply it now.
|
|
877
|
+
*
|
|
878
|
+
* `titleByDefault` alone only takes effect on the first update or on
|
|
879
|
+
* `reset()`, and an owner that resets before Lit re-renders would seed from
|
|
880
|
+
* the previous session's value. An owner that knows the default up front
|
|
881
|
+
* calls this instead.
|
|
882
|
+
*
|
|
883
|
+
* @param show - Whether a note's title field starts visible
|
|
884
|
+
* @example
|
|
885
|
+
* editor.setTitleDefault(false); // next new note opens without a title field
|
|
886
|
+
*/
|
|
887
|
+
setTitleDefault(show: boolean) {
|
|
888
|
+
this.titleByDefault = show;
|
|
889
|
+
this._showTitle = show;
|
|
890
|
+
}
|
|
891
|
+
|
|
781
892
|
reset() {
|
|
782
893
|
this.#clearPendingInlineImageUploads();
|
|
783
894
|
this._title = "";
|
|
895
|
+
this._showTitle = this.titleByDefault;
|
|
784
896
|
this._bodyJson = null;
|
|
785
897
|
this._editor?.commands.clearContent();
|
|
786
898
|
this._lastEditorSelection = null;
|
|
@@ -788,7 +900,6 @@ export class JantComposeEditor extends LitElement {
|
|
|
788
900
|
this._quoteText = "";
|
|
789
901
|
this._quoteAuthor = "";
|
|
790
902
|
this._rating = 0;
|
|
791
|
-
this._showTitle = false;
|
|
792
903
|
this._showRating = false;
|
|
793
904
|
this._attachedTexts = [];
|
|
794
905
|
// Revoke preview URLs before clearing
|
|
@@ -811,9 +922,12 @@ export class JantComposeEditor extends LitElement {
|
|
|
811
922
|
status: ComposeAttachment["status"],
|
|
812
923
|
mediaId: string | null,
|
|
813
924
|
error: string | null,
|
|
925
|
+
remoteUrl?: string | null,
|
|
814
926
|
) {
|
|
815
927
|
this._attachments = this._attachments.map((a) =>
|
|
816
|
-
a.clientId === clientId
|
|
928
|
+
a.clientId === clientId
|
|
929
|
+
? { ...a, status, mediaId, error, remoteUrl: remoteUrl ?? a.remoteUrl }
|
|
930
|
+
: a,
|
|
817
931
|
);
|
|
818
932
|
}
|
|
819
933
|
|
|
@@ -978,7 +1092,6 @@ export class JantComposeEditor extends LitElement {
|
|
|
978
1092
|
toolbarMode: "compose",
|
|
979
1093
|
onUpdate: (json) => {
|
|
980
1094
|
this._bodyJson = json;
|
|
981
|
-
this._ensureScrollBuffer();
|
|
982
1095
|
this.promoteLeadingH1Title();
|
|
983
1096
|
hideSlashCommandHint(this);
|
|
984
1097
|
},
|
|
@@ -1006,38 +1119,9 @@ export class JantComposeEditor extends LitElement {
|
|
|
1006
1119
|
rehost: (src) => this.#rehostInlineImage(src),
|
|
1007
1120
|
},
|
|
1008
1121
|
imageNodeLabels: getInlineImageNodeLabels(this.labels),
|
|
1122
|
+
tableControlLabels: this.labels.tableControls,
|
|
1009
1123
|
});
|
|
1010
1124
|
this._lastEditorSelection = this._readEditorSelection();
|
|
1011
|
-
|
|
1012
|
-
// Lock editor min-height once so new lines fill existing space
|
|
1013
|
-
// instead of growing the dialog line-by-line.
|
|
1014
|
-
// Skip in page mode where the editor grows freely with the page.
|
|
1015
|
-
this._scrollBufferApplied = false;
|
|
1016
|
-
const dom = this._editor.view.dom as HTMLElement;
|
|
1017
|
-
const isPageMode = !!this.closest(".compose-page-shell");
|
|
1018
|
-
if (!isPageMode) {
|
|
1019
|
-
const last = dom.lastElementChild as HTMLElement | null;
|
|
1020
|
-
const contentH = last ? last.offsetTop + last.offsetHeight : 0;
|
|
1021
|
-
const buffer = this.format !== "note" ? 60 : 120;
|
|
1022
|
-
dom.style.minHeight = `${contentH + buffer}px`;
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
/**
|
|
1027
|
-
* One-time: adds bottom padding for scroll buffer once the
|
|
1028
|
-
* compose-body starts scrolling. Since the dialog is already at
|
|
1029
|
-
* max-height by that point, the extra padding doesn't grow it.
|
|
1030
|
-
*/
|
|
1031
|
-
private _ensureScrollBuffer() {
|
|
1032
|
-
if (this._scrollBufferApplied) return;
|
|
1033
|
-
const dom = this._editor?.view?.dom as HTMLElement | undefined;
|
|
1034
|
-
if (!dom) return;
|
|
1035
|
-
const body = this.querySelector(".compose-body") as HTMLElement | null;
|
|
1036
|
-
if (!body) return;
|
|
1037
|
-
if (body.scrollHeight > body.clientHeight + 20) {
|
|
1038
|
-
dom.style.paddingBottom = "40px";
|
|
1039
|
-
this._scrollBufferApplied = true;
|
|
1040
|
-
}
|
|
1041
1125
|
}
|
|
1042
1126
|
|
|
1043
1127
|
private _destroyEditor() {
|
|
@@ -1060,6 +1144,17 @@ export class JantComposeEditor extends LitElement {
|
|
|
1060
1144
|
"_attachmentOrder",
|
|
1061
1145
|
]);
|
|
1062
1146
|
|
|
1147
|
+
protected willUpdate(changed: Map<string, unknown>) {
|
|
1148
|
+
super.willUpdate(changed);
|
|
1149
|
+
|
|
1150
|
+
// `titleByDefault` is an owner-supplied prop, so it is only known once the
|
|
1151
|
+
// first update runs. Seed the toggle from it there and leave it alone after
|
|
1152
|
+
// that — from then on the value belongs to the user (and to `reset()`).
|
|
1153
|
+
if (!this.hasUpdated) {
|
|
1154
|
+
this._showTitle = this.titleByDefault;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1063
1158
|
protected updated(changed: Map<string, unknown>) {
|
|
1064
1159
|
super.updated(changed);
|
|
1065
1160
|
|
|
@@ -1097,6 +1192,11 @@ export class JantComposeEditor extends LitElement {
|
|
|
1097
1192
|
}
|
|
1098
1193
|
}
|
|
1099
1194
|
|
|
1195
|
+
// Every field that can change this row's answer is reactive, so `updated()`
|
|
1196
|
+
// is where the owner hears about it — including the ones a user edit never
|
|
1197
|
+
// touches, like an upload finishing.
|
|
1198
|
+
this.#notifyStatus();
|
|
1199
|
+
|
|
1100
1200
|
// Notify parent dialog of content changes for draft auto-save. A format
|
|
1101
1201
|
// conversion writes content fields too, but it's not a user edit, so skip
|
|
1102
1202
|
// the notification once when asked.
|
|
@@ -1170,6 +1270,8 @@ export class JantComposeEditor extends LitElement {
|
|
|
1170
1270
|
showRating?: boolean;
|
|
1171
1271
|
media?: Array<{
|
|
1172
1272
|
id: string;
|
|
1273
|
+
/** Preserved so a restored draft's attachmentOrder still maps by clientId */
|
|
1274
|
+
clientId?: string;
|
|
1173
1275
|
previewUrl: string;
|
|
1174
1276
|
posterUrl?: string | null;
|
|
1175
1277
|
alt?: string;
|
|
@@ -1195,6 +1297,8 @@ export class JantComposeEditor extends LitElement {
|
|
|
1195
1297
|
this._rating = data.rating;
|
|
1196
1298
|
this._showRating = true;
|
|
1197
1299
|
}
|
|
1300
|
+
// A post that already has a title shows the field whatever the default is —
|
|
1301
|
+
// otherwise editing a titled reply would silently drop its title.
|
|
1198
1302
|
if (data.showTitle !== undefined) this._showTitle = data.showTitle;
|
|
1199
1303
|
else if (data.title && data.format === "note") this._showTitle = true;
|
|
1200
1304
|
if (data.showRating !== undefined) this._showRating = data.showRating;
|
|
@@ -1216,13 +1320,14 @@ export class JantComposeEditor extends LitElement {
|
|
|
1216
1320
|
// Convert media attachments to ComposeAttachment[] with status "done"
|
|
1217
1321
|
if (data.media?.length) {
|
|
1218
1322
|
const attachments = data.media.map((m) => ({
|
|
1219
|
-
clientId: randomUUID(),
|
|
1323
|
+
clientId: m.clientId ?? randomUUID(),
|
|
1220
1324
|
file: new File([], m.originalName ?? "existing", { type: m.mimeType }),
|
|
1221
1325
|
previewUrl: m.previewUrl,
|
|
1222
1326
|
posterUrl: m.posterUrl ?? null,
|
|
1223
1327
|
status: "done" as const,
|
|
1224
1328
|
progress: null,
|
|
1225
1329
|
mediaId: m.id,
|
|
1330
|
+
remoteUrl: m.previewUrl,
|
|
1226
1331
|
alt: m.alt ?? "",
|
|
1227
1332
|
error: null,
|
|
1228
1333
|
summary: m.summary ?? null,
|
|
@@ -1280,6 +1385,7 @@ export class JantComposeEditor extends LitElement {
|
|
|
1280
1385
|
|
|
1281
1386
|
this._showUrlValidation = false;
|
|
1282
1387
|
this._showLinkTitleValidation = false;
|
|
1388
|
+
this.#notifyStatus();
|
|
1283
1389
|
}
|
|
1284
1390
|
|
|
1285
1391
|
/** Updates editor content and title from fullscreen close */
|
|
@@ -1303,6 +1409,10 @@ export class JantComposeEditor extends LitElement {
|
|
|
1303
1409
|
);
|
|
1304
1410
|
}
|
|
1305
1411
|
this._lastEditorSelection = selection ?? this._readEditorSelection();
|
|
1412
|
+
// Content handed in from outside has to be visible to the owner in the same
|
|
1413
|
+
// tick: fullscreen's ⌘↵ hands the text back and publishes on the next line,
|
|
1414
|
+
// with no render in between to carry the news.
|
|
1415
|
+
this.#notifyStatus();
|
|
1306
1416
|
}
|
|
1307
1417
|
|
|
1308
1418
|
private static SUMMARY_LENGTH = 100;
|
|
@@ -1527,6 +1637,25 @@ export class JantComposeEditor extends LitElement {
|
|
|
1527
1637
|
el.style.height = `${el.scrollHeight}px`;
|
|
1528
1638
|
}
|
|
1529
1639
|
|
|
1640
|
+
/**
|
|
1641
|
+
* Puts the caret in the body when the click landed on blank section instead
|
|
1642
|
+
* of on the editor. The surfaces that reserve height — the `/new` page, the
|
|
1643
|
+
* dialog on a phone — leave a stretch of empty paper under a two-line
|
|
1644
|
+
* editor, and it should behave like paper: click it, write there. Only the
|
|
1645
|
+
* layout wrappers forward; a click that reached a real control belongs to
|
|
1646
|
+
* that control.
|
|
1647
|
+
*/
|
|
1648
|
+
private _focusBodyFromBlankSpace = (e: MouseEvent) => {
|
|
1649
|
+
const target = e.target as HTMLElement | null;
|
|
1650
|
+
if (!target) return;
|
|
1651
|
+
const forwards =
|
|
1652
|
+
target.classList.contains("compose-body") ||
|
|
1653
|
+
target.classList.contains("compose-field-enter") ||
|
|
1654
|
+
target.classList.contains("compose-tiptap-wrap");
|
|
1655
|
+
if (!forwards) return;
|
|
1656
|
+
this._editor?.commands.focus("end");
|
|
1657
|
+
};
|
|
1658
|
+
|
|
1530
1659
|
private _setRating(star: number) {
|
|
1531
1660
|
this._rating = this._rating === star ? 0 : star;
|
|
1532
1661
|
}
|
|
@@ -1587,6 +1716,7 @@ export class JantComposeEditor extends LitElement {
|
|
|
1587
1716
|
status: "pending",
|
|
1588
1717
|
progress: null,
|
|
1589
1718
|
mediaId: null,
|
|
1719
|
+
remoteUrl: null,
|
|
1590
1720
|
alt: "",
|
|
1591
1721
|
error: null,
|
|
1592
1722
|
summary: null,
|
|
@@ -1709,6 +1839,16 @@ export class JantComposeEditor extends LitElement {
|
|
|
1709
1839
|
this._lastFocusedField = target;
|
|
1710
1840
|
}
|
|
1711
1841
|
|
|
1842
|
+
private _handleTitleKeydown(e: globalThis.KeyboardEvent) {
|
|
1843
|
+
if (e.isComposing || e.keyCode === 229) return;
|
|
1844
|
+
if (e.key !== "Enter" || e.metaKey || e.ctrlKey || e.altKey) {
|
|
1845
|
+
return;
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
e.preventDefault();
|
|
1849
|
+
this._editor?.commands.focus("start");
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1712
1852
|
private _toggleEmojiPicker() {
|
|
1713
1853
|
if (this._showEmojiPicker) {
|
|
1714
1854
|
this.closeEmojiPicker();
|
|
@@ -1967,34 +2107,15 @@ export class JantComposeEditor extends LitElement {
|
|
|
1967
2107
|
return html`
|
|
1968
2108
|
<div class="compose-field-enter">
|
|
1969
2109
|
${this._showTitle
|
|
1970
|
-
? html
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
if (e.key === "Enter") {
|
|
1980
|
-
e.preventDefault();
|
|
1981
|
-
this._editor?.commands.focus("start");
|
|
1982
|
-
}
|
|
1983
|
-
}}
|
|
1984
|
-
class="compose-input compose-note-title"
|
|
1985
|
-
placeholder=${this.labels.titlePlaceholder}
|
|
1986
|
-
/>
|
|
1987
|
-
<button
|
|
1988
|
-
type="button"
|
|
1989
|
-
class="compose-note-title-dismiss"
|
|
1990
|
-
@click=${() => {
|
|
1991
|
-
this._showTitle = false;
|
|
1992
|
-
}}
|
|
1993
|
-
>
|
|
1994
|
-
✕
|
|
1995
|
-
</button>
|
|
1996
|
-
</div>
|
|
1997
|
-
`
|
|
2110
|
+
? html`<input
|
|
2111
|
+
type="text"
|
|
2112
|
+
.value=${this._title}
|
|
2113
|
+
@input=${(e: Event) => this._onInput("_title", e)}
|
|
2114
|
+
@focus=${(e: Event) => this._onFieldFocus(e)}
|
|
2115
|
+
@keydown=${this._handleTitleKeydown}
|
|
2116
|
+
class="compose-input compose-note-title"
|
|
2117
|
+
placeholder=${this.labels.titlePlaceholder}
|
|
2118
|
+
/>`
|
|
1998
2119
|
: nothing}
|
|
1999
2120
|
<div class="compose-tiptap-wrap">
|
|
2000
2121
|
<div class="compose-tiptap-body"></div>
|
|
@@ -2053,6 +2174,7 @@ export class JantComposeEditor extends LitElement {
|
|
|
2053
2174
|
.value=${this._title}
|
|
2054
2175
|
@input=${(e: Event) => this._onInput("_title", e)}
|
|
2055
2176
|
@focus=${(e: Event) => this._onFieldFocus(e)}
|
|
2177
|
+
@keydown=${this._handleTitleKeydown}
|
|
2056
2178
|
@blur=${() => {
|
|
2057
2179
|
this._showLinkTitleValidation = true;
|
|
2058
2180
|
}}
|
|
@@ -2070,9 +2192,7 @@ export class JantComposeEditor extends LitElement {
|
|
|
2070
2192
|
: nothing}
|
|
2071
2193
|
<div class="compose-divider"></div>
|
|
2072
2194
|
<div class="compose-tiptap-wrap">
|
|
2073
|
-
<div
|
|
2074
|
-
class="compose-tiptap-body compose-tiptap-thoughts compose-tiptap-link"
|
|
2075
|
-
></div>
|
|
2195
|
+
<div class="compose-tiptap-body compose-tiptap-link"></div>
|
|
2076
2196
|
<span class="compose-slash-discovery-hint" aria-hidden="true">
|
|
2077
2197
|
${this.labels.slashHint}
|
|
2078
2198
|
</span>
|
|
@@ -2096,7 +2216,7 @@ export class JantComposeEditor extends LitElement {
|
|
|
2096
2216
|
@focus=${(e: Event) => this._onFieldFocus(e)}
|
|
2097
2217
|
class="compose-input compose-quote-text"
|
|
2098
2218
|
placeholder=${this.labels.quotePlaceholder}
|
|
2099
|
-
rows="
|
|
2219
|
+
rows="4"
|
|
2100
2220
|
></textarea>
|
|
2101
2221
|
</div>
|
|
2102
2222
|
<div class="compose-quote-author-row">
|
|
@@ -2141,9 +2261,7 @@ export class JantComposeEditor extends LitElement {
|
|
|
2141
2261
|
aria-hidden="true"
|
|
2142
2262
|
></div>
|
|
2143
2263
|
<div class="compose-tiptap-wrap">
|
|
2144
|
-
<div
|
|
2145
|
-
class="compose-tiptap-body compose-tiptap-thoughts compose-tiptap-thoughts-quote"
|
|
2146
|
-
></div>
|
|
2264
|
+
<div class="compose-tiptap-body"></div>
|
|
2147
2265
|
<span class="compose-slash-discovery-hint" aria-hidden="true">
|
|
2148
2266
|
${this.labels.slashHint}
|
|
2149
2267
|
</span>
|
|
@@ -2599,12 +2717,13 @@ export class JantComposeEditor extends LitElement {
|
|
|
2599
2717
|
"compose-tool-btn-active": this._showEmojiPicker,
|
|
2600
2718
|
})}
|
|
2601
2719
|
title=${this.labels.emoji}
|
|
2720
|
+
aria-pressed=${this._showEmojiPicker ? "true" : "false"}
|
|
2602
2721
|
@click=${() => this._toggleEmojiPicker()}
|
|
2603
2722
|
>
|
|
2604
2723
|
${renderComposeToolbarIcon(COMPOSE_TOOLBAR_ICONS.emoji)}
|
|
2605
2724
|
</button>
|
|
2606
2725
|
|
|
2607
|
-
<div class="compose-tool-
|
|
2726
|
+
<div class="compose-tool-gap"></div>
|
|
2608
2727
|
|
|
2609
2728
|
<button
|
|
2610
2729
|
type="button"
|
|
@@ -2613,6 +2732,7 @@ export class JantComposeEditor extends LitElement {
|
|
|
2613
2732
|
"compose-tool-btn-active": this._showRating,
|
|
2614
2733
|
})}
|
|
2615
2734
|
title=${this.labels.rate}
|
|
2735
|
+
aria-pressed=${this._showRating ? "true" : "false"}
|
|
2616
2736
|
@click=${() => {
|
|
2617
2737
|
const willShow = !this._showRating;
|
|
2618
2738
|
this._showRating = willShow;
|
|
@@ -2637,9 +2757,20 @@ export class JantComposeEditor extends LitElement {
|
|
|
2637
2757
|
"compose-tool-btn-active": this._showTitle,
|
|
2638
2758
|
})}
|
|
2639
2759
|
title=${this.labels.title}
|
|
2760
|
+
aria-pressed=${this._showTitle ? "true" : "false"}
|
|
2640
2761
|
@click=${() => {
|
|
2641
2762
|
const willShow = !this._showTitle;
|
|
2642
2763
|
this._showTitle = willShow;
|
|
2764
|
+
// Only this deliberate click is worth remembering. The other
|
|
2765
|
+
// writers of `_showTitle` — H1 promotion, format conversion,
|
|
2766
|
+
// fullscreen reveal — are the program acting on one post, not
|
|
2767
|
+
// the author stating a habit, so they stay silent.
|
|
2768
|
+
this.dispatchEvent(
|
|
2769
|
+
new CustomEvent("jant:title-toggle", {
|
|
2770
|
+
bubbles: true,
|
|
2771
|
+
detail: { showTitle: willShow },
|
|
2772
|
+
}),
|
|
2773
|
+
);
|
|
2643
2774
|
if (willShow) {
|
|
2644
2775
|
this.updateComplete.then(() => {
|
|
2645
2776
|
this.querySelector<HTMLInputElement>(
|
|
@@ -2683,14 +2814,10 @@ export class JantComposeEditor extends LitElement {
|
|
|
2683
2814
|
|
|
2684
2815
|
return html`
|
|
2685
2816
|
<div class="compose-thread-post-header">
|
|
2686
|
-
<div class="compose-segmented
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
"compose-format-pill-link": this.format === "link",
|
|
2691
|
-
"compose-format-pill-quote": this.format === "quote",
|
|
2692
|
-
})}
|
|
2693
|
-
></div>
|
|
2817
|
+
<div class="compose-segmented">
|
|
2818
|
+
<!-- No sliding indicator: the items size to their labels now, so a
|
|
2819
|
+
thirds-based pill would not line up. The active item carries its
|
|
2820
|
+
own background instead. -->
|
|
2694
2821
|
${formats.map(
|
|
2695
2822
|
(f) => html`
|
|
2696
2823
|
<button
|
|
@@ -2715,6 +2842,17 @@ export class JantComposeEditor extends LitElement {
|
|
|
2715
2842
|
`,
|
|
2716
2843
|
)}
|
|
2717
2844
|
</div>
|
|
2845
|
+
${this.positionLabel
|
|
2846
|
+
? html`<span class="compose-post-position"
|
|
2847
|
+
>${this.positionLabel}</span
|
|
2848
|
+
>`
|
|
2849
|
+
: nothing}
|
|
2850
|
+
${this.badgeLabel
|
|
2851
|
+
? html`<span class="compose-post-position compose-post-badge"
|
|
2852
|
+
>${this.badgeLabel}</span
|
|
2853
|
+
>`
|
|
2854
|
+
: nothing}
|
|
2855
|
+
${this.headerExtra ?? nothing}
|
|
2718
2856
|
${this.removable
|
|
2719
2857
|
? html`<button
|
|
2720
2858
|
type="button"
|
|
@@ -2756,11 +2894,11 @@ export class JantComposeEditor extends LitElement {
|
|
|
2756
2894
|
}
|
|
2757
2895
|
|
|
2758
2896
|
render() {
|
|
2897
|
+
// The format selector lives here in every mode — single post, reply, and
|
|
2898
|
+
// thread item alike — so there is exactly one place it can be.
|
|
2759
2899
|
return html`
|
|
2760
|
-
${this.
|
|
2761
|
-
|
|
2762
|
-
: nothing}
|
|
2763
|
-
<section class="compose-body">
|
|
2900
|
+
${this._renderFormatHeader()}
|
|
2901
|
+
<section class="compose-body" @click=${this._focusBodyFromBlankSpace}>
|
|
2764
2902
|
${this.format === "note"
|
|
2765
2903
|
? this._renderNoteFields()
|
|
2766
2904
|
: this.format === "link"
|