@jant/core 0.3.27 → 0.3.29

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 (314) hide show
  1. package/bin/reset-password.js +22 -0
  2. package/dist/client/client.css +1 -0
  3. package/dist/client/client.js +31561 -0
  4. package/dist/index.js +15209 -15
  5. package/package.json +25 -15
  6. package/src/__tests__/helpers/app.ts +19 -3
  7. package/src/__tests__/helpers/db.ts +44 -0
  8. package/src/__tests__/helpers/lingui-core-macro-mock.ts +33 -0
  9. package/src/app.tsx +111 -174
  10. package/src/client.ts +13 -0
  11. package/src/db/migrations/0007_post_collections_m2m.sql +94 -0
  12. package/src/db/migrations/0008_add_collection_dividers.sql +8 -0
  13. package/src/db/migrations/0009_drop_collection_show_divider.sql +2 -0
  14. package/src/db/migrations/0010_add_performance_indexes.sql +16 -0
  15. package/src/db/schema.ts +24 -4
  16. package/src/i18n/locales/en.po +810 -385
  17. package/src/i18n/locales/en.ts +1 -1
  18. package/src/i18n/locales/zh-Hans.po +733 -522
  19. package/src/i18n/locales/zh-Hans.ts +1 -1
  20. package/src/i18n/locales/zh-Hant.po +733 -522
  21. package/src/i18n/locales/zh-Hant.ts +1 -1
  22. package/src/i18n/middleware.ts +7 -11
  23. package/src/index.ts +1 -1
  24. package/src/lib/__tests__/icons.test.ts +178 -0
  25. package/src/lib/__tests__/resolve-config.test.ts +184 -0
  26. package/src/lib/__tests__/schemas.test.ts +12 -6
  27. package/src/lib/__tests__/theme.test.ts +62 -0
  28. package/src/lib/__tests__/timezones.test.ts +1 -1
  29. package/src/lib/__tests__/url.test.ts +12 -0
  30. package/src/lib/__tests__/view.test.ts +1 -5
  31. package/src/lib/avatar-upload.ts +18 -10
  32. package/src/lib/collection-form-bridge.ts +52 -0
  33. package/src/lib/collections-reorder.ts +28 -0
  34. package/src/lib/compose-bridge.ts +251 -0
  35. package/src/lib/errors.ts +116 -0
  36. package/src/lib/excerpt.ts +1 -1
  37. package/src/lib/favicon.ts +3 -5
  38. package/src/lib/html.ts +22 -0
  39. package/src/lib/icon-catalog.ts +181 -0
  40. package/src/lib/icons.ts +202 -0
  41. package/src/lib/navigation.ts +18 -33
  42. package/src/lib/pagination.ts +3 -2
  43. package/src/lib/post-form-bridge.ts +136 -0
  44. package/src/lib/render.tsx +11 -4
  45. package/src/lib/resolve-config.ts +157 -0
  46. package/src/lib/schemas.ts +76 -12
  47. package/src/lib/settings-bridge.ts +139 -0
  48. package/src/lib/storage.ts +37 -16
  49. package/src/lib/theme.ts +5 -7
  50. package/src/lib/timeline.ts +4 -8
  51. package/src/lib/toast.ts +134 -0
  52. package/src/lib/upload.ts +71 -0
  53. package/src/lib/url.ts +9 -1
  54. package/src/lib/version.ts +16 -0
  55. package/src/lib/view.ts +9 -10
  56. package/src/middleware/__tests__/auth.test.ts +6 -28
  57. package/src/middleware/__tests__/onboarding.test.ts +1 -1
  58. package/src/middleware/auth.ts +6 -12
  59. package/src/middleware/config.ts +51 -0
  60. package/src/middleware/error-handler.ts +56 -0
  61. package/src/middleware/onboarding.ts +1 -1
  62. package/src/preset.css +6 -0
  63. package/src/routes/__tests__/compose.test.ts +104 -17
  64. package/src/routes/api/__tests__/collections.test.ts +93 -2
  65. package/src/routes/api/__tests__/posts.test.ts +2 -1
  66. package/src/routes/api/__tests__/settings.test.ts +1 -1
  67. package/src/routes/api/collections.ts +64 -68
  68. package/src/routes/api/nav-items.ts +21 -59
  69. package/src/routes/api/pages.ts +18 -46
  70. package/src/routes/api/posts.ts +64 -86
  71. package/src/routes/api/search.ts +6 -4
  72. package/src/routes/api/settings.ts +8 -24
  73. package/src/routes/api/upload.ts +55 -53
  74. package/src/routes/auth/__tests__/setup.test.ts +118 -0
  75. package/src/routes/auth/reset.tsx +17 -66
  76. package/src/routes/auth/setup.tsx +67 -11
  77. package/src/routes/auth/signin.tsx +44 -8
  78. package/src/routes/compose.tsx +194 -0
  79. package/src/routes/dash/__tests__/font-theme.test.ts +110 -0
  80. package/src/routes/dash/__tests__/pages.test.ts +2 -2
  81. package/src/routes/dash/__tests__/settings-avatar.test.ts +23 -12
  82. package/src/routes/dash/appearance.tsx +173 -0
  83. package/src/routes/dash/collections.tsx +80 -14
  84. package/src/routes/dash/index.tsx +12 -14
  85. package/src/routes/dash/media.tsx +46 -49
  86. package/src/routes/dash/pages.tsx +85 -37
  87. package/src/routes/dash/posts.tsx +60 -23
  88. package/src/routes/dash/redirects.tsx +43 -33
  89. package/src/routes/dash/settings.tsx +234 -214
  90. package/src/routes/feed/__tests__/rss.test.ts +7 -3
  91. package/src/routes/feed/rss.ts +11 -16
  92. package/src/routes/feed/sitemap.ts +15 -9
  93. package/src/routes/pages/__tests__/collections.test.ts +9 -8
  94. package/src/routes/pages/archive.tsx +2 -2
  95. package/src/routes/pages/collection.tsx +76 -9
  96. package/src/routes/pages/collections.tsx +3 -1
  97. package/src/routes/pages/featured.tsx +2 -2
  98. package/src/routes/pages/home.tsx +3 -3
  99. package/src/routes/pages/latest.tsx +2 -2
  100. package/src/routes/pages/page.tsx +2 -2
  101. package/src/routes/pages/post.tsx +2 -2
  102. package/src/routes/pages/search.tsx +2 -2
  103. package/src/services/__tests__/collection.test.ts +324 -34
  104. package/src/services/__tests__/media.test.ts +1 -1
  105. package/src/services/__tests__/page.test.ts +116 -1
  106. package/src/services/auth.ts +88 -0
  107. package/src/services/collection.ts +169 -30
  108. package/src/services/index.ts +8 -3
  109. package/src/services/media.ts +39 -12
  110. package/src/services/navigation.ts +17 -5
  111. package/src/services/page.ts +24 -4
  112. package/src/services/post.ts +87 -19
  113. package/src/services/search.ts +0 -1
  114. package/src/services/settings.ts +21 -13
  115. package/src/style.css +3 -0
  116. package/src/styles/components.css +42 -1
  117. package/src/styles/tokens.css +4 -0
  118. package/src/styles/ui.css +902 -73
  119. package/src/types/app-context.ts +25 -0
  120. package/src/types/bindings.ts +1 -0
  121. package/src/types/config.ts +60 -23
  122. package/src/types/entities.ts +12 -2
  123. package/src/types/lingui-react-macro.d.ts +3 -3
  124. package/src/types/operations.ts +2 -4
  125. package/src/types/views.ts +1 -3
  126. package/src/ui/__tests__/font-themes.test.ts +27 -8
  127. package/src/ui/color-themes.ts +1 -1
  128. package/src/ui/components/__tests__/jant-collection-form.test.ts +153 -0
  129. package/src/ui/components/__tests__/jant-compose-dialog.test.ts +512 -0
  130. package/src/ui/components/__tests__/jant-compose-editor.test.ts +272 -0
  131. package/src/ui/components/__tests__/jant-post-form.test.ts +172 -0
  132. package/src/ui/components/__tests__/jant-settings-avatar.test.ts +235 -0
  133. package/src/ui/components/__tests__/jant-settings-general.test.ts +319 -0
  134. package/src/ui/components/collection-types.ts +45 -0
  135. package/src/ui/components/compose-types.ts +75 -0
  136. package/src/ui/components/jant-collection-form.ts +512 -0
  137. package/src/ui/components/jant-compose-dialog.ts +494 -0
  138. package/src/ui/components/jant-compose-editor.ts +799 -0
  139. package/src/ui/components/jant-post-form.ts +290 -0
  140. package/src/ui/components/jant-settings-avatar.ts +231 -0
  141. package/src/ui/components/jant-settings-general.ts +436 -0
  142. package/src/ui/components/post-form-template.ts +260 -0
  143. package/src/ui/components/post-form-types.ts +87 -0
  144. package/src/ui/components/settings-types.ts +62 -0
  145. package/src/ui/compose/ComposeDialog.tsx +141 -385
  146. package/src/ui/compose/ComposePrompt.tsx +3 -3
  147. package/src/ui/dash/PostList.tsx +55 -61
  148. package/src/ui/dash/appearance/AdvancedContent.tsx +80 -0
  149. package/src/ui/dash/appearance/AppearanceNav.tsx +56 -0
  150. package/src/ui/dash/appearance/ColorThemeContent.tsx +129 -0
  151. package/src/ui/dash/appearance/FontThemeContent.tsx +98 -0
  152. package/src/ui/dash/collections/CollectionForm.tsx +130 -117
  153. package/src/ui/dash/collections/CollectionsListContent.tsx +102 -41
  154. package/src/ui/dash/collections/IconPickerGrid.tsx +50 -0
  155. package/src/ui/dash/collections/ViewCollectionContent.tsx +14 -3
  156. package/src/ui/dash/index.ts +1 -1
  157. package/src/ui/dash/posts/PostForm.tsx +248 -0
  158. package/src/ui/dash/settings/AccountContent.tsx +69 -80
  159. package/src/ui/dash/settings/GeneralContent.tsx +159 -478
  160. package/src/ui/dash/settings/SettingsNav.tsx +4 -4
  161. package/src/ui/font-themes.ts +115 -32
  162. package/src/ui/layouts/BaseLayout.tsx +49 -19
  163. package/src/ui/layouts/DashLayout.tsx +14 -9
  164. package/src/ui/layouts/SiteLayout.tsx +38 -23
  165. package/src/ui/pages/CollectionPage.tsx +12 -2
  166. package/src/ui/pages/CollectionsPage.tsx +27 -27
  167. package/src/ui/pages/HomePage.tsx +15 -6
  168. package/src/ui/pages/SearchPage.tsx +1 -2
  169. package/src/ui/shared/CollectionsSidebar.tsx +59 -0
  170. package/src/ui/shared/Pagination.tsx +2 -2
  171. package/dist/app.js +0 -267
  172. package/dist/auth.js +0 -39
  173. package/dist/client.js +0 -13
  174. package/dist/db/index.js +0 -10
  175. package/dist/db/schema.js +0 -224
  176. package/dist/i18n/Trans.js +0 -24
  177. package/dist/i18n/context.js +0 -58
  178. package/dist/i18n/detect.js +0 -26
  179. package/dist/i18n/i18n.js +0 -49
  180. package/dist/i18n/index.js +0 -44
  181. package/dist/i18n/locales/en.js +0 -1
  182. package/dist/i18n/locales/zh-Hans.js +0 -1
  183. package/dist/i18n/locales/zh-Hant.js +0 -1
  184. package/dist/i18n/locales.js +0 -13
  185. package/dist/i18n/middleware.js +0 -30
  186. package/dist/lib/avatar-upload.js +0 -134
  187. package/dist/lib/config.js +0 -143
  188. package/dist/lib/constants.js +0 -50
  189. package/dist/lib/excerpt.js +0 -76
  190. package/dist/lib/favicon.js +0 -102
  191. package/dist/lib/feed.js +0 -123
  192. package/dist/lib/image-processor.js +0 -187
  193. package/dist/lib/image.js +0 -97
  194. package/dist/lib/index.js +0 -7
  195. package/dist/lib/markdown.js +0 -83
  196. package/dist/lib/media-helpers.js +0 -49
  197. package/dist/lib/media-upload.js +0 -104
  198. package/dist/lib/nav-reorder.js +0 -27
  199. package/dist/lib/navigation.js +0 -79
  200. package/dist/lib/pagination.js +0 -44
  201. package/dist/lib/render.js +0 -53
  202. package/dist/lib/schemas.js +0 -174
  203. package/dist/lib/sqid.js +0 -72
  204. package/dist/lib/sse.js +0 -218
  205. package/dist/lib/storage.js +0 -164
  206. package/dist/lib/theme.js +0 -65
  207. package/dist/lib/time.js +0 -159
  208. package/dist/lib/timeline.js +0 -95
  209. package/dist/lib/timezones.js +0 -388
  210. package/dist/lib/url.js +0 -89
  211. package/dist/lib/view.js +0 -217
  212. package/dist/middleware/auth.js +0 -52
  213. package/dist/middleware/onboarding.js +0 -41
  214. package/dist/routes/api/collections.js +0 -124
  215. package/dist/routes/api/nav-items.js +0 -104
  216. package/dist/routes/api/pages.js +0 -91
  217. package/dist/routes/api/posts.js +0 -218
  218. package/dist/routes/api/search.js +0 -48
  219. package/dist/routes/api/settings.js +0 -68
  220. package/dist/routes/api/upload.js +0 -246
  221. package/dist/routes/auth/reset.js +0 -221
  222. package/dist/routes/auth/setup.js +0 -194
  223. package/dist/routes/auth/signin.js +0 -176
  224. package/dist/routes/compose.js +0 -48
  225. package/dist/routes/dash/collections.js +0 -115
  226. package/dist/routes/dash/index.js +0 -118
  227. package/dist/routes/dash/media.js +0 -106
  228. package/dist/routes/dash/pages.js +0 -294
  229. package/dist/routes/dash/posts.js +0 -244
  230. package/dist/routes/dash/redirects.js +0 -257
  231. package/dist/routes/dash/settings.js +0 -379
  232. package/dist/routes/feed/rss.js +0 -62
  233. package/dist/routes/feed/sitemap.js +0 -49
  234. package/dist/routes/pages/archive.js +0 -62
  235. package/dist/routes/pages/collection.js +0 -34
  236. package/dist/routes/pages/collections.js +0 -28
  237. package/dist/routes/pages/featured.js +0 -36
  238. package/dist/routes/pages/home.js +0 -64
  239. package/dist/routes/pages/latest.js +0 -45
  240. package/dist/routes/pages/page.js +0 -68
  241. package/dist/routes/pages/post.js +0 -44
  242. package/dist/routes/pages/search.js +0 -54
  243. package/dist/services/collection.js +0 -109
  244. package/dist/services/index.js +0 -24
  245. package/dist/services/media.js +0 -117
  246. package/dist/services/navigation.js +0 -91
  247. package/dist/services/page.js +0 -84
  248. package/dist/services/post.js +0 -229
  249. package/dist/services/redirect.js +0 -48
  250. package/dist/services/search.js +0 -67
  251. package/dist/services/settings.js +0 -68
  252. package/dist/types/bindings.js +0 -3
  253. package/dist/types/config.js +0 -147
  254. package/dist/types/constants.js +0 -27
  255. package/dist/types/entities.js +0 -3
  256. package/dist/types/lingui-react-macro.d.js +0 -9
  257. package/dist/types/operations.js +0 -3
  258. package/dist/types/props.js +0 -3
  259. package/dist/types/sortablejs.d.js +0 -5
  260. package/dist/types/views.js +0 -5
  261. package/dist/types.js +0 -11
  262. package/dist/ui/color-themes.js +0 -268
  263. package/dist/ui/compose/ComposeDialog.js +0 -467
  264. package/dist/ui/compose/ComposePrompt.js +0 -55
  265. package/dist/ui/dash/ActionButtons.js +0 -46
  266. package/dist/ui/dash/CrudPageHeader.js +0 -22
  267. package/dist/ui/dash/DangerZone.js +0 -36
  268. package/dist/ui/dash/FormatBadge.js +0 -27
  269. package/dist/ui/dash/ListItemRow.js +0 -21
  270. package/dist/ui/dash/PageForm.js +0 -195
  271. package/dist/ui/dash/PostForm.js +0 -395
  272. package/dist/ui/dash/PostList.js +0 -83
  273. package/dist/ui/dash/StatusBadge.js +0 -46
  274. package/dist/ui/dash/collections/CollectionForm.js +0 -152
  275. package/dist/ui/dash/collections/CollectionsListContent.js +0 -68
  276. package/dist/ui/dash/collections/ViewCollectionContent.js +0 -96
  277. package/dist/ui/dash/index.js +0 -10
  278. package/dist/ui/dash/media/MediaListContent.js +0 -166
  279. package/dist/ui/dash/media/ViewMediaContent.js +0 -212
  280. package/dist/ui/dash/pages/LinkFormContent.js +0 -130
  281. package/dist/ui/dash/pages/UnifiedPagesContent.js +0 -193
  282. package/dist/ui/dash/settings/AccountContent.js +0 -209
  283. package/dist/ui/dash/settings/AppearanceContent.js +0 -259
  284. package/dist/ui/dash/settings/GeneralContent.js +0 -536
  285. package/dist/ui/dash/settings/SettingsNav.js +0 -41
  286. package/dist/ui/feed/LinkCard.js +0 -72
  287. package/dist/ui/feed/NoteCard.js +0 -58
  288. package/dist/ui/feed/QuoteCard.js +0 -63
  289. package/dist/ui/feed/ThreadPreview.js +0 -48
  290. package/dist/ui/feed/TimelineFeed.js +0 -41
  291. package/dist/ui/feed/TimelineItem.js +0 -27
  292. package/dist/ui/font-themes.js +0 -36
  293. package/dist/ui/layouts/BaseLayout.js +0 -153
  294. package/dist/ui/layouts/DashLayout.js +0 -141
  295. package/dist/ui/layouts/SiteLayout.js +0 -169
  296. package/dist/ui/pages/ArchivePage.js +0 -143
  297. package/dist/ui/pages/CollectionPage.js +0 -70
  298. package/dist/ui/pages/CollectionsPage.js +0 -76
  299. package/dist/ui/pages/FeaturedPage.js +0 -24
  300. package/dist/ui/pages/HomePage.js +0 -24
  301. package/dist/ui/pages/PostPage.js +0 -55
  302. package/dist/ui/pages/SearchPage.js +0 -122
  303. package/dist/ui/pages/SinglePage.js +0 -23
  304. package/dist/ui/shared/EmptyState.js +0 -27
  305. package/dist/ui/shared/MediaGallery.js +0 -35
  306. package/dist/ui/shared/Pagination.js +0 -195
  307. package/dist/ui/shared/ThreadView.js +0 -108
  308. package/dist/ui/shared/index.js +0 -5
  309. package/dist/vendor/datastar.js +0 -1606
  310. package/src/lib/__tests__/config.test.ts +0 -192
  311. package/src/lib/config.ts +0 -167
  312. package/src/routes/compose.ts +0 -63
  313. package/src/ui/dash/PostForm.tsx +0 -360
  314. 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