@jant/core 0.3.26 → 0.3.28
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/client.css +1 -0
- package/dist/client/client.js +31561 -0
- package/dist/index.js +15209 -15
- package/package.json +21 -15
- package/src/__tests__/helpers/app.ts +19 -3
- package/src/__tests__/helpers/db.ts +44 -0
- package/src/__tests__/helpers/lingui-core-macro-mock.ts +33 -0
- package/src/app.tsx +112 -173
- package/src/auth.ts +4 -1
- package/src/client.ts +13 -0
- package/src/db/migrations/0007_post_collections_m2m.sql +94 -0
- package/src/db/migrations/0008_add_collection_dividers.sql +8 -0
- package/src/db/migrations/0009_drop_collection_show_divider.sql +2 -0
- package/src/db/migrations/0010_add_performance_indexes.sql +16 -0
- package/src/db/schema.ts +24 -4
- package/src/i18n/locales/en.po +810 -385
- package/src/i18n/locales/en.ts +1 -1
- package/src/i18n/locales/zh-Hans.po +733 -522
- package/src/i18n/locales/zh-Hans.ts +1 -1
- package/src/i18n/locales/zh-Hant.po +733 -522
- package/src/i18n/locales/zh-Hant.ts +1 -1
- package/src/i18n/middleware.ts +7 -11
- package/src/index.ts +1 -1
- package/src/lib/__tests__/icons.test.ts +178 -0
- package/src/lib/__tests__/resolve-config.test.ts +184 -0
- package/src/lib/__tests__/schemas.test.ts +12 -6
- package/src/lib/__tests__/theme.test.ts +62 -0
- package/src/lib/__tests__/timezones.test.ts +1 -1
- package/src/lib/__tests__/url.test.ts +12 -0
- package/src/lib/__tests__/view.test.ts +1 -5
- package/src/lib/avatar-upload.ts +18 -10
- package/src/lib/collection-form-bridge.ts +52 -0
- package/src/lib/collections-reorder.ts +28 -0
- package/src/lib/compose-bridge.ts +251 -0
- package/src/lib/errors.ts +116 -0
- package/src/lib/excerpt.ts +1 -1
- package/src/lib/favicon.ts +3 -5
- package/src/lib/html.ts +22 -0
- package/src/lib/icon-catalog.ts +181 -0
- package/src/lib/icons.ts +202 -0
- package/src/lib/navigation.ts +18 -33
- package/src/lib/pagination.ts +3 -2
- package/src/lib/post-form-bridge.ts +136 -0
- package/src/lib/render.tsx +11 -4
- package/src/lib/resolve-config.ts +157 -0
- package/src/lib/schemas.ts +76 -12
- package/src/lib/settings-bridge.ts +139 -0
- package/src/lib/storage.ts +37 -16
- package/src/lib/theme.ts +5 -7
- package/src/lib/timeline.ts +4 -8
- package/src/lib/toast.ts +134 -0
- package/src/lib/upload.ts +71 -0
- package/src/lib/url.ts +9 -1
- package/src/lib/version.ts +16 -0
- package/src/lib/view.ts +9 -10
- package/src/middleware/__tests__/auth.test.ts +6 -28
- package/src/middleware/__tests__/onboarding.test.ts +1 -1
- package/src/middleware/auth.ts +6 -12
- package/src/middleware/config.ts +51 -0
- package/src/middleware/error-handler.ts +56 -0
- package/src/middleware/onboarding.ts +1 -1
- package/src/preset.css +6 -0
- package/src/routes/__tests__/compose.test.ts +104 -17
- package/src/routes/api/__tests__/collections.test.ts +93 -2
- package/src/routes/api/__tests__/posts.test.ts +2 -1
- package/src/routes/api/__tests__/settings.test.ts +1 -1
- package/src/routes/api/collections.ts +64 -68
- package/src/routes/api/nav-items.ts +21 -59
- package/src/routes/api/pages.ts +18 -46
- package/src/routes/api/posts.ts +64 -86
- package/src/routes/api/search.ts +6 -4
- package/src/routes/api/settings.ts +8 -24
- package/src/routes/api/upload.ts +55 -53
- package/src/routes/auth/__tests__/setup.test.ts +118 -0
- package/src/routes/auth/reset.tsx +17 -66
- package/src/routes/auth/setup.tsx +67 -11
- package/src/routes/auth/signin.tsx +44 -8
- package/src/routes/compose.tsx +194 -0
- package/src/routes/dash/__tests__/font-theme.test.ts +110 -0
- package/src/routes/dash/__tests__/pages.test.ts +2 -2
- package/src/routes/dash/__tests__/settings-avatar.test.ts +23 -12
- package/src/routes/dash/appearance.tsx +173 -0
- package/src/routes/dash/collections.tsx +80 -14
- package/src/routes/dash/index.tsx +12 -14
- package/src/routes/dash/media.tsx +46 -49
- package/src/routes/dash/pages.tsx +85 -37
- package/src/routes/dash/posts.tsx +60 -23
- package/src/routes/dash/redirects.tsx +43 -33
- package/src/routes/dash/settings.tsx +234 -214
- package/src/routes/feed/__tests__/rss.test.ts +7 -3
- package/src/routes/feed/rss.ts +11 -16
- package/src/routes/feed/sitemap.ts +15 -9
- package/src/routes/pages/__tests__/collections.test.ts +9 -8
- package/src/routes/pages/archive.tsx +2 -2
- package/src/routes/pages/collection.tsx +76 -9
- package/src/routes/pages/collections.tsx +3 -1
- package/src/routes/pages/featured.tsx +2 -2
- package/src/routes/pages/home.tsx +3 -3
- package/src/routes/pages/latest.tsx +2 -2
- package/src/routes/pages/page.tsx +2 -2
- package/src/routes/pages/post.tsx +2 -2
- package/src/routes/pages/search.tsx +2 -2
- package/src/services/__tests__/collection.test.ts +324 -34
- package/src/services/__tests__/media.test.ts +1 -1
- package/src/services/__tests__/page.test.ts +116 -1
- package/src/services/auth.ts +88 -0
- package/src/services/collection.ts +169 -30
- package/src/services/index.ts +8 -3
- package/src/services/media.ts +39 -12
- package/src/services/navigation.ts +17 -5
- package/src/services/page.ts +24 -4
- package/src/services/post.ts +87 -19
- package/src/services/search.ts +0 -1
- package/src/services/settings.ts +21 -13
- package/src/style.css +3 -0
- package/src/styles/components.css +42 -1
- package/src/styles/tokens.css +4 -0
- package/src/styles/ui.css +902 -73
- package/src/types/app-context.ts +25 -0
- package/src/types/bindings.ts +1 -0
- package/src/types/config.ts +60 -23
- package/src/types/entities.ts +12 -2
- package/src/types/lingui-react-macro.d.ts +3 -3
- package/src/types/operations.ts +2 -4
- package/src/types/views.ts +1 -3
- package/src/ui/__tests__/font-themes.test.ts +27 -8
- package/src/ui/color-themes.ts +1 -1
- package/src/ui/components/__tests__/jant-collection-form.test.ts +153 -0
- package/src/ui/components/__tests__/jant-compose-dialog.test.ts +512 -0
- package/src/ui/components/__tests__/jant-compose-editor.test.ts +272 -0
- package/src/ui/components/__tests__/jant-post-form.test.ts +172 -0
- package/src/ui/components/__tests__/jant-settings-avatar.test.ts +235 -0
- package/src/ui/components/__tests__/jant-settings-general.test.ts +319 -0
- package/src/ui/components/collection-types.ts +45 -0
- package/src/ui/components/compose-types.ts +75 -0
- package/src/ui/components/jant-collection-form.ts +512 -0
- package/src/ui/components/jant-compose-dialog.ts +494 -0
- package/src/ui/components/jant-compose-editor.ts +799 -0
- package/src/ui/components/jant-post-form.ts +290 -0
- package/src/ui/components/jant-settings-avatar.ts +231 -0
- package/src/ui/components/jant-settings-general.ts +436 -0
- package/src/ui/components/post-form-template.ts +260 -0
- package/src/ui/components/post-form-types.ts +87 -0
- package/src/ui/components/settings-types.ts +62 -0
- package/src/ui/compose/ComposeDialog.tsx +141 -385
- package/src/ui/compose/ComposePrompt.tsx +3 -3
- package/src/ui/dash/PostList.tsx +55 -61
- package/src/ui/dash/appearance/AdvancedContent.tsx +80 -0
- package/src/ui/dash/appearance/AppearanceNav.tsx +56 -0
- package/src/ui/dash/appearance/ColorThemeContent.tsx +129 -0
- package/src/ui/dash/appearance/FontThemeContent.tsx +98 -0
- package/src/ui/dash/collections/CollectionForm.tsx +130 -117
- package/src/ui/dash/collections/CollectionsListContent.tsx +102 -41
- package/src/ui/dash/collections/IconPickerGrid.tsx +50 -0
- package/src/ui/dash/collections/ViewCollectionContent.tsx +14 -3
- package/src/ui/dash/index.ts +1 -1
- package/src/ui/dash/posts/PostForm.tsx +248 -0
- package/src/ui/dash/settings/AccountContent.tsx +69 -80
- package/src/ui/dash/settings/GeneralContent.tsx +159 -478
- package/src/ui/dash/settings/SettingsNav.tsx +4 -4
- package/src/ui/font-themes.ts +115 -32
- package/src/ui/layouts/BaseLayout.tsx +49 -19
- package/src/ui/layouts/DashLayout.tsx +14 -9
- package/src/ui/layouts/SiteLayout.tsx +38 -23
- package/src/ui/pages/CollectionPage.tsx +12 -2
- package/src/ui/pages/CollectionsPage.tsx +27 -27
- package/src/ui/pages/HomePage.tsx +15 -6
- package/src/ui/pages/SearchPage.tsx +1 -2
- package/src/ui/shared/CollectionsSidebar.tsx +59 -0
- package/src/ui/shared/Pagination.tsx +2 -2
- package/dist/app.js +0 -265
- package/dist/auth.js +0 -36
- package/dist/client.js +0 -13
- package/dist/db/index.js +0 -10
- package/dist/db/schema.js +0 -224
- package/dist/i18n/Trans.js +0 -24
- package/dist/i18n/context.js +0 -58
- package/dist/i18n/detect.js +0 -26
- package/dist/i18n/i18n.js +0 -49
- package/dist/i18n/index.js +0 -44
- package/dist/i18n/locales/en.js +0 -1
- package/dist/i18n/locales/zh-Hans.js +0 -1
- package/dist/i18n/locales/zh-Hant.js +0 -1
- package/dist/i18n/locales.js +0 -13
- package/dist/i18n/middleware.js +0 -30
- package/dist/lib/avatar-upload.js +0 -134
- package/dist/lib/config.js +0 -143
- package/dist/lib/constants.js +0 -50
- package/dist/lib/excerpt.js +0 -76
- package/dist/lib/favicon.js +0 -102
- package/dist/lib/feed.js +0 -123
- package/dist/lib/image-processor.js +0 -187
- package/dist/lib/image.js +0 -97
- package/dist/lib/index.js +0 -7
- package/dist/lib/markdown.js +0 -83
- package/dist/lib/media-helpers.js +0 -49
- package/dist/lib/media-upload.js +0 -104
- package/dist/lib/nav-reorder.js +0 -27
- package/dist/lib/navigation.js +0 -79
- package/dist/lib/pagination.js +0 -44
- package/dist/lib/render.js +0 -53
- package/dist/lib/schemas.js +0 -174
- package/dist/lib/sqid.js +0 -72
- package/dist/lib/sse.js +0 -218
- package/dist/lib/storage.js +0 -164
- package/dist/lib/theme.js +0 -65
- package/dist/lib/time.js +0 -159
- package/dist/lib/timeline.js +0 -95
- package/dist/lib/timezones.js +0 -388
- package/dist/lib/url.js +0 -89
- package/dist/lib/view.js +0 -217
- package/dist/middleware/auth.js +0 -52
- package/dist/middleware/onboarding.js +0 -41
- package/dist/routes/api/collections.js +0 -124
- package/dist/routes/api/nav-items.js +0 -104
- package/dist/routes/api/pages.js +0 -91
- package/dist/routes/api/posts.js +0 -218
- package/dist/routes/api/search.js +0 -48
- package/dist/routes/api/settings.js +0 -68
- package/dist/routes/api/upload.js +0 -246
- package/dist/routes/auth/reset.js +0 -221
- package/dist/routes/auth/setup.js +0 -194
- package/dist/routes/auth/signin.js +0 -176
- package/dist/routes/compose.js +0 -48
- package/dist/routes/dash/collections.js +0 -115
- package/dist/routes/dash/index.js +0 -118
- package/dist/routes/dash/media.js +0 -106
- package/dist/routes/dash/pages.js +0 -294
- package/dist/routes/dash/posts.js +0 -244
- package/dist/routes/dash/redirects.js +0 -257
- package/dist/routes/dash/settings.js +0 -379
- package/dist/routes/feed/rss.js +0 -62
- package/dist/routes/feed/sitemap.js +0 -49
- package/dist/routes/pages/archive.js +0 -62
- package/dist/routes/pages/collection.js +0 -34
- package/dist/routes/pages/collections.js +0 -28
- package/dist/routes/pages/featured.js +0 -36
- package/dist/routes/pages/home.js +0 -64
- package/dist/routes/pages/latest.js +0 -45
- package/dist/routes/pages/page.js +0 -68
- package/dist/routes/pages/post.js +0 -44
- package/dist/routes/pages/search.js +0 -54
- package/dist/services/collection.js +0 -109
- package/dist/services/index.js +0 -24
- package/dist/services/media.js +0 -117
- package/dist/services/navigation.js +0 -91
- package/dist/services/page.js +0 -84
- package/dist/services/post.js +0 -229
- package/dist/services/redirect.js +0 -48
- package/dist/services/search.js +0 -67
- package/dist/services/settings.js +0 -68
- package/dist/types/bindings.js +0 -3
- package/dist/types/config.js +0 -147
- package/dist/types/constants.js +0 -27
- package/dist/types/entities.js +0 -3
- package/dist/types/lingui-react-macro.d.js +0 -9
- package/dist/types/operations.js +0 -3
- package/dist/types/props.js +0 -3
- package/dist/types/sortablejs.d.js +0 -5
- package/dist/types/views.js +0 -5
- package/dist/types.js +0 -11
- package/dist/ui/color-themes.js +0 -268
- package/dist/ui/compose/ComposeDialog.js +0 -467
- package/dist/ui/compose/ComposePrompt.js +0 -55
- package/dist/ui/dash/ActionButtons.js +0 -46
- package/dist/ui/dash/CrudPageHeader.js +0 -22
- package/dist/ui/dash/DangerZone.js +0 -36
- package/dist/ui/dash/FormatBadge.js +0 -27
- package/dist/ui/dash/ListItemRow.js +0 -21
- package/dist/ui/dash/PageForm.js +0 -195
- package/dist/ui/dash/PostForm.js +0 -395
- package/dist/ui/dash/PostList.js +0 -83
- package/dist/ui/dash/StatusBadge.js +0 -46
- package/dist/ui/dash/collections/CollectionForm.js +0 -152
- package/dist/ui/dash/collections/CollectionsListContent.js +0 -68
- package/dist/ui/dash/collections/ViewCollectionContent.js +0 -96
- package/dist/ui/dash/index.js +0 -10
- package/dist/ui/dash/media/MediaListContent.js +0 -166
- package/dist/ui/dash/media/ViewMediaContent.js +0 -212
- package/dist/ui/dash/pages/LinkFormContent.js +0 -130
- package/dist/ui/dash/pages/UnifiedPagesContent.js +0 -193
- package/dist/ui/dash/settings/AccountContent.js +0 -209
- package/dist/ui/dash/settings/AppearanceContent.js +0 -259
- package/dist/ui/dash/settings/GeneralContent.js +0 -536
- package/dist/ui/dash/settings/SettingsNav.js +0 -41
- package/dist/ui/feed/LinkCard.js +0 -72
- package/dist/ui/feed/NoteCard.js +0 -58
- package/dist/ui/feed/QuoteCard.js +0 -63
- package/dist/ui/feed/ThreadPreview.js +0 -48
- package/dist/ui/feed/TimelineFeed.js +0 -41
- package/dist/ui/feed/TimelineItem.js +0 -27
- package/dist/ui/font-themes.js +0 -36
- package/dist/ui/layouts/BaseLayout.js +0 -153
- package/dist/ui/layouts/DashLayout.js +0 -141
- package/dist/ui/layouts/SiteLayout.js +0 -169
- package/dist/ui/pages/ArchivePage.js +0 -143
- package/dist/ui/pages/CollectionPage.js +0 -70
- package/dist/ui/pages/CollectionsPage.js +0 -76
- package/dist/ui/pages/FeaturedPage.js +0 -24
- package/dist/ui/pages/HomePage.js +0 -24
- package/dist/ui/pages/PostPage.js +0 -55
- package/dist/ui/pages/SearchPage.js +0 -122
- package/dist/ui/pages/SinglePage.js +0 -23
- package/dist/ui/shared/EmptyState.js +0 -27
- package/dist/ui/shared/MediaGallery.js +0 -35
- package/dist/ui/shared/Pagination.js +0 -195
- package/dist/ui/shared/ThreadView.js +0 -108
- package/dist/ui/shared/index.js +0 -5
- package/dist/vendor/datastar.js +0 -1606
- package/src/lib/__tests__/config.test.ts +0 -192
- package/src/lib/config.ts +0 -167
- package/src/routes/compose.ts +0 -63
- package/src/ui/dash/PostForm.tsx +0 -360
- package/src/ui/dash/settings/AppearanceContent.tsx +0 -254
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared type definitions for the dashboard post form Lit component.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type PostFormat = "note" | "link" | "quote";
|
|
6
|
+
export type PostStatus = "published" | "draft";
|
|
7
|
+
|
|
8
|
+
export interface PostFormLabels {
|
|
9
|
+
formatLabel: string;
|
|
10
|
+
noteOption: string;
|
|
11
|
+
linkOption: string;
|
|
12
|
+
quoteOption: string;
|
|
13
|
+
titleLabel: string;
|
|
14
|
+
titlePlaceholder: string;
|
|
15
|
+
bodyLabel: string;
|
|
16
|
+
bodyPlaceholder: string;
|
|
17
|
+
urlLabel: string;
|
|
18
|
+
urlPlaceholder: string;
|
|
19
|
+
quoteTextLabel: string;
|
|
20
|
+
quoteTextPlaceholder: string;
|
|
21
|
+
mediaLabel: string;
|
|
22
|
+
mediaAddButton: string;
|
|
23
|
+
mediaRemoveButton: string;
|
|
24
|
+
mediaEmptyLabel: string;
|
|
25
|
+
statusLabel: string;
|
|
26
|
+
statusPublished: string;
|
|
27
|
+
statusDraft: string;
|
|
28
|
+
featuredLabel: string;
|
|
29
|
+
pinnedLabel: string;
|
|
30
|
+
collectionsLabel: string;
|
|
31
|
+
submitLabel: string;
|
|
32
|
+
cancelLabel: string;
|
|
33
|
+
mediaDialogTitle: string;
|
|
34
|
+
mediaDialogDone: string;
|
|
35
|
+
mediaDialogLoading: string;
|
|
36
|
+
submitSuccessMessage: string;
|
|
37
|
+
submitErrorMessage: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface PostFormInitial {
|
|
41
|
+
format: PostFormat;
|
|
42
|
+
title: string;
|
|
43
|
+
body: string;
|
|
44
|
+
url: string;
|
|
45
|
+
quoteText: string;
|
|
46
|
+
status: PostStatus;
|
|
47
|
+
featured: boolean;
|
|
48
|
+
pinned: boolean;
|
|
49
|
+
rating: number;
|
|
50
|
+
collectionIds: number[];
|
|
51
|
+
mediaIds: string[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface PostCollectionOption {
|
|
55
|
+
id: number;
|
|
56
|
+
title: string;
|
|
57
|
+
icon?: string | null;
|
|
58
|
+
iconHtml?: string | null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface PostMediaItem {
|
|
62
|
+
id: string;
|
|
63
|
+
thumbUrl: string;
|
|
64
|
+
alt: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface PostSubmitDetail {
|
|
68
|
+
endpoint: string;
|
|
69
|
+
isEdit: boolean;
|
|
70
|
+
data: {
|
|
71
|
+
format: PostFormat;
|
|
72
|
+
title?: string;
|
|
73
|
+
body?: string;
|
|
74
|
+
status: PostStatus;
|
|
75
|
+
featured: boolean;
|
|
76
|
+
pinned: boolean;
|
|
77
|
+
url?: string;
|
|
78
|
+
quoteText?: string;
|
|
79
|
+
rating?: number;
|
|
80
|
+
collectionIds: number[];
|
|
81
|
+
mediaIds: string[];
|
|
82
|
+
};
|
|
83
|
+
messages: {
|
|
84
|
+
success: string;
|
|
85
|
+
error: string;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for settings Lit components and bridge script
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/** Translated labels for the settings UI */
|
|
6
|
+
export interface SettingsLabels {
|
|
7
|
+
// Avatar
|
|
8
|
+
blogAvatar: string;
|
|
9
|
+
uploadAvatar: string;
|
|
10
|
+
remove: string;
|
|
11
|
+
avatarHelp: string;
|
|
12
|
+
displayInHeader: string;
|
|
13
|
+
processing: string;
|
|
14
|
+
uploading: string;
|
|
15
|
+
uploadError: string;
|
|
16
|
+
|
|
17
|
+
// General
|
|
18
|
+
general: string;
|
|
19
|
+
siteName: string;
|
|
20
|
+
aboutBlog: string;
|
|
21
|
+
aboutBlogHelp: string;
|
|
22
|
+
siteFooter: string;
|
|
23
|
+
footerHelp: string;
|
|
24
|
+
markdownSupported: string;
|
|
25
|
+
language: string;
|
|
26
|
+
defaultHomepageView: string;
|
|
27
|
+
latest: string;
|
|
28
|
+
featured: string;
|
|
29
|
+
timeZone: string;
|
|
30
|
+
|
|
31
|
+
// SEO
|
|
32
|
+
seo: string;
|
|
33
|
+
allowIndexing: string;
|
|
34
|
+
|
|
35
|
+
// Actions
|
|
36
|
+
save: string;
|
|
37
|
+
cancel: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Timezone entry for the select dropdown */
|
|
41
|
+
export interface SettingsTimezone {
|
|
42
|
+
value: string;
|
|
43
|
+
label: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Language option for the select dropdown */
|
|
47
|
+
export interface SettingsLanguage {
|
|
48
|
+
value: string;
|
|
49
|
+
label: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Event detail dispatched when a settings form is saved */
|
|
53
|
+
export interface SettingsSaveDetail {
|
|
54
|
+
endpoint: string;
|
|
55
|
+
data: Record<string, unknown>;
|
|
56
|
+
section: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Event detail dispatched when avatar remove is requested */
|
|
60
|
+
export interface AvatarRemoveDetail {
|
|
61
|
+
endpoint: string;
|
|
62
|
+
}
|
|
@@ -3,10 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Full-screen compose dialog for quick post creation.
|
|
5
5
|
* Rendered server-side as part of SiteLayout for authenticated users.
|
|
6
|
+
*
|
|
7
|
+
* The Lit Web Component <jant-compose-dialog> handles all form state
|
|
8
|
+
* and rendering. Server provides labels and collections as JSON attributes.
|
|
6
9
|
*/
|
|
7
10
|
|
|
8
11
|
import type { FC } from "hono/jsx";
|
|
9
12
|
import type { Collection } from "../../types.js";
|
|
13
|
+
import { renderCollectionIcon } from "../../lib/icons.js";
|
|
10
14
|
import { useLingui } from "@lingui/react/macro";
|
|
11
15
|
|
|
12
16
|
export interface ComposeDialogProps {
|
|
@@ -16,399 +20,151 @@ export interface ComposeDialogProps {
|
|
|
16
20
|
export const ComposeDialog: FC<ComposeDialogProps> = ({ collections }) => {
|
|
17
21
|
const { t } = useLingui();
|
|
18
22
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
23
|
+
const labels = JSON.stringify({
|
|
24
|
+
cancel: t({ message: "Cancel", comment: "@context: Close compose dialog" }),
|
|
25
|
+
note: t({ message: "Note", comment: "@context: Compose format tab" }),
|
|
26
|
+
link: t({ message: "Link", comment: "@context: Compose format tab" }),
|
|
27
|
+
quote: t({ message: "Quote", comment: "@context: Compose format tab" }),
|
|
28
|
+
saveDraft: t({
|
|
29
|
+
message: "Save as Draft",
|
|
30
|
+
comment: "@context: Header draft button tooltip",
|
|
31
|
+
}),
|
|
32
|
+
saveAsDraft: t({
|
|
33
|
+
message: "Save as draft",
|
|
34
|
+
comment: "@context: More menu - save draft",
|
|
35
|
+
}),
|
|
36
|
+
discard: t({
|
|
37
|
+
message: "Discard",
|
|
38
|
+
comment: "@context: More menu - discard post",
|
|
39
|
+
}),
|
|
40
|
+
titlePlaceholder: t({
|
|
41
|
+
message: "Title",
|
|
42
|
+
comment: "@context: Compose note title placeholder",
|
|
43
|
+
}),
|
|
44
|
+
bodyPlaceholder: t({
|
|
45
|
+
message: "What's on your mind...",
|
|
46
|
+
comment: "@context: Compose body placeholder",
|
|
47
|
+
}),
|
|
48
|
+
urlPlaceholder: t({
|
|
49
|
+
message: "Paste a URL...",
|
|
50
|
+
comment: "@context: Compose link URL placeholder",
|
|
51
|
+
}),
|
|
52
|
+
linkTitlePlaceholder: t({
|
|
53
|
+
message: "Give it a title...",
|
|
54
|
+
comment: "@context: Compose link title placeholder",
|
|
55
|
+
}),
|
|
56
|
+
thoughtsPlaceholder: t({
|
|
57
|
+
message: "Your thoughts (optional)",
|
|
58
|
+
comment: "@context: Compose thoughts placeholder",
|
|
59
|
+
}),
|
|
60
|
+
quotePlaceholder: t({
|
|
61
|
+
message: "Type the quote...",
|
|
62
|
+
comment: "@context: Compose quote text placeholder",
|
|
63
|
+
}),
|
|
64
|
+
authorPlaceholder: t({
|
|
65
|
+
message: "Author (optional)",
|
|
66
|
+
comment: "@context: Compose quote author placeholder",
|
|
67
|
+
}),
|
|
68
|
+
sourcePlaceholder: t({
|
|
69
|
+
message: "Source link (optional)",
|
|
70
|
+
comment: "@context: Compose quote source link placeholder",
|
|
71
|
+
}),
|
|
72
|
+
attachedText: t({
|
|
73
|
+
message: "Attached Text",
|
|
74
|
+
comment: "@context: Attached text panel title",
|
|
75
|
+
}),
|
|
76
|
+
attachedTextPlaceholder: t({
|
|
77
|
+
message:
|
|
78
|
+
"Paste a long article, AI response, or any text...\n\nMarkdown formatting will be preserved.",
|
|
79
|
+
comment: "@context: Attached text placeholder",
|
|
80
|
+
}),
|
|
81
|
+
attachedTextHint: t({
|
|
82
|
+
message: "Supplementary content attached to your post",
|
|
83
|
+
comment: "@context: Attached text panel hint",
|
|
84
|
+
}),
|
|
85
|
+
done: t({
|
|
86
|
+
message: "Done",
|
|
87
|
+
comment: "@context: Close attached text panel",
|
|
88
|
+
}),
|
|
89
|
+
media: t({
|
|
90
|
+
message: "Media",
|
|
91
|
+
comment: "@context: Compose toolbar - media tooltip",
|
|
92
|
+
}),
|
|
93
|
+
score: t({
|
|
94
|
+
message: "Score",
|
|
95
|
+
comment: "@context: Compose toolbar - score tooltip",
|
|
96
|
+
}),
|
|
97
|
+
title: t({
|
|
98
|
+
message: "Title",
|
|
99
|
+
comment: "@context: Compose toolbar - title tooltip",
|
|
100
|
+
}),
|
|
101
|
+
collection: t({
|
|
102
|
+
message: "Collection",
|
|
103
|
+
comment: "@context: Compose collection selector trigger label",
|
|
104
|
+
}),
|
|
105
|
+
searchCollections: t({
|
|
106
|
+
message: "Search...",
|
|
107
|
+
comment: "@context: Compose collection combobox search placeholder",
|
|
108
|
+
}),
|
|
109
|
+
noCollections: t({
|
|
110
|
+
message: "No collections found.",
|
|
111
|
+
comment: "@context: Compose collection combobox empty state",
|
|
112
|
+
}),
|
|
113
|
+
post: t({
|
|
114
|
+
message: "Post",
|
|
115
|
+
comment: "@context: Compose button - publish post",
|
|
116
|
+
}),
|
|
117
|
+
addAlt: t({
|
|
118
|
+
message: "+ ALT",
|
|
119
|
+
comment: "@context: Add alt text label under attachment thumbnail",
|
|
120
|
+
}),
|
|
121
|
+
addAltTitle: t({
|
|
122
|
+
message: "Add alt text",
|
|
123
|
+
comment: "@context: Alt text panel title",
|
|
124
|
+
}),
|
|
125
|
+
altPlaceholder: t({
|
|
126
|
+
message: "Describe this for people with visual impairments...",
|
|
127
|
+
comment: "@context: Alt text textarea placeholder",
|
|
128
|
+
}),
|
|
129
|
+
altHint: t({
|
|
130
|
+
message: "Alt text improves accessibility",
|
|
131
|
+
comment: "@context: Hint text in alt text panel",
|
|
132
|
+
}),
|
|
133
|
+
addMore: t({
|
|
134
|
+
message: "Add",
|
|
135
|
+
comment: "@context: Add more attachments button",
|
|
136
|
+
}),
|
|
137
|
+
uploading: t({
|
|
138
|
+
message: "Uploading...",
|
|
139
|
+
comment: "@context: Toast shown during background upload",
|
|
140
|
+
}),
|
|
141
|
+
published: t({
|
|
142
|
+
message: "Published!",
|
|
143
|
+
comment: "@context: Toast shown after successful deferred publish",
|
|
144
|
+
}),
|
|
34
145
|
}).replace(/</g, "\\u003c");
|
|
35
146
|
|
|
147
|
+
const collectionsJson = JSON.stringify(
|
|
148
|
+
(collections ?? []).map((c) => ({
|
|
149
|
+
id: c.id,
|
|
150
|
+
title: c.title,
|
|
151
|
+
iconHtml: renderCollectionIcon(c.icon, { size: 16 }),
|
|
152
|
+
})),
|
|
153
|
+
).replace(/</g, "\\u003c");
|
|
154
|
+
|
|
36
155
|
return (
|
|
37
156
|
<dialog
|
|
38
157
|
id="compose-dialog"
|
|
39
|
-
class="compose-dialog
|
|
158
|
+
class="compose-dialog"
|
|
40
159
|
onclick="event.target === this && this.close()"
|
|
41
160
|
>
|
|
42
|
-
<
|
|
43
|
-
{/*
|
|
44
|
-
<
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
class="compose-dialog-close"
|
|
48
|
-
onclick="this.closest('dialog').close()"
|
|
49
|
-
>
|
|
50
|
-
<svg
|
|
51
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
52
|
-
width="20"
|
|
53
|
-
height="20"
|
|
54
|
-
viewBox="0 0 24 24"
|
|
55
|
-
fill="none"
|
|
56
|
-
stroke="currentColor"
|
|
57
|
-
stroke-width="2"
|
|
58
|
-
stroke-linecap="round"
|
|
59
|
-
stroke-linejoin="round"
|
|
60
|
-
>
|
|
61
|
-
<path d="M18 6 6 18" />
|
|
62
|
-
<path d="M6 6l12 12" />
|
|
63
|
-
</svg>
|
|
64
|
-
</button>
|
|
65
|
-
<h2 class="compose-dialog-title">
|
|
66
|
-
{t({
|
|
67
|
-
message: "New Post",
|
|
68
|
-
comment: "@context: Compose dialog title",
|
|
69
|
-
})}
|
|
70
|
-
</h2>
|
|
71
|
-
<div class="w-5" />
|
|
72
|
-
</header>
|
|
73
|
-
|
|
74
|
-
{/* Form */}
|
|
75
|
-
<section class="compose-dialog-body">
|
|
76
|
-
<form
|
|
77
|
-
data-signals={signals}
|
|
78
|
-
data-on:submit__prevent="@post('/compose')"
|
|
79
|
-
data-indicator="_composeLoading"
|
|
80
|
-
class="flex flex-col gap-3"
|
|
81
|
-
>
|
|
82
|
-
{/* Format tabs */}
|
|
83
|
-
<div class="compose-format-tabs">
|
|
84
|
-
<button
|
|
85
|
-
type="button"
|
|
86
|
-
class="compose-format-tab"
|
|
87
|
-
data-class-compose-format-tab-active="$format === 'note'"
|
|
88
|
-
data-on:click="$format = 'note'"
|
|
89
|
-
>
|
|
90
|
-
{t({
|
|
91
|
-
message: "Note",
|
|
92
|
-
comment: "@context: Compose format tab",
|
|
93
|
-
})}
|
|
94
|
-
</button>
|
|
95
|
-
<button
|
|
96
|
-
type="button"
|
|
97
|
-
class="compose-format-tab"
|
|
98
|
-
data-class-compose-format-tab-active="$format === 'link'"
|
|
99
|
-
data-on:click="$format = 'link'"
|
|
100
|
-
>
|
|
101
|
-
{t({
|
|
102
|
-
message: "Link",
|
|
103
|
-
comment: "@context: Compose format tab",
|
|
104
|
-
})}
|
|
105
|
-
</button>
|
|
106
|
-
<button
|
|
107
|
-
type="button"
|
|
108
|
-
class="compose-format-tab"
|
|
109
|
-
data-class-compose-format-tab-active="$format === 'quote'"
|
|
110
|
-
data-on:click="$format = 'quote'"
|
|
111
|
-
>
|
|
112
|
-
{t({
|
|
113
|
-
message: "Quote",
|
|
114
|
-
comment: "@context: Compose format tab",
|
|
115
|
-
})}
|
|
116
|
-
</button>
|
|
117
|
-
</div>
|
|
118
|
-
|
|
119
|
-
{/* Title input */}
|
|
120
|
-
<input
|
|
121
|
-
type="text"
|
|
122
|
-
data-bind="title"
|
|
123
|
-
class="compose-title-input"
|
|
124
|
-
placeholder={t({
|
|
125
|
-
message: "Title (optional)",
|
|
126
|
-
comment: "@context: Compose title placeholder",
|
|
127
|
-
})}
|
|
128
|
-
/>
|
|
129
|
-
|
|
130
|
-
{/* Body textarea */}
|
|
131
|
-
<textarea
|
|
132
|
-
data-bind="body"
|
|
133
|
-
class="compose-body-input"
|
|
134
|
-
placeholder={t({
|
|
135
|
-
message: "What's on your mind?",
|
|
136
|
-
comment: "@context: Compose body placeholder",
|
|
137
|
-
})}
|
|
138
|
-
rows={4}
|
|
139
|
-
/>
|
|
140
|
-
|
|
141
|
-
{/* URL input (link/quote) */}
|
|
142
|
-
<div data-show="$format === 'link' || $format === 'quote'">
|
|
143
|
-
<input
|
|
144
|
-
type="url"
|
|
145
|
-
data-bind="url"
|
|
146
|
-
class="input text-sm"
|
|
147
|
-
placeholder="https://..."
|
|
148
|
-
/>
|
|
149
|
-
</div>
|
|
150
|
-
|
|
151
|
-
{/* Quote text (quote format) */}
|
|
152
|
-
<div data-show="$format === 'quote'">
|
|
153
|
-
<textarea
|
|
154
|
-
data-bind="quoteText"
|
|
155
|
-
class="textarea text-sm"
|
|
156
|
-
placeholder={t({
|
|
157
|
-
message: "The text being quoted...",
|
|
158
|
-
comment: "@context: Compose quote text placeholder",
|
|
159
|
-
})}
|
|
160
|
-
rows={2}
|
|
161
|
-
/>
|
|
162
|
-
</div>
|
|
163
|
-
|
|
164
|
-
{/* Rating picker (toggleable) */}
|
|
165
|
-
<div data-show="$_showRating" class="field">
|
|
166
|
-
<label class="label text-sm">
|
|
167
|
-
{t({
|
|
168
|
-
message: "Rating",
|
|
169
|
-
comment: "@context: Compose rating field",
|
|
170
|
-
})}
|
|
171
|
-
</label>
|
|
172
|
-
<select data-bind="rating" class="select text-sm">
|
|
173
|
-
<option value="0">
|
|
174
|
-
{t({
|
|
175
|
-
message: "None",
|
|
176
|
-
comment: "@context: No rating selected",
|
|
177
|
-
})}
|
|
178
|
-
</option>
|
|
179
|
-
<option value="1">1</option>
|
|
180
|
-
<option value="2">2</option>
|
|
181
|
-
<option value="3">3</option>
|
|
182
|
-
<option value="4">4</option>
|
|
183
|
-
<option value="5">5</option>
|
|
184
|
-
</select>
|
|
185
|
-
</div>
|
|
186
|
-
|
|
187
|
-
{/* Collection picker (toggleable) */}
|
|
188
|
-
{collections && collections.length > 0 && (
|
|
189
|
-
<div data-show="$_showCollection" class="field">
|
|
190
|
-
<label class="label text-sm">
|
|
191
|
-
{t({
|
|
192
|
-
message: "Collection",
|
|
193
|
-
comment: "@context: Compose collection field",
|
|
194
|
-
})}
|
|
195
|
-
</label>
|
|
196
|
-
<select data-bind="collectionId" class="select text-sm">
|
|
197
|
-
<option value="0">
|
|
198
|
-
{t({
|
|
199
|
-
message: "None",
|
|
200
|
-
comment: "@context: No collection selected",
|
|
201
|
-
})}
|
|
202
|
-
</option>
|
|
203
|
-
{collections.map((col) => (
|
|
204
|
-
<option key={col.id} value={col.id}>
|
|
205
|
-
{col.title}
|
|
206
|
-
</option>
|
|
207
|
-
))}
|
|
208
|
-
</select>
|
|
209
|
-
</div>
|
|
210
|
-
)}
|
|
211
|
-
|
|
212
|
-
{/* Toolbar */}
|
|
213
|
-
<div class="compose-toolbar">
|
|
214
|
-
<div class="flex gap-1">
|
|
215
|
-
{/* Media button */}
|
|
216
|
-
<button
|
|
217
|
-
type="button"
|
|
218
|
-
class="compose-toolbar-btn"
|
|
219
|
-
title={t({
|
|
220
|
-
message: "Add Media",
|
|
221
|
-
comment: "@context: Compose toolbar - add media",
|
|
222
|
-
})}
|
|
223
|
-
data-on:click="document.getElementById('compose-media-picker').showModal(); fetch('/dash/media/picker').then(r => r.text()).then(html => document.getElementById('compose-media-grid').innerHTML = html)"
|
|
224
|
-
>
|
|
225
|
-
<svg
|
|
226
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
227
|
-
width="18"
|
|
228
|
-
height="18"
|
|
229
|
-
viewBox="0 0 24 24"
|
|
230
|
-
fill="none"
|
|
231
|
-
stroke="currentColor"
|
|
232
|
-
stroke-width="2"
|
|
233
|
-
stroke-linecap="round"
|
|
234
|
-
stroke-linejoin="round"
|
|
235
|
-
>
|
|
236
|
-
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
|
|
237
|
-
<circle cx="9" cy="9" r="2" />
|
|
238
|
-
<path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" />
|
|
239
|
-
</svg>
|
|
240
|
-
</button>
|
|
241
|
-
|
|
242
|
-
{/* Rating toggle */}
|
|
243
|
-
<button
|
|
244
|
-
type="button"
|
|
245
|
-
class="compose-toolbar-btn"
|
|
246
|
-
title={t({
|
|
247
|
-
message: "Rating",
|
|
248
|
-
comment: "@context: Compose toolbar - toggle rating",
|
|
249
|
-
})}
|
|
250
|
-
data-on:click="$_showRating = !$_showRating"
|
|
251
|
-
>
|
|
252
|
-
<svg
|
|
253
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
254
|
-
width="18"
|
|
255
|
-
height="18"
|
|
256
|
-
viewBox="0 0 24 24"
|
|
257
|
-
fill="none"
|
|
258
|
-
stroke="currentColor"
|
|
259
|
-
stroke-width="2"
|
|
260
|
-
stroke-linecap="round"
|
|
261
|
-
stroke-linejoin="round"
|
|
262
|
-
>
|
|
263
|
-
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" />
|
|
264
|
-
</svg>
|
|
265
|
-
</button>
|
|
266
|
-
|
|
267
|
-
{/* Collection toggle */}
|
|
268
|
-
{collections && collections.length > 0 && (
|
|
269
|
-
<button
|
|
270
|
-
type="button"
|
|
271
|
-
class="compose-toolbar-btn"
|
|
272
|
-
title={t({
|
|
273
|
-
message: "Collection",
|
|
274
|
-
comment: "@context: Compose toolbar - toggle collection",
|
|
275
|
-
})}
|
|
276
|
-
data-on:click="$_showCollection = !$_showCollection"
|
|
277
|
-
>
|
|
278
|
-
<svg
|
|
279
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
280
|
-
width="18"
|
|
281
|
-
height="18"
|
|
282
|
-
viewBox="0 0 24 24"
|
|
283
|
-
fill="none"
|
|
284
|
-
stroke="currentColor"
|
|
285
|
-
stroke-width="2"
|
|
286
|
-
stroke-linecap="round"
|
|
287
|
-
stroke-linejoin="round"
|
|
288
|
-
>
|
|
289
|
-
<path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" />
|
|
290
|
-
</svg>
|
|
291
|
-
</button>
|
|
292
|
-
)}
|
|
293
|
-
</div>
|
|
294
|
-
</div>
|
|
295
|
-
|
|
296
|
-
{/* Footer: checkboxes + submit */}
|
|
297
|
-
<div class="compose-dialog-footer">
|
|
298
|
-
<div class="flex gap-3">
|
|
299
|
-
<label class="flex items-center gap-1.5 text-xs text-muted-foreground">
|
|
300
|
-
<input
|
|
301
|
-
type="checkbox"
|
|
302
|
-
class="checkbox"
|
|
303
|
-
data-bind="featured"
|
|
304
|
-
/>
|
|
305
|
-
{t({
|
|
306
|
-
message: "Featured",
|
|
307
|
-
comment: "@context: Compose checkbox - mark as featured",
|
|
308
|
-
})}
|
|
309
|
-
</label>
|
|
310
|
-
<label class="flex items-center gap-1.5 text-xs text-muted-foreground">
|
|
311
|
-
<input type="checkbox" class="checkbox" data-bind="pinned" />
|
|
312
|
-
{t({
|
|
313
|
-
message: "Pinned",
|
|
314
|
-
comment: "@context: Compose checkbox - pin to top",
|
|
315
|
-
})}
|
|
316
|
-
</label>
|
|
317
|
-
</div>
|
|
318
|
-
<div class="flex gap-2">
|
|
319
|
-
<button
|
|
320
|
-
type="button"
|
|
321
|
-
class="btn-outline text-sm"
|
|
322
|
-
data-attr:disabled="$_composeLoading"
|
|
323
|
-
data-on:click="$status = 'draft'; document.querySelector('#compose-dialog form').requestSubmit()"
|
|
324
|
-
>
|
|
325
|
-
<svg
|
|
326
|
-
data-show="$_composeLoading"
|
|
327
|
-
style="display:none"
|
|
328
|
-
class="animate-spin size-4"
|
|
329
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
330
|
-
viewBox="0 0 24 24"
|
|
331
|
-
fill="none"
|
|
332
|
-
stroke="currentColor"
|
|
333
|
-
stroke-width="2"
|
|
334
|
-
stroke-linecap="round"
|
|
335
|
-
stroke-linejoin="round"
|
|
336
|
-
role="status"
|
|
337
|
-
>
|
|
338
|
-
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
|
339
|
-
</svg>
|
|
340
|
-
{t({
|
|
341
|
-
message: "Draft",
|
|
342
|
-
comment: "@context: Compose button - save as draft",
|
|
343
|
-
})}
|
|
344
|
-
</button>
|
|
345
|
-
<button
|
|
346
|
-
type="submit"
|
|
347
|
-
class="btn text-sm"
|
|
348
|
-
data-attr:disabled="$_composeLoading"
|
|
349
|
-
>
|
|
350
|
-
<svg
|
|
351
|
-
data-show="$_composeLoading"
|
|
352
|
-
style="display:none"
|
|
353
|
-
class="animate-spin size-4"
|
|
354
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
355
|
-
viewBox="0 0 24 24"
|
|
356
|
-
fill="none"
|
|
357
|
-
stroke="currentColor"
|
|
358
|
-
stroke-width="2"
|
|
359
|
-
stroke-linecap="round"
|
|
360
|
-
stroke-linejoin="round"
|
|
361
|
-
role="status"
|
|
362
|
-
>
|
|
363
|
-
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
|
364
|
-
</svg>
|
|
365
|
-
{t({
|
|
366
|
-
message: "Post",
|
|
367
|
-
comment: "@context: Compose button - publish post",
|
|
368
|
-
})}
|
|
369
|
-
</button>
|
|
370
|
-
</div>
|
|
371
|
-
</div>
|
|
372
|
-
</form>
|
|
373
|
-
</section>
|
|
374
|
-
</div>
|
|
375
|
-
|
|
376
|
-
{/* Nested media picker dialog */}
|
|
377
|
-
<dialog
|
|
378
|
-
id="compose-media-picker"
|
|
379
|
-
class="p-6 rounded-lg max-w-2xl w-full backdrop:bg-black/50"
|
|
380
|
-
onclick="event.target === this && this.close()"
|
|
381
|
-
>
|
|
382
|
-
<div class="flex items-center justify-between mb-4">
|
|
383
|
-
<h2 class="text-lg font-semibold">
|
|
384
|
-
{t({
|
|
385
|
-
message: "Select Media",
|
|
386
|
-
comment: "@context: Media picker dialog title",
|
|
387
|
-
})}
|
|
388
|
-
</h2>
|
|
389
|
-
<button
|
|
390
|
-
type="button"
|
|
391
|
-
class="btn-outline text-sm"
|
|
392
|
-
onclick="this.closest('dialog').close()"
|
|
393
|
-
>
|
|
394
|
-
{t({
|
|
395
|
-
message: "Done",
|
|
396
|
-
comment: "@context: Close media picker button",
|
|
397
|
-
})}
|
|
398
|
-
</button>
|
|
399
|
-
</div>
|
|
400
|
-
<div
|
|
401
|
-
id="compose-media-grid"
|
|
402
|
-
class="grid grid-cols-4 gap-2 max-h-96 overflow-y-auto"
|
|
403
|
-
>
|
|
404
|
-
<p class="text-muted-foreground text-sm col-span-4">
|
|
405
|
-
{t({
|
|
406
|
-
message: "Loading...",
|
|
407
|
-
comment: "@context: Loading state for media picker",
|
|
408
|
-
})}
|
|
409
|
-
</p>
|
|
161
|
+
<jant-compose-dialog collections={collectionsJson} labels={labels}>
|
|
162
|
+
{/* SSR fallback skeleton */}
|
|
163
|
+
<div class="compose-dialog-inner">
|
|
164
|
+
<div class="compose-dialog-header" />
|
|
165
|
+
<div class="compose-body skel-section-md" />
|
|
410
166
|
</div>
|
|
411
|
-
</dialog>
|
|
167
|
+
</jant-compose-dialog>
|
|
412
168
|
</dialog>
|
|
413
169
|
);
|
|
414
170
|
};
|