@jant/core 0.3.35 → 0.3.37
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/export.js +1 -1
- package/bin/commands/import-site.js +529 -0
- package/bin/commands/reset-password.js +3 -2
- package/dist/client/assets/heic-to-DIRPI3VF.js +1 -0
- package/dist/client/assets/module-RjUF93sV.js +716 -0
- package/dist/client/assets/native-48B9X9Wg.js +1 -0
- package/dist/client/assets/url-FWFqPJPb.js +1 -0
- package/dist/client/client.css +1 -1
- package/dist/client/client.js +4564 -3013
- package/dist/index.js +12885 -8161
- package/package.json +23 -6
- package/src/__tests__/helpers/app.ts +10 -10
- package/src/__tests__/helpers/db.ts +91 -87
- package/src/app.tsx +157 -31
- package/src/auth.ts +20 -2
- package/src/client/archive-nav.js +187 -0
- package/src/client/audio-player.ts +478 -0
- package/src/client/audio-processor.ts +84 -0
- package/src/{lib → client}/avatar-upload.ts +4 -3
- package/src/{lib → client}/collection-form-bridge.ts +2 -2
- package/src/{ui → client}/components/__tests__/jant-collection-form.test.ts +26 -9
- package/src/client/components/__tests__/jant-compose-dialog.test.ts +1140 -0
- package/src/client/components/__tests__/jant-compose-editor.test.ts +504 -0
- package/src/{ui → client}/components/__tests__/jant-post-form.test.ts +37 -17
- package/src/{ui → client}/components/__tests__/jant-settings-avatar.test.ts +2 -2
- package/src/{ui → client}/components/__tests__/jant-settings-general.test.ts +3 -3
- package/src/client/components/collection-sidebar-types.ts +43 -0
- package/src/{ui → client}/components/collection-types.ts +3 -4
- package/src/client/components/compose-types.ts +174 -0
- package/src/client/components/jant-collection-form.ts +667 -0
- package/src/client/components/jant-collection-sidebar.ts +805 -0
- package/src/client/components/jant-compose-dialog.ts +2161 -0
- package/src/client/components/jant-compose-editor.ts +1813 -0
- package/src/client/components/jant-compose-fullscreen.ts +283 -0
- package/src/client/components/jant-media-lightbox.ts +259 -0
- package/src/{ui → client}/components/jant-nav-manager.ts +97 -298
- package/src/{ui → client}/components/jant-post-form.ts +141 -12
- package/src/client/components/jant-post-menu.ts +1019 -0
- package/src/{ui → client}/components/jant-settings-avatar.ts +3 -3
- package/src/{ui → client}/components/jant-settings-general.ts +38 -4
- package/src/client/components/jant-text-preview.ts +232 -0
- package/src/{ui → client}/components/nav-manager-types.ts +6 -18
- package/src/{ui → client}/components/post-form-template.ts +137 -38
- package/src/{ui → client}/components/post-form-types.ts +15 -4
- package/src/client/compose-bridge.ts +583 -0
- package/src/{lib → client}/image-processor.ts +26 -8
- package/src/client/lazy-slugify.ts +51 -0
- package/src/client/media-metadata.ts +247 -0
- package/src/client/multipart-upload.ts +160 -0
- package/src/{lib → client}/nav-manager-bridge.ts +1 -1
- package/src/{lib → client}/post-form-bridge.ts +53 -2
- package/src/{lib → client}/settings-bridge.ts +3 -15
- package/src/client/thread-context.ts +140 -0
- package/src/client/tiptap/bubble-menu.ts +205 -0
- package/src/client/tiptap/create-editor.ts +86 -0
- package/src/client/tiptap/exitable-marks.ts +73 -0
- package/src/client/tiptap/extensions.ts +65 -0
- package/src/client/tiptap/image-node.ts +482 -0
- package/src/client/tiptap/link-toolbar.ts +371 -0
- package/src/client/tiptap/more-break.ts +50 -0
- package/src/client/tiptap/paste-image.ts +129 -0
- package/src/client/tiptap/slash-commands.ts +438 -0
- package/src/{lib → client}/toast.ts +101 -3
- package/src/client/types/sortablejs.d.ts +44 -0
- package/src/client/upload-with-metadata.ts +54 -0
- package/src/client/video-processor.ts +207 -0
- package/src/client.ts +27 -17
- package/src/db/__tests__/migrations.test.ts +118 -0
- package/src/db/index.ts +52 -0
- package/src/db/migrations/0000_baseline.sql +269 -0
- package/src/db/migrations/0001_fts_setup.sql +31 -0
- package/src/db/migrations/meta/0000_snapshot.json +703 -119
- package/src/db/migrations/meta/0001_snapshot.json +1337 -0
- package/src/db/migrations/meta/_journal.json +4 -39
- package/src/db/schema.ts +409 -140
- package/src/i18n/__tests__/detect.test.ts +115 -0
- package/src/i18n/context.tsx +2 -2
- package/src/i18n/detect.ts +85 -1
- package/src/i18n/i18n.ts +1 -1
- package/src/i18n/index.ts +2 -1
- package/src/i18n/locales/en.po +783 -1087
- package/src/i18n/locales/en.ts +1 -1
- package/src/i18n/locales/zh-Hans.po +867 -812
- package/src/i18n/locales/zh-Hans.ts +1 -1
- package/src/i18n/locales/zh-Hant.po +878 -823
- package/src/i18n/locales/zh-Hant.ts +1 -1
- package/src/i18n/middleware.ts +6 -0
- package/src/index.ts +5 -7
- package/src/lib/__tests__/blurhash-placeholder.test.ts +75 -0
- package/src/lib/__tests__/constants.test.ts +0 -1
- package/src/lib/__tests__/markdown-to-tiptap.test.ts +358 -0
- package/src/lib/__tests__/nanoid.test.ts +26 -0
- package/src/lib/__tests__/resolve-config.test.ts +2 -2
- package/src/lib/__tests__/schemas.test.ts +186 -65
- package/src/lib/__tests__/slug.test.ts +126 -0
- package/src/lib/__tests__/sse.test.ts +6 -6
- package/src/lib/__tests__/summary.test.ts +264 -0
- package/src/lib/__tests__/theme.test.ts +1 -1
- package/src/lib/__tests__/timeline.test.ts +33 -30
- package/src/lib/__tests__/tiptap-to-markdown.test.ts +346 -0
- package/src/lib/__tests__/url.test.ts +2 -2
- package/src/lib/__tests__/view.test.ts +140 -65
- package/src/lib/blurhash-placeholder.ts +102 -0
- package/src/lib/constants.ts +3 -1
- package/src/lib/emoji-catalog.ts +963 -0
- package/src/lib/errors.ts +11 -8
- package/src/lib/feed.ts +77 -31
- package/src/lib/html.ts +2 -1
- package/src/lib/icon-catalog.ts +5033 -1
- package/src/lib/icons.ts +3 -2
- package/src/lib/index.ts +0 -1
- package/src/lib/markdown-to-tiptap.ts +286 -0
- package/src/lib/media-helpers.ts +22 -12
- package/src/lib/nanoid.ts +29 -0
- package/src/lib/navigation.ts +1 -1
- package/src/lib/render.tsx +24 -5
- package/src/lib/resolve-config.ts +13 -2
- package/src/lib/schemas.ts +226 -58
- package/src/lib/search-snippet.ts +34 -0
- package/src/lib/slug.ts +96 -0
- package/src/lib/sse.ts +6 -6
- package/src/lib/storage.ts +115 -7
- package/src/lib/summary.ts +158 -0
- package/src/lib/theme.ts +11 -8
- package/src/lib/timeline.ts +76 -34
- package/src/lib/tiptap-render.ts +191 -0
- package/src/lib/tiptap-to-markdown.ts +305 -0
- package/src/lib/upload.ts +263 -14
- package/src/lib/url.ts +37 -22
- package/src/lib/view.ts +236 -55
- package/src/middleware/__tests__/auth.test.ts +191 -11
- package/src/middleware/__tests__/onboarding.test.ts +12 -10
- package/src/middleware/auth.ts +63 -9
- package/src/middleware/error-handler.ts +3 -3
- package/src/middleware/onboarding.ts +1 -1
- package/src/middleware/secure-headers.ts +40 -0
- package/src/preset.css +83 -2
- package/src/routes/__tests__/compose.test.ts +17 -24
- package/src/routes/api/__tests__/collections.test.ts +109 -61
- package/src/routes/api/__tests__/nav-items.test.ts +46 -29
- package/src/routes/api/__tests__/posts.test.ts +132 -68
- package/src/routes/api/__tests__/search.test.ts +15 -2
- package/src/routes/api/__tests__/upload-multipart.test.ts +534 -0
- package/src/routes/api/collections.ts +57 -31
- package/src/routes/api/custom-urls.ts +80 -0
- package/src/routes/api/export.ts +31 -0
- package/src/routes/api/nav-items.ts +23 -19
- package/src/routes/api/posts.ts +81 -62
- package/src/routes/api/search.ts +3 -4
- package/src/routes/api/upload-multipart.ts +245 -0
- package/src/routes/api/upload.ts +92 -24
- package/src/routes/auth/__tests__/setup.test.ts +20 -60
- package/src/routes/auth/reset.tsx +5 -4
- package/src/routes/auth/setup.tsx +39 -31
- package/src/routes/auth/signin.tsx +13 -14
- package/src/routes/compose.tsx +27 -63
- package/src/routes/dash/__tests__/settings-avatar.test.ts +44 -9
- package/src/routes/dash/custom-urls.tsx +414 -0
- package/src/routes/dash/settings.tsx +475 -99
- package/src/routes/feed/__tests__/rss.test.ts +22 -23
- package/src/routes/feed/rss.ts +6 -2
- package/src/routes/feed/sitemap.ts +2 -12
- package/src/routes/pages/__tests__/collections.test.ts +5 -6
- package/src/routes/pages/__tests__/featured.test.ts +36 -18
- package/src/routes/pages/archive.tsx +177 -37
- package/src/routes/pages/collection.tsx +43 -14
- package/src/routes/pages/collections.tsx +11 -2
- package/src/routes/pages/featured.tsx +27 -3
- package/src/routes/pages/home.tsx +15 -14
- package/src/routes/pages/latest.tsx +1 -11
- package/src/routes/pages/new.tsx +39 -0
- package/src/routes/pages/page.tsx +95 -49
- package/src/routes/pages/search.tsx +1 -1
- package/src/services/__tests__/api-token.test.ts +135 -0
- package/src/services/__tests__/collection.test.ts +275 -227
- package/src/services/__tests__/custom-url.test.ts +213 -0
- package/src/services/__tests__/media.test.ts +162 -22
- package/src/services/__tests__/navigation.test.ts +109 -68
- package/src/services/__tests__/post-timeline.test.ts +205 -32
- package/src/services/__tests__/post.test.ts +800 -230
- package/src/services/__tests__/search.test.ts +67 -10
- package/src/services/__tests__/settings.test.ts +3 -3
- package/src/services/api-token.ts +166 -0
- package/src/services/auth.ts +17 -2
- package/src/services/collection.ts +397 -131
- package/src/services/custom-url.ts +188 -0
- package/src/services/export.ts +802 -0
- package/src/services/index.ts +26 -19
- package/src/services/media.ts +100 -22
- package/src/services/navigation.ts +158 -47
- package/src/services/path.ts +339 -0
- package/src/services/post.ts +764 -172
- package/src/services/search.ts +161 -74
- package/src/services/settings.ts +6 -2
- package/src/styles/components.css +293 -62
- package/src/styles/tokens.css +93 -5
- package/src/styles/ui.css +4349 -766
- package/src/types/bindings.ts +8 -0
- package/src/types/config.ts +34 -4
- package/src/types/constants.ts +17 -2
- package/src/types/entities.ts +83 -37
- package/src/types/operations.ts +20 -27
- package/src/types/props.ts +52 -17
- package/src/types/views.ts +48 -24
- package/src/ui/color-themes.ts +133 -23
- package/src/ui/compose/ComposeDialog.tsx +255 -16
- package/src/ui/compose/ComposePrompt.tsx +1 -1
- package/src/ui/dash/CrudPageHeader.tsx +1 -1
- package/src/ui/dash/ListItemRow.tsx +1 -1
- package/src/ui/dash/StatusBadge.tsx +12 -2
- package/src/ui/dash/appearance/AdvancedContent.tsx +71 -59
- package/src/ui/dash/appearance/ColorThemeContent.tsx +48 -33
- package/src/ui/dash/appearance/FontThemeContent.tsx +65 -73
- package/src/ui/dash/appearance/NavigationContent.tsx +106 -135
- package/src/ui/dash/index.ts +0 -3
- package/src/ui/dash/settings/AccountContent.tsx +87 -146
- package/src/ui/dash/settings/AccountMenuContent.tsx +147 -0
- package/src/ui/dash/settings/ApiTokensContent.tsx +232 -0
- package/src/ui/dash/settings/AvatarContent.tsx +78 -0
- package/src/ui/dash/settings/GeneralContent.tsx +3 -62
- package/src/ui/dash/settings/SessionsContent.tsx +159 -0
- package/src/ui/dash/settings/SettingsRootContent.tsx +266 -0
- package/src/ui/feed/LinkCard.tsx +89 -40
- package/src/ui/feed/NoteCard.tsx +39 -25
- package/src/ui/feed/PostStatusBadges.tsx +67 -0
- package/src/ui/feed/QuoteCard.tsx +38 -23
- package/src/ui/feed/ThreadPreview.tsx +90 -26
- package/src/ui/feed/TimelineFeed.tsx +3 -2
- package/src/ui/feed/TimelineItem.tsx +15 -6
- package/src/ui/feed/__tests__/thread-preview.test.ts +107 -0
- package/src/ui/feed/thread-preview-state.ts +61 -0
- package/src/ui/font-themes.ts +2 -2
- package/src/ui/layouts/BaseLayout.tsx +2 -2
- package/src/ui/layouts/SiteLayout.tsx +116 -103
- package/src/ui/pages/ArchivePage.tsx +923 -95
- package/src/ui/pages/CollectionPage.tsx +6 -35
- package/src/ui/pages/CollectionsPage.tsx +2 -1
- package/src/ui/pages/ComposePage.tsx +54 -0
- package/src/ui/pages/FeaturedPage.tsx +2 -1
- package/src/ui/pages/HomePage.tsx +1 -1
- package/src/ui/pages/PostPage.tsx +30 -45
- package/src/ui/pages/SearchPage.tsx +182 -38
- package/src/ui/shared/AdminBreadcrumb.tsx +29 -0
- package/src/ui/shared/CollectionsSidebar.tsx +239 -4
- package/src/ui/shared/MediaGallery.tsx +475 -41
- package/src/ui/shared/PostFooter.tsx +204 -0
- package/src/ui/shared/StarRating.tsx +27 -0
- package/src/ui/shared/__tests__/format-chars.test.ts +35 -0
- package/src/ui/shared/index.ts +0 -1
- package/src/db/migrations/0000_square_wallflower.sql +0 -118
- package/src/db/migrations/0001_add_search_fts.sql +0 -34
- package/src/db/migrations/0002_add_media_attachments.sql +0 -3
- package/src/db/migrations/0003_add_navigation_links.sql +0 -8
- package/src/db/migrations/0004_add_storage_provider.sql +0 -3
- package/src/db/migrations/0005_v2_schema_migration.sql +0 -268
- package/src/db/migrations/0006_rename_slug_to_path.sql +0 -5
- package/src/db/migrations/0007_post_collections_m2m.sql +0 -94
- package/src/db/migrations/0008_add_collection_dividers.sql +0 -8
- package/src/db/migrations/0009_drop_collection_show_divider.sql +0 -2
- package/src/db/migrations/0010_add_performance_indexes.sql +0 -16
- package/src/db/migrations/0011_add_path_registry.sql +0 -23
- package/src/db/migrations/meta/0003_snapshot.json +0 -821
- package/src/lib/__tests__/sqid.test.ts +0 -65
- package/src/lib/collections-reorder.ts +0 -28
- package/src/lib/compose-bridge.ts +0 -280
- package/src/lib/media-upload.ts +0 -148
- package/src/lib/sqid.ts +0 -79
- package/src/routes/api/__tests__/pages.test.ts +0 -218
- package/src/routes/api/pages.ts +0 -73
- package/src/routes/dash/__tests__/pages.test.ts +0 -226
- package/src/routes/dash/appearance.tsx +0 -240
- package/src/routes/dash/collections.tsx +0 -211
- package/src/routes/dash/index.tsx +0 -103
- package/src/routes/dash/media.tsx +0 -132
- package/src/routes/dash/pages.tsx +0 -239
- package/src/routes/dash/posts.tsx +0 -334
- package/src/routes/dash/redirects.tsx +0 -257
- package/src/routes/pages/post.tsx +0 -59
- package/src/services/__tests__/page.test.ts +0 -298
- package/src/services/__tests__/path-registry.test.ts +0 -165
- package/src/services/__tests__/redirect.test.ts +0 -159
- package/src/services/page.ts +0 -203
- package/src/services/path-registry.ts +0 -160
- package/src/services/redirect.ts +0 -97
- package/src/types/sortablejs.d.ts +0 -29
- package/src/ui/components/__tests__/jant-compose-dialog.test.ts +0 -512
- package/src/ui/components/__tests__/jant-compose-editor.test.ts +0 -272
- package/src/ui/components/compose-types.ts +0 -75
- package/src/ui/components/jant-collection-form.ts +0 -512
- package/src/ui/components/jant-compose-dialog.ts +0 -495
- package/src/ui/components/jant-compose-editor.ts +0 -814
- package/src/ui/dash/PageForm.tsx +0 -185
- package/src/ui/dash/PostList.tsx +0 -95
- package/src/ui/dash/appearance/AppearanceNav.tsx +0 -60
- package/src/ui/dash/collections/CollectionForm.tsx +0 -166
- package/src/ui/dash/collections/CollectionsListContent.tsx +0 -146
- package/src/ui/dash/collections/IconPickerGrid.tsx +0 -50
- package/src/ui/dash/collections/ViewCollectionContent.tsx +0 -103
- package/src/ui/dash/media/MediaListContent.tsx +0 -201
- package/src/ui/dash/media/ViewMediaContent.tsx +0 -208
- package/src/ui/dash/pages/PagesContent.tsx +0 -74
- package/src/ui/dash/posts/PostForm.tsx +0 -248
- package/src/ui/dash/settings/SettingsNav.tsx +0 -52
- package/src/ui/layouts/DashLayout.tsx +0 -165
- package/src/ui/pages/SinglePage.tsx +0 -23
- package/src/ui/shared/ThreadView.tsx +0 -136
- /package/src/{ui → client}/components/settings-types.ts +0 -0
|
@@ -87,7 +87,7 @@ export class JantSettingsAvatar extends LitElement {
|
|
|
87
87
|
new CustomEvent("jant:settings-save", {
|
|
88
88
|
bubbles: true,
|
|
89
89
|
detail: {
|
|
90
|
-
endpoint: "/
|
|
90
|
+
endpoint: "/settings/avatar/display",
|
|
91
91
|
data: { showHeaderAvatar: this._showInHeader ? "true" : "" },
|
|
92
92
|
section: "avatar-display",
|
|
93
93
|
},
|
|
@@ -101,7 +101,7 @@ export class JantSettingsAvatar extends LitElement {
|
|
|
101
101
|
this.dispatchEvent(
|
|
102
102
|
new CustomEvent("jant:avatar-remove", {
|
|
103
103
|
bubbles: true,
|
|
104
|
-
detail: { endpoint: "/
|
|
104
|
+
detail: { endpoint: "/settings/avatar/remove" },
|
|
105
105
|
}),
|
|
106
106
|
);
|
|
107
107
|
}
|
|
@@ -146,7 +146,7 @@ export class JantSettingsAvatar extends LitElement {
|
|
|
146
146
|
${this._renderPreview()}
|
|
147
147
|
<div class="flex flex-col gap-2">
|
|
148
148
|
<form
|
|
149
|
-
action="/
|
|
149
|
+
action="/settings/avatar"
|
|
150
150
|
method="post"
|
|
151
151
|
enctype="multipart/form-data"
|
|
152
152
|
class="inline"
|
|
@@ -170,7 +170,7 @@ export class JantSettingsGeneral extends LitElement {
|
|
|
170
170
|
new CustomEvent("jant:settings-save", {
|
|
171
171
|
bubbles: true,
|
|
172
172
|
detail: {
|
|
173
|
-
endpoint: "/
|
|
173
|
+
endpoint: "/settings/general",
|
|
174
174
|
data: {
|
|
175
175
|
siteName: this._siteName,
|
|
176
176
|
siteDescription: this._siteDescription,
|
|
@@ -203,7 +203,7 @@ export class JantSettingsGeneral extends LitElement {
|
|
|
203
203
|
new CustomEvent("jant:settings-save", {
|
|
204
204
|
bubbles: true,
|
|
205
205
|
detail: {
|
|
206
|
-
endpoint: "/
|
|
206
|
+
endpoint: "/settings/general/seo",
|
|
207
207
|
data: { noindex: this._noindex ? "" : "true" },
|
|
208
208
|
section: "seo",
|
|
209
209
|
},
|
|
@@ -211,6 +211,24 @@ export class JantSettingsGeneral extends LitElement {
|
|
|
211
211
|
);
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
/** Submit on Enter from non-textarea fields */
|
|
215
|
+
private _onKeydown(
|
|
216
|
+
e: globalThis.KeyboardEvent,
|
|
217
|
+
save: () => void,
|
|
218
|
+
dirty: boolean,
|
|
219
|
+
loading: boolean,
|
|
220
|
+
) {
|
|
221
|
+
if (
|
|
222
|
+
e.key === "Enter" &&
|
|
223
|
+
!loading &&
|
|
224
|
+
dirty &&
|
|
225
|
+
!(e.target instanceof HTMLTextAreaElement)
|
|
226
|
+
) {
|
|
227
|
+
e.preventDefault();
|
|
228
|
+
save();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
214
232
|
// ── Render helpers ────────────────────────────────────────────────
|
|
215
233
|
|
|
216
234
|
private _renderActions(
|
|
@@ -258,7 +276,15 @@ export class JantSettingsGeneral extends LitElement {
|
|
|
258
276
|
|
|
259
277
|
private _renderGeneralForm() {
|
|
260
278
|
return html`
|
|
261
|
-
<div
|
|
279
|
+
<div
|
|
280
|
+
@keydown=${(e: globalThis.KeyboardEvent) =>
|
|
281
|
+
this._onKeydown(
|
|
282
|
+
e,
|
|
283
|
+
() => this._saveGeneral(),
|
|
284
|
+
this._generalDirty,
|
|
285
|
+
this._generalLoading,
|
|
286
|
+
)}
|
|
287
|
+
>
|
|
262
288
|
<h2 class="text-lg font-semibold mb-4">${this.labels.general}</h2>
|
|
263
289
|
<div class="flex flex-col gap-4">
|
|
264
290
|
<div class="field">
|
|
@@ -366,7 +392,15 @@ export class JantSettingsGeneral extends LitElement {
|
|
|
366
392
|
|
|
367
393
|
private _renderSeoForm() {
|
|
368
394
|
return html`
|
|
369
|
-
<div
|
|
395
|
+
<div
|
|
396
|
+
@keydown=${(e: globalThis.KeyboardEvent) =>
|
|
397
|
+
this._onKeydown(
|
|
398
|
+
e,
|
|
399
|
+
() => this._saveSeo(),
|
|
400
|
+
this._seoDirty,
|
|
401
|
+
this._seoLoading,
|
|
402
|
+
)}
|
|
403
|
+
>
|
|
370
404
|
<h2 class="text-lg font-semibold mb-4">${this.labels.seo}</h2>
|
|
371
405
|
<div>
|
|
372
406
|
<label class="flex items-center gap-2 cursor-pointer">
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text Preview Dialog
|
|
3
|
+
*
|
|
4
|
+
* Displays attached text content (TipTap-authored) in a modal dialog.
|
|
5
|
+
* Intercepts clicks on [data-text-preview-url] buttons, fetches the
|
|
6
|
+
* stored { json, html } envelope from the URL, and renders the HTML
|
|
7
|
+
* in a native <dialog>.
|
|
8
|
+
*
|
|
9
|
+
* Light DOM only — BaseCoat and Tailwind classes apply directly.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { LitElement, html, nothing } from "lit";
|
|
13
|
+
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
14
|
+
import { showToast } from "../toast.js";
|
|
15
|
+
import { jsonToMarkdown } from "../tiptap/create-editor.js";
|
|
16
|
+
|
|
17
|
+
export class JantTextPreview extends LitElement {
|
|
18
|
+
static properties = {
|
|
19
|
+
_open: { state: true },
|
|
20
|
+
_html: { state: true },
|
|
21
|
+
_loading: { state: true },
|
|
22
|
+
_copied: { state: true },
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
declare _open: boolean;
|
|
26
|
+
declare _html: string;
|
|
27
|
+
declare _loading: boolean;
|
|
28
|
+
declare _copied: boolean;
|
|
29
|
+
/** Raw text for the copy button (markdown / plain text source) */
|
|
30
|
+
#rawText = "";
|
|
31
|
+
|
|
32
|
+
createRenderRoot() {
|
|
33
|
+
this.innerHTML = "";
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
constructor() {
|
|
38
|
+
super();
|
|
39
|
+
this._open = false;
|
|
40
|
+
this._html = "";
|
|
41
|
+
this._loading = false;
|
|
42
|
+
this._copied = false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
connectedCallback() {
|
|
46
|
+
super.connectedCallback();
|
|
47
|
+
document.addEventListener("click", this.#handleDocumentClick);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
disconnectedCallback() {
|
|
51
|
+
super.disconnectedCallback();
|
|
52
|
+
document.removeEventListener("click", this.#handleDocumentClick);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
#handleDocumentClick = (e: Event) => {
|
|
56
|
+
const target = e.target as HTMLElement;
|
|
57
|
+
const btn = target.closest<HTMLButtonElement>("[data-text-preview-id]");
|
|
58
|
+
if (!btn) return;
|
|
59
|
+
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
const mediaId = btn.dataset.textPreviewId;
|
|
62
|
+
if (mediaId) this.#openPreview(mediaId);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
async #openPreview(mediaId: string) {
|
|
66
|
+
this._loading = true;
|
|
67
|
+
this._open = true;
|
|
68
|
+
|
|
69
|
+
document.body.style.overflow = "hidden";
|
|
70
|
+
|
|
71
|
+
await this.updateComplete;
|
|
72
|
+
this.querySelector<HTMLDialogElement>(".text-preview-dialog")?.showModal();
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const res = await fetch(`/api/media/${mediaId}/content`);
|
|
76
|
+
if (!res.ok) throw new Error("Fetch failed");
|
|
77
|
+
|
|
78
|
+
const raw = await res.text();
|
|
79
|
+
|
|
80
|
+
// Try parsing as { json, html } envelope (TipTap rich text)
|
|
81
|
+
try {
|
|
82
|
+
const envelope = JSON.parse(raw) as {
|
|
83
|
+
json?: import("@tiptap/core").JSONContent;
|
|
84
|
+
html?: string;
|
|
85
|
+
};
|
|
86
|
+
this._html = envelope.html || "";
|
|
87
|
+
// Serialize JSON → markdown via headless TipTap editor
|
|
88
|
+
this.#rawText = envelope.json ? jsonToMarkdown(envelope.json) : "";
|
|
89
|
+
} catch {
|
|
90
|
+
// Not JSON — raw markdown / plain text, copy as-is
|
|
91
|
+
this.#rawText = raw;
|
|
92
|
+
this._html = `<pre>${raw.replace(/</g, "<")}</pre>`;
|
|
93
|
+
}
|
|
94
|
+
} catch {
|
|
95
|
+
this._html = "<p>Failed to load content.</p>";
|
|
96
|
+
this.#rawText = "";
|
|
97
|
+
} finally {
|
|
98
|
+
this._loading = false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
#close() {
|
|
103
|
+
this.querySelector<HTMLDialogElement>(".text-preview-dialog")?.close();
|
|
104
|
+
document.body.style.overflow = "";
|
|
105
|
+
this._open = false;
|
|
106
|
+
this._html = "";
|
|
107
|
+
this.#rawText = "";
|
|
108
|
+
this._copied = false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async #copy() {
|
|
112
|
+
if (!this.#rawText) return;
|
|
113
|
+
try {
|
|
114
|
+
await globalThis.navigator.clipboard.writeText(this.#rawText);
|
|
115
|
+
this._copied = true;
|
|
116
|
+
showToast("Copied.");
|
|
117
|
+
setTimeout(() => {
|
|
118
|
+
this._copied = false;
|
|
119
|
+
}, 2000);
|
|
120
|
+
} catch {
|
|
121
|
+
showToast("Could not copy.", "error");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#handleKeydown = (e: globalThis.KeyboardEvent) => {
|
|
126
|
+
if (e.key === "Escape") {
|
|
127
|
+
e.preventDefault();
|
|
128
|
+
e.stopPropagation();
|
|
129
|
+
this.#close();
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
render() {
|
|
134
|
+
if (!this._open) return nothing;
|
|
135
|
+
|
|
136
|
+
return html`
|
|
137
|
+
<dialog
|
|
138
|
+
class="text-preview-dialog"
|
|
139
|
+
@cancel=${(e: Event) => {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
this.#close();
|
|
142
|
+
}}
|
|
143
|
+
@keydown=${this.#handleKeydown}
|
|
144
|
+
@click=${(e: Event) => {
|
|
145
|
+
// Close on backdrop click
|
|
146
|
+
if ((e.target as HTMLElement).tagName === "DIALOG") {
|
|
147
|
+
this.#close();
|
|
148
|
+
}
|
|
149
|
+
}}
|
|
150
|
+
>
|
|
151
|
+
<div class="text-preview-content">
|
|
152
|
+
<div class="text-preview-toolbar">
|
|
153
|
+
<button
|
|
154
|
+
type="button"
|
|
155
|
+
class="text-preview-btn"
|
|
156
|
+
@click=${() => this.#copy()}
|
|
157
|
+
?disabled=${this._loading || !this.#rawText}
|
|
158
|
+
title="Copy"
|
|
159
|
+
>
|
|
160
|
+
${this._copied
|
|
161
|
+
? html`<svg
|
|
162
|
+
width="16"
|
|
163
|
+
height="16"
|
|
164
|
+
viewBox="0 0 24 24"
|
|
165
|
+
fill="none"
|
|
166
|
+
stroke="currentColor"
|
|
167
|
+
stroke-width="2"
|
|
168
|
+
stroke-linecap="round"
|
|
169
|
+
stroke-linejoin="round"
|
|
170
|
+
>
|
|
171
|
+
<path d="M20 6 9 17l-5-5" />
|
|
172
|
+
</svg>`
|
|
173
|
+
: html`<svg
|
|
174
|
+
width="16"
|
|
175
|
+
height="16"
|
|
176
|
+
viewBox="0 0 24 24"
|
|
177
|
+
fill="none"
|
|
178
|
+
stroke="currentColor"
|
|
179
|
+
stroke-width="2"
|
|
180
|
+
stroke-linecap="round"
|
|
181
|
+
stroke-linejoin="round"
|
|
182
|
+
>
|
|
183
|
+
<rect width="14" height="14" x="8" y="8" rx="2" />
|
|
184
|
+
<path
|
|
185
|
+
d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"
|
|
186
|
+
/>
|
|
187
|
+
</svg>`}
|
|
188
|
+
</button>
|
|
189
|
+
<button
|
|
190
|
+
type="button"
|
|
191
|
+
class="text-preview-btn"
|
|
192
|
+
@click=${() => this.#close()}
|
|
193
|
+
title="Close"
|
|
194
|
+
>
|
|
195
|
+
<svg
|
|
196
|
+
width="16"
|
|
197
|
+
height="16"
|
|
198
|
+
viewBox="0 0 24 24"
|
|
199
|
+
fill="none"
|
|
200
|
+
stroke="currentColor"
|
|
201
|
+
stroke-width="2"
|
|
202
|
+
stroke-linecap="round"
|
|
203
|
+
stroke-linejoin="round"
|
|
204
|
+
>
|
|
205
|
+
<path d="M18 6 6 18M6 6l12 12" />
|
|
206
|
+
</svg>
|
|
207
|
+
</button>
|
|
208
|
+
</div>
|
|
209
|
+
${this._loading
|
|
210
|
+
? html`<div class="text-preview-loading">
|
|
211
|
+
<svg
|
|
212
|
+
class="animate-spin size-5"
|
|
213
|
+
viewBox="0 0 24 24"
|
|
214
|
+
fill="none"
|
|
215
|
+
stroke="currentColor"
|
|
216
|
+
stroke-width="2"
|
|
217
|
+
stroke-linecap="round"
|
|
218
|
+
stroke-linejoin="round"
|
|
219
|
+
>
|
|
220
|
+
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
|
221
|
+
</svg>
|
|
222
|
+
</div>`
|
|
223
|
+
: html`<div class="text-preview-body prose">
|
|
224
|
+
${unsafeHTML(this._html)}
|
|
225
|
+
</div>`}
|
|
226
|
+
</div>
|
|
227
|
+
</dialog>
|
|
228
|
+
`;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
customElements.define("jant-text-preview", JantTextPreview);
|
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
export interface NavManagerItem {
|
|
6
|
-
id:
|
|
7
|
-
type: "
|
|
6
|
+
id: string;
|
|
7
|
+
type: "link" | "system";
|
|
8
8
|
label: string;
|
|
9
9
|
url: string;
|
|
10
|
-
pageId: number | null;
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
export interface SystemNavConfig {
|
|
@@ -17,17 +16,10 @@ export interface SystemNavConfig {
|
|
|
17
16
|
description: string;
|
|
18
17
|
}
|
|
19
18
|
|
|
20
|
-
export interface AvailablePage {
|
|
21
|
-
id: number;
|
|
22
|
-
title: string;
|
|
23
|
-
slug: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
19
|
export interface NavManagerLabels {
|
|
27
20
|
preview: string;
|
|
28
21
|
navigationItems: string;
|
|
29
22
|
emptyState: string;
|
|
30
|
-
page: string;
|
|
31
23
|
link: string;
|
|
32
24
|
system: string;
|
|
33
25
|
toggleEdit: string;
|
|
@@ -35,7 +27,6 @@ export interface NavManagerLabels {
|
|
|
35
27
|
url: string;
|
|
36
28
|
save: string;
|
|
37
29
|
delete: string;
|
|
38
|
-
editPage: string;
|
|
39
30
|
remove: string;
|
|
40
31
|
orderSaved: string;
|
|
41
32
|
labelRequired: string;
|
|
@@ -43,30 +34,27 @@ export interface NavManagerLabels {
|
|
|
43
34
|
deleteFailed: string;
|
|
44
35
|
systemLinks: string;
|
|
45
36
|
systemLinksDescription: string;
|
|
46
|
-
addPageToNavigation: string;
|
|
47
37
|
addCustomLinkToNavigation: string;
|
|
48
|
-
choosePage: string;
|
|
49
|
-
searchPages: string;
|
|
50
|
-
noPagesFound: string;
|
|
51
38
|
addLink: string;
|
|
52
39
|
addLinkDescription: string;
|
|
53
|
-
allPagesInNav: string;
|
|
54
40
|
urlPlaceholder: string;
|
|
55
41
|
labelAndUrlRequired: string;
|
|
56
42
|
maxVisibleLinks: string;
|
|
43
|
+
maxVisibleLinksDescription: string;
|
|
57
44
|
maxVisibleSaved: string;
|
|
58
45
|
useFeaturedAsDefault: string;
|
|
46
|
+
useFeaturedAsDefaultDescription: string;
|
|
59
47
|
homeViewSaved: string;
|
|
60
48
|
latest: string;
|
|
61
49
|
featured: string;
|
|
62
50
|
}
|
|
63
51
|
|
|
64
52
|
export interface NavManagerUpdateDetail {
|
|
65
|
-
id:
|
|
53
|
+
id: string;
|
|
66
54
|
label: string;
|
|
67
55
|
url?: string;
|
|
68
56
|
}
|
|
69
57
|
|
|
70
58
|
export interface NavManagerDeleteDetail {
|
|
71
|
-
id:
|
|
59
|
+
id: string;
|
|
72
60
|
}
|
|
@@ -1,6 +1,91 @@
|
|
|
1
1
|
import { html, nothing } from "lit";
|
|
2
|
+
import { unsafeSVG } from "lit/directives/unsafe-svg.js";
|
|
2
3
|
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
3
4
|
import type { JantPostForm } from "./jant-post-form.js";
|
|
5
|
+
import type { PostMediaItem } from "./post-form-types.js";
|
|
6
|
+
import { getMediaCategory } from "../../lib/upload.js";
|
|
7
|
+
|
|
8
|
+
function renderFileIcon(mimeType: string) {
|
|
9
|
+
const doc = `<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/>`;
|
|
10
|
+
|
|
11
|
+
let inner: string;
|
|
12
|
+
if (mimeType === "application/pdf") {
|
|
13
|
+
inner = `<text x="12" y="16.5" text-anchor="middle" fill="currentColor" stroke="none" font-size="6" font-weight="700" font-family="system-ui, sans-serif">PDF</text>`;
|
|
14
|
+
} else if (mimeType === "text/markdown") {
|
|
15
|
+
inner = `<text x="12" y="16.5" text-anchor="middle" fill="currentColor" stroke="none" font-size="10" font-weight="700" font-family="system-ui, sans-serif">#</text>`;
|
|
16
|
+
} else if (mimeType === "text/csv") {
|
|
17
|
+
inner = `<line x1="8" y1="12" x2="16" y2="12"/><line x1="8" y1="15" x2="16" y2="15"/><line x1="8" y1="18" x2="16" y2="18"/><line x1="10.7" y1="12" x2="10.7" y2="18"/><line x1="13.3" y1="12" x2="13.3" y2="18"/>`;
|
|
18
|
+
} else if (getMediaCategory(mimeType) === "archive") {
|
|
19
|
+
inner = `<line x1="12" y1="10" x2="12" y2="11.5"/><line x1="12" y1="13" x2="12" y2="14.5"/><line x1="12" y1="16" x2="12" y2="17.5"/>`;
|
|
20
|
+
} else if (mimeType.startsWith("audio/")) {
|
|
21
|
+
return html`<svg
|
|
22
|
+
width="24"
|
|
23
|
+
height="24"
|
|
24
|
+
viewBox="0 0 24 24"
|
|
25
|
+
fill="none"
|
|
26
|
+
stroke="currentColor"
|
|
27
|
+
stroke-width="1.5"
|
|
28
|
+
stroke-linecap="round"
|
|
29
|
+
stroke-linejoin="round"
|
|
30
|
+
>
|
|
31
|
+
${unsafeSVG(
|
|
32
|
+
`<path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/>`,
|
|
33
|
+
)}
|
|
34
|
+
</svg>`;
|
|
35
|
+
} else if (mimeType.startsWith("video/")) {
|
|
36
|
+
return html`<svg
|
|
37
|
+
width="24"
|
|
38
|
+
height="24"
|
|
39
|
+
viewBox="0 0 24 24"
|
|
40
|
+
fill="none"
|
|
41
|
+
stroke="currentColor"
|
|
42
|
+
stroke-width="1.5"
|
|
43
|
+
stroke-linecap="round"
|
|
44
|
+
stroke-linejoin="round"
|
|
45
|
+
>
|
|
46
|
+
${unsafeSVG(
|
|
47
|
+
`<polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/>`,
|
|
48
|
+
)}
|
|
49
|
+
</svg>`;
|
|
50
|
+
} else {
|
|
51
|
+
inner = `<line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><line x1="10" y1="9" x2="8" y2="9"/>`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return html`<svg
|
|
55
|
+
width="24"
|
|
56
|
+
height="24"
|
|
57
|
+
viewBox="0 0 24 24"
|
|
58
|
+
fill="none"
|
|
59
|
+
stroke="currentColor"
|
|
60
|
+
stroke-width="1.5"
|
|
61
|
+
stroke-linecap="round"
|
|
62
|
+
stroke-linejoin="round"
|
|
63
|
+
>
|
|
64
|
+
${unsafeSVG(doc + inner)}
|
|
65
|
+
</svg>`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function renderMediaThumb(item: PostMediaItem) {
|
|
69
|
+
const category = getMediaCategory(item.mimeType);
|
|
70
|
+
|
|
71
|
+
if (category === "image") {
|
|
72
|
+
return html`<img
|
|
73
|
+
src=${item.thumbUrl}
|
|
74
|
+
alt=${item.alt}
|
|
75
|
+
class="w-full h-full object-cover rounded-lg border"
|
|
76
|
+
loading="lazy"
|
|
77
|
+
/>`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return html`<div
|
|
81
|
+
class="w-full h-full rounded-lg border bg-muted flex flex-col items-center justify-center gap-1 p-1 text-muted-foreground"
|
|
82
|
+
>
|
|
83
|
+
${renderFileIcon(item.mimeType)}
|
|
84
|
+
<span class="text-[10px] leading-tight text-center truncate w-full px-1"
|
|
85
|
+
>${item.originalName}</span
|
|
86
|
+
>
|
|
87
|
+
</div>`;
|
|
88
|
+
}
|
|
4
89
|
|
|
5
90
|
function renderMediaList(component: JantPostForm) {
|
|
6
91
|
const { media, labels, _mediaIds } = component;
|
|
@@ -32,12 +117,7 @@ function renderMediaList(component: JantPostForm) {
|
|
|
32
117
|
}
|
|
33
118
|
|
|
34
119
|
return html`<div class="relative group aspect-square" data-media-id=${id}>
|
|
35
|
-
|
|
36
|
-
src=${item.thumbUrl}
|
|
37
|
-
alt=${item.alt}
|
|
38
|
-
class="w-full h-full object-cover rounded-lg border"
|
|
39
|
-
loading="lazy"
|
|
40
|
-
/>
|
|
120
|
+
${renderMediaThumb(item)}
|
|
41
121
|
<button
|
|
42
122
|
type="button"
|
|
43
123
|
class="absolute top-1 right-1 w-5 h-5 flex items-center justify-center bg-black/60 text-white rounded-full text-xs opacity-0 group-hover:opacity-100 transition-opacity cursor-pointer"
|
|
@@ -107,18 +187,33 @@ export function renderPostForm(component: JantPostForm) {
|
|
|
107
187
|
class="input"
|
|
108
188
|
placeholder=${component.labels.titlePlaceholder}
|
|
109
189
|
.value=${component._title}
|
|
110
|
-
@input=${(e: Event) => component.
|
|
190
|
+
@input=${(e: Event) => component.handleTitleInput(e)}
|
|
191
|
+
/>
|
|
192
|
+
</div>
|
|
193
|
+
|
|
194
|
+
<div class="field">
|
|
195
|
+
<label class="label">${component.labels.slugLabel}</label>
|
|
196
|
+
<input
|
|
197
|
+
type="text"
|
|
198
|
+
class="input"
|
|
199
|
+
placeholder=${component.labels.slugPlaceholder}
|
|
200
|
+
.value=${component._slug}
|
|
201
|
+
@input=${(e: Event) => component.handleSlugInput(e)}
|
|
111
202
|
/>
|
|
203
|
+
${component._slug
|
|
204
|
+
? html`<p class="text-xs text-muted-foreground mt-1">
|
|
205
|
+
${component.siteUrl}/${component._slug}
|
|
206
|
+
</p>`
|
|
207
|
+
: html`<p class="text-xs text-muted-foreground mt-1">
|
|
208
|
+
${component.labels.slugHelp}
|
|
209
|
+
</p>`}
|
|
112
210
|
</div>
|
|
113
211
|
|
|
114
212
|
<div class="field">
|
|
115
213
|
<label class="label">${component.labels.bodyLabel}</label>
|
|
116
|
-
<
|
|
117
|
-
class="
|
|
118
|
-
|
|
119
|
-
.value=${component._body}
|
|
120
|
-
@input=${(e: Event) => component.handleInput("_body", e)}
|
|
121
|
-
></textarea>
|
|
214
|
+
<div
|
|
215
|
+
class="post-form-tiptap-body compose-tiptap-body border rounded-lg p-3 min-h-32"
|
|
216
|
+
></div>
|
|
122
217
|
</div>
|
|
123
218
|
|
|
124
219
|
<div class="field">
|
|
@@ -173,33 +268,37 @@ export function renderPostForm(component: JantPostForm) {
|
|
|
173
268
|
</select>
|
|
174
269
|
</div>
|
|
175
270
|
|
|
176
|
-
<div class="
|
|
177
|
-
<label class="
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
component.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
class="checkbox"
|
|
193
|
-
.checked=${component._pinned}
|
|
194
|
-
@change=${(e: Event) => {
|
|
195
|
-
const target = e.target as HTMLInputElement;
|
|
196
|
-
component._pinned = target.checked;
|
|
197
|
-
}}
|
|
198
|
-
/>
|
|
199
|
-
${component.labels.pinnedLabel}
|
|
200
|
-
</label>
|
|
271
|
+
<div class="field">
|
|
272
|
+
<label class="label">${component.labels.visibilityLabel}</label>
|
|
273
|
+
<select
|
|
274
|
+
class="select"
|
|
275
|
+
.value=${component._visibility}
|
|
276
|
+
@change=${(e: Event) => {
|
|
277
|
+
const target = e.target as HTMLSelectElement;
|
|
278
|
+
component._visibility =
|
|
279
|
+
(target.value as typeof component._visibility) ?? "public";
|
|
280
|
+
}}
|
|
281
|
+
>
|
|
282
|
+
<option value="public">${component.labels.visibilityPublic}</option>
|
|
283
|
+
<option value="unlisted">
|
|
284
|
+
${component.labels.visibilityUnlisted}
|
|
285
|
+
</option>
|
|
286
|
+
</select>
|
|
201
287
|
</div>
|
|
202
288
|
|
|
289
|
+
<label class="flex items-center gap-2 text-sm">
|
|
290
|
+
<input
|
|
291
|
+
type="checkbox"
|
|
292
|
+
class="checkbox"
|
|
293
|
+
.checked=${component._pinned}
|
|
294
|
+
@change=${(e: Event) => {
|
|
295
|
+
const target = e.target as HTMLInputElement;
|
|
296
|
+
component._pinned = target.checked;
|
|
297
|
+
}}
|
|
298
|
+
/>
|
|
299
|
+
${component.labels.pinnedLabel}
|
|
300
|
+
</label>
|
|
301
|
+
|
|
203
302
|
${renderCollections(component)}
|
|
204
303
|
|
|
205
304
|
<div class="flex gap-2">
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared type definitions for the
|
|
2
|
+
* Shared type definitions for the post form Lit component.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
export type PostFormat = "note" | "link" | "quote";
|
|
6
6
|
export type PostStatus = "published" | "draft";
|
|
7
|
+
export type PostVisibility = "public" | "unlisted";
|
|
7
8
|
|
|
8
9
|
export interface PostFormLabels {
|
|
9
10
|
formatLabel: string;
|
|
@@ -12,6 +13,9 @@ export interface PostFormLabels {
|
|
|
12
13
|
quoteOption: string;
|
|
13
14
|
titleLabel: string;
|
|
14
15
|
titlePlaceholder: string;
|
|
16
|
+
slugLabel: string;
|
|
17
|
+
slugPlaceholder: string;
|
|
18
|
+
slugHelp: string;
|
|
15
19
|
bodyLabel: string;
|
|
16
20
|
bodyPlaceholder: string;
|
|
17
21
|
urlLabel: string;
|
|
@@ -25,7 +29,9 @@ export interface PostFormLabels {
|
|
|
25
29
|
statusLabel: string;
|
|
26
30
|
statusPublished: string;
|
|
27
31
|
statusDraft: string;
|
|
28
|
-
|
|
32
|
+
visibilityLabel: string;
|
|
33
|
+
visibilityPublic: string;
|
|
34
|
+
visibilityUnlisted: string;
|
|
29
35
|
pinnedLabel: string;
|
|
30
36
|
collectionsLabel: string;
|
|
31
37
|
submitLabel: string;
|
|
@@ -35,16 +41,18 @@ export interface PostFormLabels {
|
|
|
35
41
|
mediaDialogLoading: string;
|
|
36
42
|
submitSuccessMessage: string;
|
|
37
43
|
submitErrorMessage: string;
|
|
44
|
+
draftFallbackMessage: string;
|
|
38
45
|
}
|
|
39
46
|
|
|
40
47
|
export interface PostFormInitial {
|
|
41
48
|
format: PostFormat;
|
|
42
49
|
title: string;
|
|
50
|
+
slug: string;
|
|
43
51
|
body: string;
|
|
44
52
|
url: string;
|
|
45
53
|
quoteText: string;
|
|
46
54
|
status: PostStatus;
|
|
47
|
-
|
|
55
|
+
visibility: PostVisibility;
|
|
48
56
|
pinned: boolean;
|
|
49
57
|
rating: number;
|
|
50
58
|
collectionIds: number[];
|
|
@@ -62,6 +70,8 @@ export interface PostMediaItem {
|
|
|
62
70
|
id: string;
|
|
63
71
|
thumbUrl: string;
|
|
64
72
|
alt: string;
|
|
73
|
+
mimeType: string;
|
|
74
|
+
originalName: string;
|
|
65
75
|
}
|
|
66
76
|
|
|
67
77
|
export interface PostSubmitDetail {
|
|
@@ -70,9 +80,10 @@ export interface PostSubmitDetail {
|
|
|
70
80
|
data: {
|
|
71
81
|
format: PostFormat;
|
|
72
82
|
title?: string;
|
|
83
|
+
slug?: string;
|
|
73
84
|
body?: string;
|
|
74
85
|
status: PostStatus;
|
|
75
|
-
|
|
86
|
+
visibility: PostVisibility;
|
|
76
87
|
pinned: boolean;
|
|
77
88
|
url?: string;
|
|
78
89
|
quoteText?: string;
|