@jant/core 0.3.27 → 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.
Files changed (313) hide show
  1. package/dist/client/client.css +1 -0
  2. package/dist/client/client.js +31561 -0
  3. package/dist/index.js +15209 -15
  4. package/package.json +21 -15
  5. package/src/__tests__/helpers/app.ts +19 -3
  6. package/src/__tests__/helpers/db.ts +44 -0
  7. package/src/__tests__/helpers/lingui-core-macro-mock.ts +33 -0
  8. package/src/app.tsx +111 -174
  9. package/src/client.ts +13 -0
  10. package/src/db/migrations/0007_post_collections_m2m.sql +94 -0
  11. package/src/db/migrations/0008_add_collection_dividers.sql +8 -0
  12. package/src/db/migrations/0009_drop_collection_show_divider.sql +2 -0
  13. package/src/db/migrations/0010_add_performance_indexes.sql +16 -0
  14. package/src/db/schema.ts +24 -4
  15. package/src/i18n/locales/en.po +810 -385
  16. package/src/i18n/locales/en.ts +1 -1
  17. package/src/i18n/locales/zh-Hans.po +733 -522
  18. package/src/i18n/locales/zh-Hans.ts +1 -1
  19. package/src/i18n/locales/zh-Hant.po +733 -522
  20. package/src/i18n/locales/zh-Hant.ts +1 -1
  21. package/src/i18n/middleware.ts +7 -11
  22. package/src/index.ts +1 -1
  23. package/src/lib/__tests__/icons.test.ts +178 -0
  24. package/src/lib/__tests__/resolve-config.test.ts +184 -0
  25. package/src/lib/__tests__/schemas.test.ts +12 -6
  26. package/src/lib/__tests__/theme.test.ts +62 -0
  27. package/src/lib/__tests__/timezones.test.ts +1 -1
  28. package/src/lib/__tests__/url.test.ts +12 -0
  29. package/src/lib/__tests__/view.test.ts +1 -5
  30. package/src/lib/avatar-upload.ts +18 -10
  31. package/src/lib/collection-form-bridge.ts +52 -0
  32. package/src/lib/collections-reorder.ts +28 -0
  33. package/src/lib/compose-bridge.ts +251 -0
  34. package/src/lib/errors.ts +116 -0
  35. package/src/lib/excerpt.ts +1 -1
  36. package/src/lib/favicon.ts +3 -5
  37. package/src/lib/html.ts +22 -0
  38. package/src/lib/icon-catalog.ts +181 -0
  39. package/src/lib/icons.ts +202 -0
  40. package/src/lib/navigation.ts +18 -33
  41. package/src/lib/pagination.ts +3 -2
  42. package/src/lib/post-form-bridge.ts +136 -0
  43. package/src/lib/render.tsx +11 -4
  44. package/src/lib/resolve-config.ts +157 -0
  45. package/src/lib/schemas.ts +76 -12
  46. package/src/lib/settings-bridge.ts +139 -0
  47. package/src/lib/storage.ts +37 -16
  48. package/src/lib/theme.ts +5 -7
  49. package/src/lib/timeline.ts +4 -8
  50. package/src/lib/toast.ts +134 -0
  51. package/src/lib/upload.ts +71 -0
  52. package/src/lib/url.ts +9 -1
  53. package/src/lib/version.ts +16 -0
  54. package/src/lib/view.ts +9 -10
  55. package/src/middleware/__tests__/auth.test.ts +6 -28
  56. package/src/middleware/__tests__/onboarding.test.ts +1 -1
  57. package/src/middleware/auth.ts +6 -12
  58. package/src/middleware/config.ts +51 -0
  59. package/src/middleware/error-handler.ts +56 -0
  60. package/src/middleware/onboarding.ts +1 -1
  61. package/src/preset.css +6 -0
  62. package/src/routes/__tests__/compose.test.ts +104 -17
  63. package/src/routes/api/__tests__/collections.test.ts +93 -2
  64. package/src/routes/api/__tests__/posts.test.ts +2 -1
  65. package/src/routes/api/__tests__/settings.test.ts +1 -1
  66. package/src/routes/api/collections.ts +64 -68
  67. package/src/routes/api/nav-items.ts +21 -59
  68. package/src/routes/api/pages.ts +18 -46
  69. package/src/routes/api/posts.ts +64 -86
  70. package/src/routes/api/search.ts +6 -4
  71. package/src/routes/api/settings.ts +8 -24
  72. package/src/routes/api/upload.ts +55 -53
  73. package/src/routes/auth/__tests__/setup.test.ts +118 -0
  74. package/src/routes/auth/reset.tsx +17 -66
  75. package/src/routes/auth/setup.tsx +67 -11
  76. package/src/routes/auth/signin.tsx +44 -8
  77. package/src/routes/compose.tsx +194 -0
  78. package/src/routes/dash/__tests__/font-theme.test.ts +110 -0
  79. package/src/routes/dash/__tests__/pages.test.ts +2 -2
  80. package/src/routes/dash/__tests__/settings-avatar.test.ts +23 -12
  81. package/src/routes/dash/appearance.tsx +173 -0
  82. package/src/routes/dash/collections.tsx +80 -14
  83. package/src/routes/dash/index.tsx +12 -14
  84. package/src/routes/dash/media.tsx +46 -49
  85. package/src/routes/dash/pages.tsx +85 -37
  86. package/src/routes/dash/posts.tsx +60 -23
  87. package/src/routes/dash/redirects.tsx +43 -33
  88. package/src/routes/dash/settings.tsx +234 -214
  89. package/src/routes/feed/__tests__/rss.test.ts +7 -3
  90. package/src/routes/feed/rss.ts +11 -16
  91. package/src/routes/feed/sitemap.ts +15 -9
  92. package/src/routes/pages/__tests__/collections.test.ts +9 -8
  93. package/src/routes/pages/archive.tsx +2 -2
  94. package/src/routes/pages/collection.tsx +76 -9
  95. package/src/routes/pages/collections.tsx +3 -1
  96. package/src/routes/pages/featured.tsx +2 -2
  97. package/src/routes/pages/home.tsx +3 -3
  98. package/src/routes/pages/latest.tsx +2 -2
  99. package/src/routes/pages/page.tsx +2 -2
  100. package/src/routes/pages/post.tsx +2 -2
  101. package/src/routes/pages/search.tsx +2 -2
  102. package/src/services/__tests__/collection.test.ts +324 -34
  103. package/src/services/__tests__/media.test.ts +1 -1
  104. package/src/services/__tests__/page.test.ts +116 -1
  105. package/src/services/auth.ts +88 -0
  106. package/src/services/collection.ts +169 -30
  107. package/src/services/index.ts +8 -3
  108. package/src/services/media.ts +39 -12
  109. package/src/services/navigation.ts +17 -5
  110. package/src/services/page.ts +24 -4
  111. package/src/services/post.ts +87 -19
  112. package/src/services/search.ts +0 -1
  113. package/src/services/settings.ts +21 -13
  114. package/src/style.css +3 -0
  115. package/src/styles/components.css +42 -1
  116. package/src/styles/tokens.css +4 -0
  117. package/src/styles/ui.css +902 -73
  118. package/src/types/app-context.ts +25 -0
  119. package/src/types/bindings.ts +1 -0
  120. package/src/types/config.ts +60 -23
  121. package/src/types/entities.ts +12 -2
  122. package/src/types/lingui-react-macro.d.ts +3 -3
  123. package/src/types/operations.ts +2 -4
  124. package/src/types/views.ts +1 -3
  125. package/src/ui/__tests__/font-themes.test.ts +27 -8
  126. package/src/ui/color-themes.ts +1 -1
  127. package/src/ui/components/__tests__/jant-collection-form.test.ts +153 -0
  128. package/src/ui/components/__tests__/jant-compose-dialog.test.ts +512 -0
  129. package/src/ui/components/__tests__/jant-compose-editor.test.ts +272 -0
  130. package/src/ui/components/__tests__/jant-post-form.test.ts +172 -0
  131. package/src/ui/components/__tests__/jant-settings-avatar.test.ts +235 -0
  132. package/src/ui/components/__tests__/jant-settings-general.test.ts +319 -0
  133. package/src/ui/components/collection-types.ts +45 -0
  134. package/src/ui/components/compose-types.ts +75 -0
  135. package/src/ui/components/jant-collection-form.ts +512 -0
  136. package/src/ui/components/jant-compose-dialog.ts +494 -0
  137. package/src/ui/components/jant-compose-editor.ts +799 -0
  138. package/src/ui/components/jant-post-form.ts +290 -0
  139. package/src/ui/components/jant-settings-avatar.ts +231 -0
  140. package/src/ui/components/jant-settings-general.ts +436 -0
  141. package/src/ui/components/post-form-template.ts +260 -0
  142. package/src/ui/components/post-form-types.ts +87 -0
  143. package/src/ui/components/settings-types.ts +62 -0
  144. package/src/ui/compose/ComposeDialog.tsx +141 -385
  145. package/src/ui/compose/ComposePrompt.tsx +3 -3
  146. package/src/ui/dash/PostList.tsx +55 -61
  147. package/src/ui/dash/appearance/AdvancedContent.tsx +80 -0
  148. package/src/ui/dash/appearance/AppearanceNav.tsx +56 -0
  149. package/src/ui/dash/appearance/ColorThemeContent.tsx +129 -0
  150. package/src/ui/dash/appearance/FontThemeContent.tsx +98 -0
  151. package/src/ui/dash/collections/CollectionForm.tsx +130 -117
  152. package/src/ui/dash/collections/CollectionsListContent.tsx +102 -41
  153. package/src/ui/dash/collections/IconPickerGrid.tsx +50 -0
  154. package/src/ui/dash/collections/ViewCollectionContent.tsx +14 -3
  155. package/src/ui/dash/index.ts +1 -1
  156. package/src/ui/dash/posts/PostForm.tsx +248 -0
  157. package/src/ui/dash/settings/AccountContent.tsx +69 -80
  158. package/src/ui/dash/settings/GeneralContent.tsx +159 -478
  159. package/src/ui/dash/settings/SettingsNav.tsx +4 -4
  160. package/src/ui/font-themes.ts +115 -32
  161. package/src/ui/layouts/BaseLayout.tsx +49 -19
  162. package/src/ui/layouts/DashLayout.tsx +14 -9
  163. package/src/ui/layouts/SiteLayout.tsx +38 -23
  164. package/src/ui/pages/CollectionPage.tsx +12 -2
  165. package/src/ui/pages/CollectionsPage.tsx +27 -27
  166. package/src/ui/pages/HomePage.tsx +15 -6
  167. package/src/ui/pages/SearchPage.tsx +1 -2
  168. package/src/ui/shared/CollectionsSidebar.tsx +59 -0
  169. package/src/ui/shared/Pagination.tsx +2 -2
  170. package/dist/app.js +0 -267
  171. package/dist/auth.js +0 -39
  172. package/dist/client.js +0 -13
  173. package/dist/db/index.js +0 -10
  174. package/dist/db/schema.js +0 -224
  175. package/dist/i18n/Trans.js +0 -24
  176. package/dist/i18n/context.js +0 -58
  177. package/dist/i18n/detect.js +0 -26
  178. package/dist/i18n/i18n.js +0 -49
  179. package/dist/i18n/index.js +0 -44
  180. package/dist/i18n/locales/en.js +0 -1
  181. package/dist/i18n/locales/zh-Hans.js +0 -1
  182. package/dist/i18n/locales/zh-Hant.js +0 -1
  183. package/dist/i18n/locales.js +0 -13
  184. package/dist/i18n/middleware.js +0 -30
  185. package/dist/lib/avatar-upload.js +0 -134
  186. package/dist/lib/config.js +0 -143
  187. package/dist/lib/constants.js +0 -50
  188. package/dist/lib/excerpt.js +0 -76
  189. package/dist/lib/favicon.js +0 -102
  190. package/dist/lib/feed.js +0 -123
  191. package/dist/lib/image-processor.js +0 -187
  192. package/dist/lib/image.js +0 -97
  193. package/dist/lib/index.js +0 -7
  194. package/dist/lib/markdown.js +0 -83
  195. package/dist/lib/media-helpers.js +0 -49
  196. package/dist/lib/media-upload.js +0 -104
  197. package/dist/lib/nav-reorder.js +0 -27
  198. package/dist/lib/navigation.js +0 -79
  199. package/dist/lib/pagination.js +0 -44
  200. package/dist/lib/render.js +0 -53
  201. package/dist/lib/schemas.js +0 -174
  202. package/dist/lib/sqid.js +0 -72
  203. package/dist/lib/sse.js +0 -218
  204. package/dist/lib/storage.js +0 -164
  205. package/dist/lib/theme.js +0 -65
  206. package/dist/lib/time.js +0 -159
  207. package/dist/lib/timeline.js +0 -95
  208. package/dist/lib/timezones.js +0 -388
  209. package/dist/lib/url.js +0 -89
  210. package/dist/lib/view.js +0 -217
  211. package/dist/middleware/auth.js +0 -52
  212. package/dist/middleware/onboarding.js +0 -41
  213. package/dist/routes/api/collections.js +0 -124
  214. package/dist/routes/api/nav-items.js +0 -104
  215. package/dist/routes/api/pages.js +0 -91
  216. package/dist/routes/api/posts.js +0 -218
  217. package/dist/routes/api/search.js +0 -48
  218. package/dist/routes/api/settings.js +0 -68
  219. package/dist/routes/api/upload.js +0 -246
  220. package/dist/routes/auth/reset.js +0 -221
  221. package/dist/routes/auth/setup.js +0 -194
  222. package/dist/routes/auth/signin.js +0 -176
  223. package/dist/routes/compose.js +0 -48
  224. package/dist/routes/dash/collections.js +0 -115
  225. package/dist/routes/dash/index.js +0 -118
  226. package/dist/routes/dash/media.js +0 -106
  227. package/dist/routes/dash/pages.js +0 -294
  228. package/dist/routes/dash/posts.js +0 -244
  229. package/dist/routes/dash/redirects.js +0 -257
  230. package/dist/routes/dash/settings.js +0 -379
  231. package/dist/routes/feed/rss.js +0 -62
  232. package/dist/routes/feed/sitemap.js +0 -49
  233. package/dist/routes/pages/archive.js +0 -62
  234. package/dist/routes/pages/collection.js +0 -34
  235. package/dist/routes/pages/collections.js +0 -28
  236. package/dist/routes/pages/featured.js +0 -36
  237. package/dist/routes/pages/home.js +0 -64
  238. package/dist/routes/pages/latest.js +0 -45
  239. package/dist/routes/pages/page.js +0 -68
  240. package/dist/routes/pages/post.js +0 -44
  241. package/dist/routes/pages/search.js +0 -54
  242. package/dist/services/collection.js +0 -109
  243. package/dist/services/index.js +0 -24
  244. package/dist/services/media.js +0 -117
  245. package/dist/services/navigation.js +0 -91
  246. package/dist/services/page.js +0 -84
  247. package/dist/services/post.js +0 -229
  248. package/dist/services/redirect.js +0 -48
  249. package/dist/services/search.js +0 -67
  250. package/dist/services/settings.js +0 -68
  251. package/dist/types/bindings.js +0 -3
  252. package/dist/types/config.js +0 -147
  253. package/dist/types/constants.js +0 -27
  254. package/dist/types/entities.js +0 -3
  255. package/dist/types/lingui-react-macro.d.js +0 -9
  256. package/dist/types/operations.js +0 -3
  257. package/dist/types/props.js +0 -3
  258. package/dist/types/sortablejs.d.js +0 -5
  259. package/dist/types/views.js +0 -5
  260. package/dist/types.js +0 -11
  261. package/dist/ui/color-themes.js +0 -268
  262. package/dist/ui/compose/ComposeDialog.js +0 -467
  263. package/dist/ui/compose/ComposePrompt.js +0 -55
  264. package/dist/ui/dash/ActionButtons.js +0 -46
  265. package/dist/ui/dash/CrudPageHeader.js +0 -22
  266. package/dist/ui/dash/DangerZone.js +0 -36
  267. package/dist/ui/dash/FormatBadge.js +0 -27
  268. package/dist/ui/dash/ListItemRow.js +0 -21
  269. package/dist/ui/dash/PageForm.js +0 -195
  270. package/dist/ui/dash/PostForm.js +0 -395
  271. package/dist/ui/dash/PostList.js +0 -83
  272. package/dist/ui/dash/StatusBadge.js +0 -46
  273. package/dist/ui/dash/collections/CollectionForm.js +0 -152
  274. package/dist/ui/dash/collections/CollectionsListContent.js +0 -68
  275. package/dist/ui/dash/collections/ViewCollectionContent.js +0 -96
  276. package/dist/ui/dash/index.js +0 -10
  277. package/dist/ui/dash/media/MediaListContent.js +0 -166
  278. package/dist/ui/dash/media/ViewMediaContent.js +0 -212
  279. package/dist/ui/dash/pages/LinkFormContent.js +0 -130
  280. package/dist/ui/dash/pages/UnifiedPagesContent.js +0 -193
  281. package/dist/ui/dash/settings/AccountContent.js +0 -209
  282. package/dist/ui/dash/settings/AppearanceContent.js +0 -259
  283. package/dist/ui/dash/settings/GeneralContent.js +0 -536
  284. package/dist/ui/dash/settings/SettingsNav.js +0 -41
  285. package/dist/ui/feed/LinkCard.js +0 -72
  286. package/dist/ui/feed/NoteCard.js +0 -58
  287. package/dist/ui/feed/QuoteCard.js +0 -63
  288. package/dist/ui/feed/ThreadPreview.js +0 -48
  289. package/dist/ui/feed/TimelineFeed.js +0 -41
  290. package/dist/ui/feed/TimelineItem.js +0 -27
  291. package/dist/ui/font-themes.js +0 -36
  292. package/dist/ui/layouts/BaseLayout.js +0 -153
  293. package/dist/ui/layouts/DashLayout.js +0 -141
  294. package/dist/ui/layouts/SiteLayout.js +0 -169
  295. package/dist/ui/pages/ArchivePage.js +0 -143
  296. package/dist/ui/pages/CollectionPage.js +0 -70
  297. package/dist/ui/pages/CollectionsPage.js +0 -76
  298. package/dist/ui/pages/FeaturedPage.js +0 -24
  299. package/dist/ui/pages/HomePage.js +0 -24
  300. package/dist/ui/pages/PostPage.js +0 -55
  301. package/dist/ui/pages/SearchPage.js +0 -122
  302. package/dist/ui/pages/SinglePage.js +0 -23
  303. package/dist/ui/shared/EmptyState.js +0 -27
  304. package/dist/ui/shared/MediaGallery.js +0 -35
  305. package/dist/ui/shared/Pagination.js +0 -195
  306. package/dist/ui/shared/ThreadView.js +0 -108
  307. package/dist/ui/shared/index.js +0 -5
  308. package/dist/vendor/datastar.js +0 -1606
  309. package/src/lib/__tests__/config.test.ts +0 -192
  310. package/src/lib/config.ts +0 -167
  311. package/src/routes/compose.ts +0 -63
  312. package/src/ui/dash/PostForm.tsx +0 -360
  313. package/src/ui/dash/settings/AppearanceContent.tsx +0 -254
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Post Form
3
+ *
4
+ * Server-rendered wrapper that feeds data/labels to `<jant-post-form>`.
5
+ * Provides SSR fallback skeleton while Lit hydrates.
6
+ */
7
+
8
+ import { useLingui } from "@lingui/react/macro";
9
+ import type { FC } from "hono/jsx";
10
+ import type { Post, Media, Collection } from "../../../types.js";
11
+ import {
12
+ getMediaUrl,
13
+ getImageUrl,
14
+ getPublicUrlForProvider,
15
+ } from "../../../lib/image.js";
16
+ import { renderCollectionIcon } from "../../../lib/icons.js";
17
+
18
+ export interface PostFormProps {
19
+ post?: Post;
20
+ action: string;
21
+ mediaAttachments?: Media[];
22
+ r2PublicUrl?: string;
23
+ imageTransformUrl?: string;
24
+ s3PublicUrl?: string;
25
+ collections?: Collection[];
26
+ postCollectionIds?: number[];
27
+ cancelHref?: string;
28
+ }
29
+
30
+ export const PostForm: FC<PostFormProps> = ({
31
+ post,
32
+ action,
33
+ mediaAttachments = [],
34
+ r2PublicUrl,
35
+ imageTransformUrl,
36
+ s3PublicUrl,
37
+ collections = [],
38
+ postCollectionIds = [],
39
+ cancelHref,
40
+ }) => {
41
+ const { t } = useLingui();
42
+ const isEdit = Boolean(post);
43
+
44
+ const labels = JSON.stringify({
45
+ formatLabel: t({
46
+ message: "Format",
47
+ comment: "@context: Post form field - post format",
48
+ }),
49
+ noteOption: t({
50
+ message: "Note",
51
+ comment: "@context: Post format option",
52
+ }),
53
+ linkOption: t({
54
+ message: "Link",
55
+ comment: "@context: Post format option",
56
+ }),
57
+ quoteOption: t({
58
+ message: "Quote",
59
+ comment: "@context: Post format option",
60
+ }),
61
+ titleLabel: t({
62
+ message: "Title (optional)",
63
+ comment: "@context: Post form field",
64
+ }),
65
+ titlePlaceholder: t({
66
+ message: "Post title...",
67
+ comment: "@context: Post title placeholder",
68
+ }),
69
+ bodyLabel: t({
70
+ message: "Content",
71
+ comment: "@context: Post form field",
72
+ }),
73
+ bodyPlaceholder: t({
74
+ message: "What's on your mind?",
75
+ comment: "@context: Post content placeholder",
76
+ }),
77
+ urlLabel: t({
78
+ message: "URL (optional)",
79
+ comment: "@context: Post form field - source URL",
80
+ }),
81
+ urlPlaceholder: "https://...",
82
+ quoteTextLabel: t({
83
+ message: "Quote Text",
84
+ comment: "@context: Post form field - quoted text",
85
+ }),
86
+ quoteTextPlaceholder: t({
87
+ message: "The text being quoted...",
88
+ comment: "@context: Quote text placeholder",
89
+ }),
90
+ mediaLabel: t({
91
+ message: "Media",
92
+ comment: "@context: Post form field - media attachments",
93
+ }),
94
+ mediaAddButton: t({
95
+ message: "Add Media",
96
+ comment: "@context: Button to open media picker",
97
+ }),
98
+ mediaRemoveButton: t({
99
+ message: "Remove",
100
+ comment: "@context: Remove media attachment button",
101
+ }),
102
+ mediaEmptyLabel: t({
103
+ message: "No media selected yet.",
104
+ comment: "@context: Post form media empty state",
105
+ }),
106
+ statusLabel: t({
107
+ message: "Status",
108
+ comment: "@context: Post form field",
109
+ }),
110
+ statusPublished: t({
111
+ message: "Published",
112
+ comment: "@context: Post status option",
113
+ }),
114
+ statusDraft: t({
115
+ message: "Draft",
116
+ comment: "@context: Post status option",
117
+ }),
118
+ featuredLabel: t({
119
+ message: "Featured",
120
+ comment: "@context: Post form checkbox - mark as featured",
121
+ }),
122
+ pinnedLabel: t({
123
+ message: "Pinned",
124
+ comment: "@context: Post form checkbox - pin to top",
125
+ }),
126
+ collectionsLabel: t({
127
+ message: "Collections (optional)",
128
+ comment: "@context: Post form field - assign to collections",
129
+ }),
130
+ submitLabel: isEdit
131
+ ? t({
132
+ message: "Update",
133
+ comment: "@context: Button to update existing post",
134
+ })
135
+ : t({
136
+ message: "Publish",
137
+ comment: "@context: Button to publish new post",
138
+ }),
139
+ cancelLabel: t({
140
+ message: "Cancel",
141
+ comment: "@context: Button to cancel form",
142
+ }),
143
+ mediaDialogTitle: t({
144
+ message: "Select Media",
145
+ comment: "@context: Media picker dialog title",
146
+ }),
147
+ mediaDialogDone: t({
148
+ message: "Done",
149
+ comment: "@context: Close media picker button",
150
+ }),
151
+ mediaDialogLoading: t({
152
+ message: "Loading...",
153
+ comment: "@context: Loading state for media picker",
154
+ }),
155
+ submitSuccessMessage: isEdit
156
+ ? t({
157
+ message: "Post updated successfully.",
158
+ comment: "@context: Toast after editing post",
159
+ })
160
+ : t({
161
+ message: "Post published successfully.",
162
+ comment: "@context: Toast after creating post",
163
+ }),
164
+ submitErrorMessage: t({
165
+ message: "Failed to save post. Please try again.",
166
+ comment: "@context: Toast when post save fails",
167
+ }),
168
+ }).replace(/</g, "\\u003c");
169
+
170
+ const initial = JSON.stringify({
171
+ format: post?.format ?? "note",
172
+ title: post?.title ?? "",
173
+ body: post?.body ?? "",
174
+ url: post?.url ?? "",
175
+ quoteText: post?.quoteText ?? "",
176
+ status: post?.status ?? "published",
177
+ featured: post?.featured === 1,
178
+ pinned: post?.pinned === 1,
179
+ rating: post?.rating ?? 0,
180
+ collectionIds: postCollectionIds,
181
+ mediaIds: mediaAttachments.map((m) => m.id),
182
+ }).replace(/</g, "\\u003c");
183
+
184
+ const media = JSON.stringify(
185
+ mediaAttachments.map((m) => {
186
+ const pUrl = getPublicUrlForProvider(
187
+ m.provider,
188
+ r2PublicUrl,
189
+ s3PublicUrl,
190
+ );
191
+ const mediaUrl = getMediaUrl(m.storageKey, pUrl);
192
+ const thumbUrl = getImageUrl(mediaUrl, imageTransformUrl, {
193
+ width: 150,
194
+ quality: 80,
195
+ format: "auto",
196
+ fit: "cover",
197
+ });
198
+ return {
199
+ id: m.id,
200
+ thumbUrl,
201
+ alt: m.alt || m.originalName,
202
+ };
203
+ }),
204
+ ).replace(/</g, "\\u003c");
205
+
206
+ const collectionOptions = JSON.stringify(
207
+ collections.map((col) => ({
208
+ id: col.id,
209
+ title: col.title,
210
+ icon: col.icon,
211
+ iconHtml: renderCollectionIcon(col.icon, { size: 18 }),
212
+ })),
213
+ ).replace(/</g, "\\u003c");
214
+
215
+ const cancel = cancelHref ?? "/dash/posts";
216
+
217
+ return (
218
+ <jant-post-form
219
+ labels={labels}
220
+ initial={initial}
221
+ action={action}
222
+ cancel-href={cancel}
223
+ media={media}
224
+ collections={collectionOptions}
225
+ media-picker-url="/dash/media/picker"
226
+ is-edit={isEdit ? "true" : undefined}
227
+ >
228
+ <div class="flex flex-col gap-4 max-w-2xl">
229
+ <div class="field">
230
+ <div class="label skel-label"></div>
231
+ <div class="input skel-input"></div>
232
+ </div>
233
+ <div class="field">
234
+ <div class="label skel-label"></div>
235
+ <div class="textarea skel-textarea"></div>
236
+ </div>
237
+ <div class="field">
238
+ <div class="label skel-label"></div>
239
+ <div class="input skel-input"></div>
240
+ </div>
241
+ <div class="flex gap-2">
242
+ <div class="btn skel-input min-w-24"></div>
243
+ <div class="btn-outline skel-input min-w-20"></div>
244
+ </div>
245
+ </div>
246
+ </jant-post-form>
247
+ );
248
+ };
@@ -17,37 +17,28 @@ export function AccountContent({ userName }: { userName: string }) {
17
17
  </h1>
18
18
  <SettingsNav currentTab="account" />
19
19
 
20
- <div class="flex flex-col gap-6 max-w-lg">
20
+ <div class="flex flex-col max-w-lg">
21
21
  <form
22
22
  data-signals={profileSignals}
23
23
  data-on:submit__prevent="@post('/dash/settings/account')"
24
24
  data-indicator="_profileLoading"
25
25
  >
26
- <div class="card">
27
- <header>
28
- <h2>
26
+ <h2 class="text-lg font-semibold mb-4">
27
+ {t({
28
+ message: "Profile",
29
+ comment: "@context: Account settings section heading",
30
+ })}
31
+ </h2>
32
+ <div class="flex flex-col gap-4">
33
+ <div class="field">
34
+ <label class="label">
29
35
  {t({
30
- message: "Profile",
31
- comment: "@context: Account settings section heading",
36
+ message: "Name",
37
+ comment: "@context: Account settings form field",
32
38
  })}
33
- </h2>
34
- </header>
35
- <section class="flex flex-col gap-4">
36
- <div class="field">
37
- <label class="label">
38
- {t({
39
- message: "Name",
40
- comment: "@context: Account settings form field",
41
- })}
42
- </label>
43
- <input
44
- type="text"
45
- data-bind="userName"
46
- class="input"
47
- required
48
- />
49
- </div>
50
- </section>
39
+ </label>
40
+ <input type="text" data-bind="userName" class="input" required />
41
+ </div>
51
42
  </div>
52
43
 
53
44
  <button
@@ -77,71 +68,69 @@ export function AccountContent({ userName }: { userName: string }) {
77
68
  </button>
78
69
  </form>
79
70
 
71
+ <hr class="my-8" />
72
+
80
73
  <form
81
74
  data-signals="{currentPassword: '', newPassword: '', confirmPassword: ''}"
82
75
  data-on:submit__prevent="@post('/dash/settings/password')"
83
76
  data-indicator="_passwordLoading"
84
77
  >
85
- <div class="card">
86
- <header>
87
- <h2>
78
+ <h2 class="text-lg font-semibold mb-4">
79
+ {t({
80
+ message: "Change Password",
81
+ comment: "@context: Settings section heading",
82
+ })}
83
+ </h2>
84
+ <div class="flex flex-col gap-4">
85
+ <div class="field">
86
+ <label class="label">
88
87
  {t({
89
- message: "Change Password",
90
- comment: "@context: Settings section heading",
88
+ message: "Current Password",
89
+ comment: "@context: Password form field",
91
90
  })}
92
- </h2>
93
- </header>
94
- <section class="flex flex-col gap-4">
95
- <div class="field">
96
- <label class="label">
97
- {t({
98
- message: "Current Password",
99
- comment: "@context: Password form field",
100
- })}
101
- </label>
102
- <input
103
- type="password"
104
- data-bind="currentPassword"
105
- class="input"
106
- required
107
- autocomplete="current-password"
108
- />
109
- </div>
91
+ </label>
92
+ <input
93
+ type="password"
94
+ data-bind="currentPassword"
95
+ class="input"
96
+ required
97
+ autocomplete="current-password"
98
+ />
99
+ </div>
110
100
 
111
- <div class="field">
112
- <label class="label">
113
- {t({
114
- message: "New Password",
115
- comment: "@context: Password form field",
116
- })}
117
- </label>
118
- <input
119
- type="password"
120
- data-bind="newPassword"
121
- class="input"
122
- required
123
- minlength={8}
124
- autocomplete="new-password"
125
- />
126
- </div>
101
+ <div class="field">
102
+ <label class="label">
103
+ {t({
104
+ message: "New Password",
105
+ comment: "@context: Password form field",
106
+ })}
107
+ </label>
108
+ <input
109
+ type="password"
110
+ data-bind="newPassword"
111
+ class="input"
112
+ required
113
+ minlength={8}
114
+ autocomplete="new-password"
115
+ />
116
+ </div>
127
117
 
128
- <div class="field">
129
- <label class="label">
130
- {t({
131
- message: "Confirm New Password",
132
- comment: "@context: Password form field",
133
- })}
134
- </label>
135
- <input
136
- type="password"
137
- data-bind="confirmPassword"
138
- class="input"
139
- required
140
- minlength={8}
141
- autocomplete="new-password"
142
- />
143
- </div>
144
- </section>
118
+ <div class="field">
119
+ <label class="label">
120
+ {t({
121
+ message: "Confirm New Password",
122
+ comment: "@context: Password form field",
123
+ })}
124
+ </label>
125
+ <input
126
+ type="password"
127
+ data-bind="confirmPassword"
128
+ class="input"
129
+ required
130
+ minlength={8}
131
+ autocomplete="new-password"
132
+ />
133
+ </div>
145
134
  </div>
146
135
 
147
136
  <button