@jant/core 0.3.35 → 0.3.36
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/dist/client/assets/module-RjUF93sV.js +716 -0
- package/dist/client/assets/native-48B9X9Wg.js +1 -0
- package/dist/client/assets/url-8Dj-5CLW.js +1 -0
- package/dist/client/client.css +1 -1
- package/dist/client/client.js +3109 -2294
- package/dist/index.js +3026 -2778
- package/package.json +13 -4
- package/src/__tests__/helpers/app.ts +1 -1
- package/src/__tests__/helpers/db.ts +6 -0
- package/src/app.tsx +1 -5
- package/src/{lib → client}/avatar-upload.ts +1 -1
- 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/{ui → client}/components/__tests__/jant-compose-dialog.test.ts +46 -14
- package/src/{ui → client}/components/__tests__/jant-compose-editor.test.ts +64 -24
- package/src/{ui → client}/components/__tests__/jant-post-form.test.ts +24 -14
- package/src/{ui → client}/components/__tests__/jant-settings-general.test.ts +3 -3
- package/src/client/components/collection-sidebar-types.ts +45 -0
- package/src/{ui → client}/components/collection-types.ts +3 -4
- package/src/{ui → client}/components/compose-types.ts +3 -1
- package/src/{ui → client}/components/jant-collection-form.ts +301 -182
- package/src/client/components/jant-collection-sidebar.ts +801 -0
- package/src/{ui → client}/components/jant-compose-dialog.ts +231 -1
- package/src/client/components/jant-compose-editor.ts +1249 -0
- package/src/client/components/jant-compose-fullscreen.ts +338 -0
- package/src/client/components/jant-media-lightbox.ts +257 -0
- package/src/{ui → client}/components/jant-nav-manager.ts +143 -84
- package/src/{ui → client}/components/jant-post-form.ts +57 -8
- package/src/{ui → client}/components/jant-settings-general.ts +2 -2
- package/src/{ui → client}/components/nav-manager-types.ts +3 -0
- package/src/{ui → client}/components/post-form-template.ts +35 -31
- package/src/{ui → client}/components/post-form-types.ts +7 -3
- package/src/{lib → client}/compose-bridge.ts +9 -7
- package/src/client/lazy-slugify.ts +51 -0
- package/src/{lib → client}/media-upload.ts +16 -3
- package/src/{lib → client}/nav-manager-bridge.ts +1 -1
- package/src/client/page-slug-bridge.ts +42 -0
- package/src/{lib → client}/post-form-bridge.ts +2 -2
- package/src/{lib → client}/settings-bridge.ts +3 -3
- package/src/client/tiptap/bubble-menu.ts +205 -0
- package/src/client/tiptap/create-editor.ts +40 -0
- package/src/client/tiptap/exitable-marks.ts +73 -0
- package/src/client/tiptap/extensions.ts +60 -0
- package/src/client/tiptap/image-node.ts +488 -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 +140 -0
- package/src/client/tiptap/slash-commands.ts +328 -0
- package/src/{types → client/types}/sortablejs.d.ts +1 -1
- package/src/client.ts +24 -17
- package/src/db/migrations/0012_add_tiptap_columns.sql +2 -0
- package/src/db/migrations/0013_replace_featured_with_visibility.sql +8 -0
- package/src/db/schema.ts +6 -1
- package/src/i18n/locales/en.po +641 -215
- package/src/i18n/locales/en.ts +1 -1
- package/src/i18n/locales/zh-Hans.po +642 -204
- package/src/i18n/locales/zh-Hans.ts +1 -1
- package/src/i18n/locales/zh-Hant.po +642 -204
- package/src/i18n/locales/zh-Hant.ts +1 -1
- package/src/lib/__tests__/resolve-config.test.ts +2 -2
- package/src/lib/__tests__/schemas.test.ts +9 -6
- package/src/lib/__tests__/url.test.ts +2 -2
- package/src/lib/__tests__/view.test.ts +9 -9
- package/src/lib/emoji-catalog.ts +146 -0
- package/src/lib/feed.ts +1 -1
- package/src/lib/media-helpers.ts +10 -9
- package/src/lib/render.tsx +4 -3
- package/src/lib/resolve-config.ts +8 -1
- package/src/lib/schemas.ts +2 -3
- package/src/lib/summary.ts +92 -0
- package/src/lib/timeline.ts +2 -0
- package/src/lib/tiptap-render.ts +196 -0
- package/src/lib/upload.ts +97 -9
- package/src/lib/url.ts +7 -23
- package/src/lib/view.ts +33 -19
- package/src/middleware/error-handler.ts +3 -3
- package/src/preset.css +38 -0
- package/src/routes/api/collections.ts +20 -3
- package/src/routes/api/posts.ts +48 -33
- package/src/routes/api/upload.ts +7 -5
- package/src/routes/auth/reset.tsx +5 -4
- package/src/routes/auth/setup.tsx +26 -11
- package/src/routes/auth/signin.tsx +10 -7
- package/src/routes/compose.tsx +20 -11
- package/src/routes/dash/__tests__/settings-avatar.test.ts +43 -8
- package/src/routes/dash/index.tsx +7 -1
- package/src/routes/dash/media.tsx +3 -0
- package/src/routes/dash/pages.tsx +8 -2
- package/src/routes/dash/posts.tsx +6 -2
- package/src/routes/dash/redirects.tsx +15 -9
- package/src/routes/dash/settings.tsx +336 -32
- package/src/routes/feed/__tests__/rss.test.ts +7 -7
- package/src/routes/feed/rss.ts +8 -6
- package/src/routes/pages/__tests__/featured.test.ts +6 -7
- package/src/routes/pages/archive.tsx +11 -7
- package/src/routes/pages/collection.tsx +32 -15
- package/src/routes/pages/collections.tsx +11 -2
- package/src/routes/pages/featured.tsx +1 -1
- package/src/routes/pages/home.tsx +1 -1
- package/src/services/__tests__/post.test.ts +124 -33
- package/src/services/__tests__/settings.test.ts +3 -3
- package/src/services/page.ts +16 -3
- package/src/services/post.ts +96 -37
- package/src/services/search.ts +4 -2
- package/src/services/settings.ts +6 -2
- package/src/styles/components.css +240 -60
- package/src/styles/tokens.css +10 -0
- package/src/styles/ui.css +1157 -81
- package/src/types/bindings.ts +5 -0
- package/src/types/config.ts +23 -1
- package/src/types/constants.ts +3 -0
- package/src/types/entities.ts +9 -2
- package/src/types/operations.ts +9 -3
- package/src/types/props.ts +3 -3
- package/src/types/views.ts +3 -2
- package/src/ui/compose/ComposeDialog.tsx +24 -7
- package/src/ui/dash/PageForm.tsx +2 -0
- package/src/ui/dash/PostList.tsx +5 -5
- package/src/ui/dash/StatusBadge.tsx +13 -5
- package/src/ui/dash/appearance/AdvancedContent.tsx +52 -61
- package/src/ui/dash/appearance/ColorThemeContent.tsx +30 -35
- package/src/ui/dash/appearance/FontThemeContent.tsx +65 -73
- package/src/ui/dash/appearance/NavigationContent.tsx +107 -96
- package/src/ui/dash/media/MediaListContent.tsx +9 -4
- package/src/ui/dash/media/ViewMediaContent.tsx +2 -2
- package/src/ui/dash/pages/PagesContent.tsx +2 -1
- package/src/ui/dash/posts/PostForm.tsx +19 -7
- package/src/ui/dash/settings/AccountContent.tsx +133 -138
- package/src/ui/dash/settings/AvatarContent.tsx +70 -0
- package/src/ui/dash/settings/GeneralContent.tsx +3 -62
- package/src/ui/dash/settings/SettingsRootContent.tsx +236 -0
- package/src/ui/layouts/DashLayout.tsx +157 -75
- package/src/ui/layouts/SiteLayout.tsx +13 -13
- package/src/ui/pages/ArchivePage.tsx +10 -7
- package/src/ui/pages/CollectionPage.tsx +6 -35
- package/src/ui/pages/CollectionsPage.tsx +2 -1
- package/src/ui/pages/FeaturedPage.tsx +2 -1
- package/src/ui/pages/HomePage.tsx +1 -1
- package/src/ui/pages/SearchPage.tsx +1 -1
- package/src/ui/shared/CollectionsSidebar.tsx +228 -3
- package/src/ui/shared/MediaGallery.tsx +179 -41
- package/src/lib/collections-reorder.ts +0 -28
- package/src/routes/dash/appearance.tsx +0 -240
- package/src/routes/dash/collections.tsx +0 -211
- package/src/ui/components/jant-compose-editor.ts +0 -814
- 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/settings/SettingsNav.tsx +0 -52
- /package/src/{ui → client}/components/__tests__/jant-settings-avatar.test.ts +0 -0
- /package/src/{ui → client}/components/jant-settings-avatar.ts +0 -0
- /package/src/{ui → client}/components/settings-types.ts +0 -0
- /package/src/{lib → client}/image-processor.ts +0 -0
- /package/src/{lib → client}/toast.ts +0 -0
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import { LitElement, html, nothing } from "lit";
|
|
16
16
|
import type { PropertyValueMap } from "lit";
|
|
17
17
|
import Sortable from "sortablejs";
|
|
18
|
-
import { showToast } from "
|
|
18
|
+
import { showToast } from "../toast.js";
|
|
19
19
|
import type {
|
|
20
20
|
AvailablePage,
|
|
21
21
|
NavManagerItem,
|
|
@@ -104,7 +104,7 @@ export class JantNavManager extends LitElement {
|
|
|
104
104
|
this.systemNavItems = [];
|
|
105
105
|
this.availablePages = [];
|
|
106
106
|
this.siteName = "";
|
|
107
|
-
this.maxVisible =
|
|
107
|
+
this.maxVisible = 2;
|
|
108
108
|
this.homeDefaultView = "latest";
|
|
109
109
|
|
|
110
110
|
this._items = [];
|
|
@@ -253,7 +253,7 @@ export class JantNavManager extends LitElement {
|
|
|
253
253
|
const clamped = Math.max(0, Math.min(5, value));
|
|
254
254
|
this.maxVisible = clamped;
|
|
255
255
|
try {
|
|
256
|
-
const res = await fetch("/dash/
|
|
256
|
+
const res = await fetch("/dash/settings/navigation/nav-max-visible", {
|
|
257
257
|
method: "POST",
|
|
258
258
|
headers: { "Content-Type": "application/json" },
|
|
259
259
|
body: JSON.stringify({ value: clamped }),
|
|
@@ -268,7 +268,7 @@ export class JantNavManager extends LitElement {
|
|
|
268
268
|
async #handleHomeViewToggle(useFeatured: boolean) {
|
|
269
269
|
this.homeDefaultView = useFeatured ? "featured" : "latest";
|
|
270
270
|
try {
|
|
271
|
-
const res = await fetch("/dash/
|
|
271
|
+
const res = await fetch("/dash/settings/navigation/home-default-view", {
|
|
272
272
|
method: "POST",
|
|
273
273
|
headers: { "Content-Type": "application/json" },
|
|
274
274
|
body: JSON.stringify({ value: this.homeDefaultView }),
|
|
@@ -420,11 +420,14 @@ export class JantNavManager extends LitElement {
|
|
|
420
420
|
const hasMore = overflow.length > 0;
|
|
421
421
|
|
|
422
422
|
return html`
|
|
423
|
-
<div class="
|
|
424
|
-
<
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
423
|
+
<div class="nav-preview">
|
|
424
|
+
<div class="nav-preview-chrome">
|
|
425
|
+
<div class="nav-preview-dots">
|
|
426
|
+
<span></span><span></span><span></span>
|
|
427
|
+
</div>
|
|
428
|
+
<span class="nav-preview-label">${this.labels.preview}</span>
|
|
429
|
+
</div>
|
|
430
|
+
<div class="nav-preview-content">
|
|
428
431
|
<div class="site-header-top">
|
|
429
432
|
<a href="/" class="site-logo">${this.siteName}</a>
|
|
430
433
|
<div class="site-header-right">
|
|
@@ -544,7 +547,7 @@ export class JantNavManager extends LitElement {
|
|
|
544
547
|
|
|
545
548
|
if (item.type === "link") {
|
|
546
549
|
return html`
|
|
547
|
-
<div class="
|
|
550
|
+
<div class="nav-item-edit">
|
|
548
551
|
<div class="field">
|
|
549
552
|
<label class="label">${this.labels.label}</label>
|
|
550
553
|
<input
|
|
@@ -569,20 +572,20 @@ export class JantNavManager extends LitElement {
|
|
|
569
572
|
}}
|
|
570
573
|
/>
|
|
571
574
|
</div>
|
|
572
|
-
<div class="flex
|
|
575
|
+
<div class="flex items-center justify-between">
|
|
573
576
|
<button
|
|
574
577
|
type="button"
|
|
575
|
-
class="btn-sm"
|
|
576
|
-
@click=${() => this.#
|
|
578
|
+
class="btn-sm-ghost text-destructive"
|
|
579
|
+
@click=${() => this.#handleDelete(item)}
|
|
577
580
|
>
|
|
578
|
-
${this.labels.
|
|
581
|
+
${this.labels.delete}
|
|
579
582
|
</button>
|
|
580
583
|
<button
|
|
581
584
|
type="button"
|
|
582
|
-
class="btn-sm
|
|
583
|
-
@click=${() => this.#
|
|
585
|
+
class="btn-sm"
|
|
586
|
+
@click=${() => this.#handleUpdate(item)}
|
|
584
587
|
>
|
|
585
|
-
${this.labels.
|
|
588
|
+
${this.labels.save}
|
|
586
589
|
</button>
|
|
587
590
|
</div>
|
|
588
591
|
</div>
|
|
@@ -591,16 +594,8 @@ export class JantNavManager extends LitElement {
|
|
|
591
594
|
|
|
592
595
|
if (item.type === "page") {
|
|
593
596
|
return html`
|
|
594
|
-
<div class="
|
|
595
|
-
<
|
|
596
|
-
<div class="flex gap-2">
|
|
597
|
-
${item.pageId
|
|
598
|
-
? html`<a
|
|
599
|
-
href=${`/dash/pages/${item.pageId}/edit`}
|
|
600
|
-
class="btn-sm-outline"
|
|
601
|
-
>${this.labels.editPage}</a
|
|
602
|
-
>`
|
|
603
|
-
: nothing}
|
|
597
|
+
<div class="nav-item-edit">
|
|
598
|
+
<div class="flex items-center justify-between">
|
|
604
599
|
<button
|
|
605
600
|
type="button"
|
|
606
601
|
class="btn-sm-ghost text-destructive"
|
|
@@ -608,6 +603,13 @@ export class JantNavManager extends LitElement {
|
|
|
608
603
|
>
|
|
609
604
|
${this.labels.remove}
|
|
610
605
|
</button>
|
|
606
|
+
${item.pageId
|
|
607
|
+
? html`<a
|
|
608
|
+
href=${`/dash/pages/${item.pageId}/edit`}
|
|
609
|
+
class="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
|
610
|
+
>${this.labels.editPage} →</a
|
|
611
|
+
>`
|
|
612
|
+
: nothing}
|
|
611
613
|
</div>
|
|
612
614
|
</div>
|
|
613
615
|
`;
|
|
@@ -615,8 +617,7 @@ export class JantNavManager extends LitElement {
|
|
|
615
617
|
|
|
616
618
|
if (item.type === "system") {
|
|
617
619
|
return html`
|
|
618
|
-
<div class="
|
|
619
|
-
<code class="text-sm text-muted-foreground">${item.url}</code>
|
|
620
|
+
<div class="nav-item-edit">
|
|
620
621
|
<div class="field">
|
|
621
622
|
<label class="label">${this.labels.label}</label>
|
|
622
623
|
<input
|
|
@@ -629,20 +630,20 @@ export class JantNavManager extends LitElement {
|
|
|
629
630
|
}}
|
|
630
631
|
/>
|
|
631
632
|
</div>
|
|
632
|
-
<div class="flex
|
|
633
|
+
<div class="flex items-center justify-between">
|
|
633
634
|
<button
|
|
634
635
|
type="button"
|
|
635
|
-
class="btn-sm"
|
|
636
|
-
@click=${() => this.#
|
|
636
|
+
class="btn-sm-ghost text-destructive"
|
|
637
|
+
@click=${() => this.#handleDelete(item)}
|
|
637
638
|
>
|
|
638
|
-
${this.labels.
|
|
639
|
+
${this.labels.remove}
|
|
639
640
|
</button>
|
|
640
641
|
<button
|
|
641
642
|
type="button"
|
|
642
|
-
class="btn-sm
|
|
643
|
-
@click=${() => this.#
|
|
643
|
+
class="btn-sm"
|
|
644
|
+
@click=${() => this.#handleUpdate(item)}
|
|
644
645
|
>
|
|
645
|
-
${this.labels.
|
|
646
|
+
${this.labels.save}
|
|
646
647
|
</button>
|
|
647
648
|
</div>
|
|
648
649
|
</div>
|
|
@@ -653,17 +654,19 @@ export class JantNavManager extends LitElement {
|
|
|
653
654
|
}
|
|
654
655
|
|
|
655
656
|
#renderItem(item: NavManagerItem) {
|
|
657
|
+
const isEditing = this._editingId === item.id;
|
|
658
|
+
|
|
656
659
|
return html`
|
|
657
|
-
<div
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
>
|
|
660
|
+
<div
|
|
661
|
+
data-nav-id=${item.id}
|
|
662
|
+
class="nav-item${isEditing ? " nav-item-editing" : ""}"
|
|
663
|
+
>
|
|
664
|
+
<div class="nav-item-row">
|
|
665
|
+
<div class="nav-item-handle" data-drag-handle>
|
|
663
666
|
<svg
|
|
664
667
|
xmlns="http://www.w3.org/2000/svg"
|
|
665
|
-
width="
|
|
666
|
-
height="
|
|
668
|
+
width="14"
|
|
669
|
+
height="14"
|
|
667
670
|
viewBox="0 0 24 24"
|
|
668
671
|
fill="none"
|
|
669
672
|
stroke="currentColor"
|
|
@@ -679,31 +682,39 @@ export class JantNavManager extends LitElement {
|
|
|
679
682
|
<circle cx="15" cy="5" r="1" />
|
|
680
683
|
<circle cx="15" cy="19" r="1" />
|
|
681
684
|
</svg>
|
|
682
|
-
<span class="font-medium truncate">${item.label}</span>
|
|
683
685
|
</div>
|
|
684
|
-
<div class="
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
type
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
686
|
+
<div class="nav-item-info" @click=${() => this.#toggleEdit(item)}>
|
|
687
|
+
<div class="flex items-center gap-2 min-w-0">
|
|
688
|
+
<span class="text-sm font-medium truncate">${item.label}</span>
|
|
689
|
+
${this.#renderTypeBadge(item.type)}
|
|
690
|
+
</div>
|
|
691
|
+
<span class="text-xs text-muted-foreground truncate"
|
|
692
|
+
>${item.url}</span
|
|
691
693
|
>
|
|
692
|
-
<svg
|
|
693
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
694
|
-
width="16"
|
|
695
|
-
height="16"
|
|
696
|
-
viewBox="0 0 24 24"
|
|
697
|
-
fill="none"
|
|
698
|
-
stroke="currentColor"
|
|
699
|
-
stroke-width="2"
|
|
700
|
-
stroke-linecap="round"
|
|
701
|
-
stroke-linejoin="round"
|
|
702
|
-
>
|
|
703
|
-
<path d="m6 9 6 6 6-6" />
|
|
704
|
-
</svg>
|
|
705
|
-
</button>
|
|
706
694
|
</div>
|
|
695
|
+
<button
|
|
696
|
+
type="button"
|
|
697
|
+
class="nav-item-toggle"
|
|
698
|
+
@click=${() => this.#toggleEdit(item)}
|
|
699
|
+
aria-label=${this.labels.toggleEdit}
|
|
700
|
+
>
|
|
701
|
+
<svg
|
|
702
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
703
|
+
width="14"
|
|
704
|
+
height="14"
|
|
705
|
+
viewBox="0 0 24 24"
|
|
706
|
+
fill="none"
|
|
707
|
+
stroke="currentColor"
|
|
708
|
+
stroke-width="2"
|
|
709
|
+
stroke-linecap="round"
|
|
710
|
+
stroke-linejoin="round"
|
|
711
|
+
style="transition: transform 0.15s; ${isEditing
|
|
712
|
+
? "transform: rotate(180deg);"
|
|
713
|
+
: ""}"
|
|
714
|
+
>
|
|
715
|
+
<path d="m6 9 6 6 6-6" />
|
|
716
|
+
</svg>
|
|
717
|
+
</button>
|
|
707
718
|
</div>
|
|
708
719
|
${this.#renderEditPanel(item)}
|
|
709
720
|
</div>
|
|
@@ -842,14 +853,52 @@ export class JantNavManager extends LitElement {
|
|
|
842
853
|
</div>
|
|
843
854
|
`,
|
|
844
855
|
)}
|
|
856
|
+
<hr role="separator" />
|
|
857
|
+
<a href="/dash/pages/new" role="option">
|
|
858
|
+
<svg
|
|
859
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
860
|
+
width="24"
|
|
861
|
+
height="24"
|
|
862
|
+
viewBox="0 0 24 24"
|
|
863
|
+
fill="none"
|
|
864
|
+
stroke="currentColor"
|
|
865
|
+
stroke-width="2"
|
|
866
|
+
stroke-linecap="round"
|
|
867
|
+
stroke-linejoin="round"
|
|
868
|
+
>
|
|
869
|
+
<circle cx="12" cy="12" r="10" />
|
|
870
|
+
<path d="M8 12h8" />
|
|
871
|
+
<path d="M12 8v8" />
|
|
872
|
+
</svg>
|
|
873
|
+
${this.labels.createPage}
|
|
874
|
+
</a>
|
|
845
875
|
</div>`
|
|
846
876
|
: html`<div
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
877
|
+
class="py-6 text-center text-sm text-muted-foreground"
|
|
878
|
+
>
|
|
879
|
+
${this._availablePages.length === 0
|
|
880
|
+
? this.labels.allPagesInNav
|
|
881
|
+
: this.labels.noPagesFound}
|
|
882
|
+
</div>
|
|
883
|
+
<hr role="separator" />
|
|
884
|
+
<a href="/dash/pages/new" role="option">
|
|
885
|
+
<svg
|
|
886
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
887
|
+
width="24"
|
|
888
|
+
height="24"
|
|
889
|
+
viewBox="0 0 24 24"
|
|
890
|
+
fill="none"
|
|
891
|
+
stroke="currentColor"
|
|
892
|
+
stroke-width="2"
|
|
893
|
+
stroke-linecap="round"
|
|
894
|
+
stroke-linejoin="round"
|
|
895
|
+
>
|
|
896
|
+
<circle cx="12" cy="12" r="10" />
|
|
897
|
+
<path d="M8 12h8" />
|
|
898
|
+
<path d="M12 8v8" />
|
|
899
|
+
</svg>
|
|
900
|
+
${this.labels.createPage}
|
|
901
|
+
</a>`}
|
|
853
902
|
</div>
|
|
854
903
|
</div>
|
|
855
904
|
`
|
|
@@ -1007,15 +1056,20 @@ export class JantNavManager extends LitElement {
|
|
|
1007
1056
|
return html`
|
|
1008
1057
|
${this.#renderPreview()}
|
|
1009
1058
|
|
|
1010
|
-
<div class="flex flex-col gap-
|
|
1011
|
-
<div class="flex items-
|
|
1012
|
-
<
|
|
1013
|
-
|
|
1014
|
-
|
|
1059
|
+
<div class="flex flex-col gap-4 mt-3">
|
|
1060
|
+
<div class="flex items-start justify-between gap-4">
|
|
1061
|
+
<div class="flex flex-col gap-0.5">
|
|
1062
|
+
<label class="text-sm font-medium" for="nav-max-visible">
|
|
1063
|
+
${this.labels.maxVisibleLinks}
|
|
1064
|
+
</label>
|
|
1065
|
+
<p class="text-xs text-muted-foreground">
|
|
1066
|
+
${this.labels.maxVisibleLinksDescription}
|
|
1067
|
+
</p>
|
|
1068
|
+
</div>
|
|
1015
1069
|
<input
|
|
1016
1070
|
type="number"
|
|
1017
1071
|
id="nav-max-visible"
|
|
1018
|
-
class="input w-16 h-8"
|
|
1072
|
+
class="input w-16 h-8 shrink-0"
|
|
1019
1073
|
min="0"
|
|
1020
1074
|
max="5"
|
|
1021
1075
|
.value=${String(this.maxVisible)}
|
|
@@ -1025,15 +1079,20 @@ export class JantNavManager extends LitElement {
|
|
|
1025
1079
|
}}
|
|
1026
1080
|
/>
|
|
1027
1081
|
</div>
|
|
1028
|
-
<div class="flex items-
|
|
1029
|
-
<
|
|
1030
|
-
|
|
1031
|
-
|
|
1082
|
+
<div class="flex items-start justify-between gap-4">
|
|
1083
|
+
<div class="flex flex-col gap-0.5">
|
|
1084
|
+
<label class="text-sm font-medium" for="nav-home-view">
|
|
1085
|
+
${this.labels.useFeaturedAsDefault}
|
|
1086
|
+
</label>
|
|
1087
|
+
<p class="text-xs text-muted-foreground">
|
|
1088
|
+
${this.labels.useFeaturedAsDefaultDescription}
|
|
1089
|
+
</p>
|
|
1090
|
+
</div>
|
|
1032
1091
|
<input
|
|
1033
1092
|
type="checkbox"
|
|
1034
1093
|
role="switch"
|
|
1035
1094
|
id="nav-home-view"
|
|
1036
|
-
class="input"
|
|
1095
|
+
class="input shrink-0"
|
|
1037
1096
|
.checked=${this.homeDefaultView === "featured"}
|
|
1038
1097
|
@change=${(e: Event) => {
|
|
1039
1098
|
this.#handleHomeViewToggle(
|
|
@@ -1053,7 +1112,7 @@ export class JantNavManager extends LitElement {
|
|
|
1053
1112
|
${this.labels.emptyState}
|
|
1054
1113
|
</p>`
|
|
1055
1114
|
: html`
|
|
1056
|
-
<div id="nav-items-list" class="
|
|
1115
|
+
<div id="nav-items-list" class="nav-items-list">
|
|
1057
1116
|
${this._items.map((item) => this.#renderItem(item))}
|
|
1058
1117
|
</div>
|
|
1059
1118
|
`}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { LitElement } from "lit";
|
|
9
|
+
import type { Editor, JSONContent } from "@tiptap/core";
|
|
9
10
|
import type {
|
|
10
11
|
PostFormInitial,
|
|
11
12
|
PostFormLabels,
|
|
@@ -14,8 +15,10 @@ import type {
|
|
|
14
15
|
PostSubmitDetail,
|
|
15
16
|
PostFormat,
|
|
16
17
|
PostStatus,
|
|
18
|
+
PostVisibility,
|
|
17
19
|
} from "./post-form-types.js";
|
|
18
20
|
import { renderPostForm } from "./post-form-template.js";
|
|
21
|
+
import { createTiptapEditor } from "../tiptap/create-editor.js";
|
|
19
22
|
|
|
20
23
|
const DEFAULT_INITIAL: PostFormInitial = {
|
|
21
24
|
format: "note",
|
|
@@ -24,7 +27,7 @@ const DEFAULT_INITIAL: PostFormInitial = {
|
|
|
24
27
|
url: "",
|
|
25
28
|
quoteText: "",
|
|
26
29
|
status: "published",
|
|
27
|
-
|
|
30
|
+
visibility: "listed",
|
|
28
31
|
pinned: false,
|
|
29
32
|
rating: 0,
|
|
30
33
|
collectionIds: [],
|
|
@@ -51,7 +54,10 @@ const EMPTY_LABELS: PostFormLabels = {
|
|
|
51
54
|
statusLabel: "",
|
|
52
55
|
statusPublished: "",
|
|
53
56
|
statusDraft: "",
|
|
54
|
-
|
|
57
|
+
visibilityLabel: "",
|
|
58
|
+
visibilityListed: "",
|
|
59
|
+
visibilityFeatured: "",
|
|
60
|
+
visibilityUnlisted: "",
|
|
55
61
|
pinnedLabel: "",
|
|
56
62
|
collectionsLabel: "",
|
|
57
63
|
submitLabel: "",
|
|
@@ -93,7 +99,7 @@ export class JantPostForm extends LitElement {
|
|
|
93
99
|
_url: { state: true },
|
|
94
100
|
_quoteText: { state: true },
|
|
95
101
|
_status: { state: true },
|
|
96
|
-
|
|
102
|
+
_visibility: { state: true },
|
|
97
103
|
_pinned: { state: true },
|
|
98
104
|
_rating: { state: true },
|
|
99
105
|
_collectionIds: { state: true },
|
|
@@ -115,13 +121,15 @@ export class JantPostForm extends LitElement {
|
|
|
115
121
|
declare _url: string;
|
|
116
122
|
declare _quoteText: string;
|
|
117
123
|
declare _status: PostStatus;
|
|
118
|
-
declare
|
|
124
|
+
declare _visibility: PostVisibility;
|
|
119
125
|
declare _pinned: boolean;
|
|
120
126
|
declare _rating: number;
|
|
121
127
|
declare _collectionIds: number[];
|
|
122
128
|
declare _mediaIds: string[];
|
|
123
129
|
declare _loading: boolean;
|
|
124
130
|
|
|
131
|
+
_editor: Editor | null = null;
|
|
132
|
+
_bodyJson: JSONContent | null = null;
|
|
125
133
|
#initialized = false;
|
|
126
134
|
|
|
127
135
|
createRenderRoot() {
|
|
@@ -145,7 +153,7 @@ export class JantPostForm extends LitElement {
|
|
|
145
153
|
this._url = "";
|
|
146
154
|
this._quoteText = "";
|
|
147
155
|
this._status = "published";
|
|
148
|
-
this.
|
|
156
|
+
this._visibility = "listed";
|
|
149
157
|
this._pinned = false;
|
|
150
158
|
this._rating = 0;
|
|
151
159
|
this._collectionIds = [];
|
|
@@ -197,6 +205,8 @@ export class JantPostForm extends LitElement {
|
|
|
197
205
|
|
|
198
206
|
disconnectedCallback() {
|
|
199
207
|
super.disconnectedCallback();
|
|
208
|
+
this._editor?.destroy();
|
|
209
|
+
this._editor = null;
|
|
200
210
|
this.closeMediaPicker();
|
|
201
211
|
}
|
|
202
212
|
|
|
@@ -208,12 +218,46 @@ export class JantPostForm extends LitElement {
|
|
|
208
218
|
this._url = init.url ?? "";
|
|
209
219
|
this._quoteText = init.quoteText ?? "";
|
|
210
220
|
this._status = init.status ?? "published";
|
|
211
|
-
this.
|
|
221
|
+
this._visibility = init.visibility ?? "listed";
|
|
212
222
|
this._pinned = !!init.pinned;
|
|
213
223
|
this._rating = init.rating ?? 0;
|
|
214
224
|
this._collectionIds = [...(init.collectionIds ?? [])];
|
|
215
225
|
this._mediaIds = [...(init.mediaIds ?? [])];
|
|
216
226
|
this.#initialized = true;
|
|
227
|
+
|
|
228
|
+
// Parse body as Tiptap JSON if it looks like JSON
|
|
229
|
+
if (this._body && this._body.startsWith("{")) {
|
|
230
|
+
try {
|
|
231
|
+
this._bodyJson = JSON.parse(this._body) as JSONContent;
|
|
232
|
+
} catch {
|
|
233
|
+
this._bodyJson = null;
|
|
234
|
+
}
|
|
235
|
+
} else {
|
|
236
|
+
this._bodyJson = null;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
initEditor() {
|
|
241
|
+
if (this._editor) return;
|
|
242
|
+
const container = this.querySelector<HTMLElement>(".post-form-tiptap-body");
|
|
243
|
+
if (!container) return;
|
|
244
|
+
|
|
245
|
+
this._editor = createTiptapEditor({
|
|
246
|
+
element: container,
|
|
247
|
+
placeholder: this.labels.bodyPlaceholder ?? "Write something…",
|
|
248
|
+
content: this._bodyJson,
|
|
249
|
+
onUpdate: (json) => {
|
|
250
|
+
this._bodyJson = json;
|
|
251
|
+
this._body = JSON.stringify(json);
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
protected updated(changed: Map<string, unknown>) {
|
|
257
|
+
super.updated(changed);
|
|
258
|
+
if (!this._editor) {
|
|
259
|
+
this.initEditor();
|
|
260
|
+
}
|
|
217
261
|
}
|
|
218
262
|
|
|
219
263
|
handleInput(field: "_title" | "_body" | "_url" | "_quoteText", e: Event) {
|
|
@@ -253,15 +297,20 @@ export class JantPostForm extends LitElement {
|
|
|
253
297
|
handleSubmit(e: Event) {
|
|
254
298
|
e.preventDefault();
|
|
255
299
|
if (this._loading || !this.action) return;
|
|
300
|
+
// Use Tiptap JSON for body
|
|
301
|
+
const bodyValue = this._bodyJson
|
|
302
|
+
? JSON.stringify(this._bodyJson)
|
|
303
|
+
: this._body;
|
|
304
|
+
|
|
256
305
|
const detail: PostSubmitDetail = {
|
|
257
306
|
endpoint: this.action,
|
|
258
307
|
isEdit: this.isEdit,
|
|
259
308
|
data: {
|
|
260
309
|
format: this._format,
|
|
261
310
|
title: this._title.trim(),
|
|
262
|
-
body:
|
|
311
|
+
body: bodyValue,
|
|
263
312
|
status: this._status,
|
|
264
|
-
|
|
313
|
+
visibility: this._visibility,
|
|
265
314
|
pinned: this._pinned,
|
|
266
315
|
url: this._url.trim(),
|
|
267
316
|
quoteText: this._quoteText.trim(),
|
|
@@ -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: "/dash/settings",
|
|
173
|
+
endpoint: "/dash/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: "/dash/settings/seo",
|
|
206
|
+
endpoint: "/dash/settings/general/seo",
|
|
207
207
|
data: { noindex: this._noindex ? "" : "true" },
|
|
208
208
|
section: "seo",
|
|
209
209
|
},
|
|
@@ -51,11 +51,14 @@ export interface NavManagerLabels {
|
|
|
51
51
|
addLink: string;
|
|
52
52
|
addLinkDescription: string;
|
|
53
53
|
allPagesInNav: string;
|
|
54
|
+
createPage: string;
|
|
54
55
|
urlPlaceholder: string;
|
|
55
56
|
labelAndUrlRequired: string;
|
|
56
57
|
maxVisibleLinks: string;
|
|
58
|
+
maxVisibleLinksDescription: string;
|
|
57
59
|
maxVisibleSaved: string;
|
|
58
60
|
useFeaturedAsDefault: string;
|
|
61
|
+
useFeaturedAsDefaultDescription: string;
|
|
59
62
|
homeViewSaved: string;
|
|
60
63
|
latest: string;
|
|
61
64
|
featured: string;
|
|
@@ -113,12 +113,9 @@ export function renderPostForm(component: JantPostForm) {
|
|
|
113
113
|
|
|
114
114
|
<div class="field">
|
|
115
115
|
<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>
|
|
116
|
+
<div
|
|
117
|
+
class="post-form-tiptap-body compose-tiptap-body border rounded-lg p-3 min-h-32"
|
|
118
|
+
></div>
|
|
122
119
|
</div>
|
|
123
120
|
|
|
124
121
|
<div class="field">
|
|
@@ -173,33 +170,40 @@ export function renderPostForm(component: JantPostForm) {
|
|
|
173
170
|
</select>
|
|
174
171
|
</div>
|
|
175
172
|
|
|
176
|
-
<div class="
|
|
177
|
-
<label class="
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
component.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const target = e.target as HTMLInputElement;
|
|
196
|
-
component._pinned = target.checked;
|
|
197
|
-
}}
|
|
198
|
-
/>
|
|
199
|
-
${component.labels.pinnedLabel}
|
|
200
|
-
</label>
|
|
173
|
+
<div class="field">
|
|
174
|
+
<label class="label">${component.labels.visibilityLabel}</label>
|
|
175
|
+
<select
|
|
176
|
+
class="select"
|
|
177
|
+
.value=${component._visibility}
|
|
178
|
+
@change=${(e: Event) => {
|
|
179
|
+
const target = e.target as HTMLSelectElement;
|
|
180
|
+
component._visibility =
|
|
181
|
+
(target.value as typeof component._visibility) ?? "listed";
|
|
182
|
+
}}
|
|
183
|
+
>
|
|
184
|
+
<option value="listed">${component.labels.visibilityListed}</option>
|
|
185
|
+
<option value="featured">
|
|
186
|
+
${component.labels.visibilityFeatured}
|
|
187
|
+
</option>
|
|
188
|
+
<option value="unlisted">
|
|
189
|
+
${component.labels.visibilityUnlisted}
|
|
190
|
+
</option>
|
|
191
|
+
</select>
|
|
201
192
|
</div>
|
|
202
193
|
|
|
194
|
+
<label class="flex items-center gap-2 text-sm">
|
|
195
|
+
<input
|
|
196
|
+
type="checkbox"
|
|
197
|
+
class="checkbox"
|
|
198
|
+
.checked=${component._pinned}
|
|
199
|
+
@change=${(e: Event) => {
|
|
200
|
+
const target = e.target as HTMLInputElement;
|
|
201
|
+
component._pinned = target.checked;
|
|
202
|
+
}}
|
|
203
|
+
/>
|
|
204
|
+
${component.labels.pinnedLabel}
|
|
205
|
+
</label>
|
|
206
|
+
|
|
203
207
|
${renderCollections(component)}
|
|
204
208
|
|
|
205
209
|
<div class="flex gap-2">
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
export type PostFormat = "note" | "link" | "quote";
|
|
6
6
|
export type PostStatus = "published" | "draft";
|
|
7
|
+
export type PostVisibility = "listed" | "featured" | "unlisted";
|
|
7
8
|
|
|
8
9
|
export interface PostFormLabels {
|
|
9
10
|
formatLabel: string;
|
|
@@ -25,7 +26,10 @@ export interface PostFormLabels {
|
|
|
25
26
|
statusLabel: string;
|
|
26
27
|
statusPublished: string;
|
|
27
28
|
statusDraft: string;
|
|
28
|
-
|
|
29
|
+
visibilityLabel: string;
|
|
30
|
+
visibilityListed: string;
|
|
31
|
+
visibilityFeatured: string;
|
|
32
|
+
visibilityUnlisted: string;
|
|
29
33
|
pinnedLabel: string;
|
|
30
34
|
collectionsLabel: string;
|
|
31
35
|
submitLabel: string;
|
|
@@ -44,7 +48,7 @@ export interface PostFormInitial {
|
|
|
44
48
|
url: string;
|
|
45
49
|
quoteText: string;
|
|
46
50
|
status: PostStatus;
|
|
47
|
-
|
|
51
|
+
visibility: PostVisibility;
|
|
48
52
|
pinned: boolean;
|
|
49
53
|
rating: number;
|
|
50
54
|
collectionIds: number[];
|
|
@@ -72,7 +76,7 @@ export interface PostSubmitDetail {
|
|
|
72
76
|
title?: string;
|
|
73
77
|
body?: string;
|
|
74
78
|
status: PostStatus;
|
|
75
|
-
|
|
79
|
+
visibility: PostVisibility;
|
|
76
80
|
pinned: boolean;
|
|
77
81
|
url?: string;
|
|
78
82
|
quoteText?: string;
|