@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.
Files changed (314) 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 +112 -173
  9. package/src/auth.ts +4 -1
  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 -265
  172. package/dist/auth.js +0 -36
  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
@@ -1,115 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
2
- /**
3
- * Dashboard Collections Routes
4
- */ import { Hono } from "hono";
5
- import { DashLayout } from "../../ui/layouts/DashLayout.js";
6
- import { DangerZone } from "../../ui/dash/index.js";
7
- import { dsRedirect } from "../../lib/sse.js";
8
- import { getSiteName } from "../../lib/config.js";
9
- import { createMediaContext, toPostViewsFromPosts } from "../../lib/view.js";
10
- import { CollectionsListContent } from "../../ui/dash/collections/CollectionsListContent.js";
11
- import { CollectionForm } from "../../ui/dash/collections/CollectionForm.js";
12
- import { ViewCollectionContent } from "../../ui/dash/collections/ViewCollectionContent.js";
13
- export const collectionsRoutes = new Hono();
14
- // List collections
15
- collectionsRoutes.get("/", async (c)=>{
16
- const siteName = await getSiteName(c);
17
- const collections = await c.var.services.collections.list();
18
- return c.html(/*#__PURE__*/ _jsx(DashLayout, {
19
- c: c,
20
- title: "Collections",
21
- siteName: siteName,
22
- currentPath: "/dash/collections",
23
- children: /*#__PURE__*/ _jsx(CollectionsListContent, {
24
- collections: collections
25
- })
26
- }));
27
- });
28
- // New collection form
29
- collectionsRoutes.get("/new", async (c)=>{
30
- const siteName = await getSiteName(c);
31
- return c.html(/*#__PURE__*/ _jsx(DashLayout, {
32
- c: c,
33
- title: "New Collection",
34
- siteName: siteName,
35
- currentPath: "/dash/collections",
36
- children: /*#__PURE__*/ _jsx(CollectionForm, {})
37
- }));
38
- });
39
- // Create collection
40
- collectionsRoutes.post("/", async (c)=>{
41
- const body = await c.req.json();
42
- const collection = await c.var.services.collections.create({
43
- title: body.title,
44
- slug: body.slug,
45
- description: body.description || undefined
46
- });
47
- return dsRedirect(`/dash/collections/${collection.id}`);
48
- });
49
- // View single collection
50
- collectionsRoutes.get("/:id", async (c)=>{
51
- const id = parseInt(c.req.param("id"), 10);
52
- if (isNaN(id)) return c.notFound();
53
- const collection = await c.var.services.collections.getById(id);
54
- if (!collection) return c.notFound();
55
- const rawPosts = await c.var.services.posts.list({
56
- collectionId: id
57
- });
58
- const ctx = createMediaContext(c);
59
- const posts = toPostViewsFromPosts(rawPosts, ctx);
60
- const siteName = await getSiteName(c);
61
- return c.html(/*#__PURE__*/ _jsx(DashLayout, {
62
- c: c,
63
- title: collection.title,
64
- siteName: siteName,
65
- currentPath: "/dash/collections",
66
- children: /*#__PURE__*/ _jsx(ViewCollectionContent, {
67
- collection: collection,
68
- posts: posts
69
- })
70
- }));
71
- });
72
- // Edit collection form
73
- collectionsRoutes.get("/:id/edit", async (c)=>{
74
- const id = parseInt(c.req.param("id"), 10);
75
- if (isNaN(id)) return c.notFound();
76
- const collection = await c.var.services.collections.getById(id);
77
- if (!collection) return c.notFound();
78
- const siteName = await getSiteName(c);
79
- return c.html(/*#__PURE__*/ _jsxs(DashLayout, {
80
- c: c,
81
- title: `Edit: ${collection.title}`,
82
- siteName: siteName,
83
- currentPath: "/dash/collections",
84
- children: [
85
- /*#__PURE__*/ _jsx(CollectionForm, {
86
- collection: collection,
87
- isEdit: true
88
- }),
89
- /*#__PURE__*/ _jsx(DangerZone, {
90
- actionLabel: "Delete Collection",
91
- formAction: `/dash/collections/${collection.id}/delete`,
92
- confirmMessage: "Are you sure you want to delete this collection?"
93
- })
94
- ]
95
- }));
96
- });
97
- // Update collection
98
- collectionsRoutes.post("/:id", async (c)=>{
99
- const id = parseInt(c.req.param("id"), 10);
100
- if (isNaN(id)) return c.notFound();
101
- const body = await c.req.json();
102
- await c.var.services.collections.update(id, {
103
- title: body.title,
104
- slug: body.slug,
105
- description: body.description || undefined
106
- });
107
- return dsRedirect(`/dash/collections/${id}`);
108
- });
109
- // Delete collection
110
- collectionsRoutes.post("/:id/delete", async (c)=>{
111
- const id = parseInt(c.req.param("id"), 10);
112
- if (isNaN(id)) return c.notFound();
113
- await c.var.services.collections.delete(id);
114
- return dsRedirect("/dash/collections");
115
- });
@@ -1,118 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
2
- /**
3
- * Dashboard Index Route
4
- *
5
- * Example of using @lingui/react/macro with Hono JSX!
6
- */ import { Hono } from "hono";
7
- import { useLingui as $_useLingui } from "@jant/core/i18n";
8
- import { Trans as Trans_ } from "@jant/core/i18n";
9
- import { DashLayout } from "../../ui/layouts/DashLayout.js";
10
- import { getSiteName } from "../../lib/config.js";
11
- export const dashIndexRoutes = new Hono();
12
- /**
13
- * Dashboard content component
14
- * Uses useLingui() from @lingui/react/macro - works with Hono JSX!
15
- */ function DashboardContent({ publishedCount, draftCount }) {
16
- // 🎉 Single layer! Just like React!
17
- const { i18n: $__i18n, _: $__ } = $_useLingui();
18
- return /*#__PURE__*/ _jsxs("div", {
19
- class: "container py-8",
20
- children: [
21
- /*#__PURE__*/ _jsx("h1", {
22
- class: "text-2xl font-semibold mb-6",
23
- children: $__i18n._({
24
- id: "7p5kLi",
25
- message: "Dashboard"
26
- })
27
- }),
28
- /*#__PURE__*/ _jsxs("div", {
29
- class: "grid gap-4 md:grid-cols-3 mb-6",
30
- children: [
31
- /*#__PURE__*/ _jsxs("div", {
32
- class: "p-4 border rounded",
33
- children: [
34
- /*#__PURE__*/ _jsx("p", {
35
- class: "text-sm text-muted-foreground",
36
- children: $__i18n._({
37
- id: "u3wRF+",
38
- message: "Published"
39
- })
40
- }),
41
- /*#__PURE__*/ _jsx("p", {
42
- class: "text-3xl font-bold",
43
- children: publishedCount
44
- })
45
- ]
46
- }),
47
- /*#__PURE__*/ _jsxs("div", {
48
- class: "p-4 border rounded",
49
- children: [
50
- /*#__PURE__*/ _jsx("p", {
51
- class: "text-sm text-muted-foreground",
52
- children: $__i18n._({
53
- id: "M8kJqa",
54
- message: "Drafts"
55
- })
56
- }),
57
- /*#__PURE__*/ _jsx("p", {
58
- class: "text-3xl font-bold",
59
- children: draftCount
60
- })
61
- ]
62
- }),
63
- /*#__PURE__*/ _jsxs("div", {
64
- class: "p-4 border rounded",
65
- children: [
66
- /*#__PURE__*/ _jsx("p", {
67
- class: "text-sm text-muted-foreground mb-2",
68
- children: $__i18n._({
69
- id: "UDMjsP",
70
- message: "Quick Actions"
71
- })
72
- }),
73
- /*#__PURE__*/ _jsx("a", {
74
- href: "/dash/posts/new",
75
- class: "btn btn-primary w-full",
76
- children: $__i18n._({
77
- id: "FGrimz",
78
- message: "New Post"
79
- })
80
- })
81
- ]
82
- })
83
- ]
84
- }),
85
- /*#__PURE__*/ _jsx("p", {
86
- children: /*#__PURE__*/ _jsx(Trans_, {
87
- message: "Need help? Visit the <0>documentation</0>",
88
- id: "Jed1wB",
89
- components: {
90
- 0: /*#__PURE__*/ _jsx("a", {
91
- href: "/docs",
92
- class: "underline"
93
- })
94
- }
95
- })
96
- })
97
- ]
98
- });
99
- }
100
- dashIndexRoutes.get("/", async (c)=>{
101
- const siteName = await getSiteName(c);
102
- // Get some stats
103
- const allPosts = await c.var.services.posts.list({
104
- limit: 1000
105
- });
106
- const publishedPosts = allPosts.filter((p)=>p.status !== "draft");
107
- const draftPosts = allPosts.filter((p)=>p.status === "draft");
108
- return c.html(/*#__PURE__*/ _jsx(DashLayout, {
109
- c: c,
110
- title: "Dashboard",
111
- siteName: siteName,
112
- currentPath: "/dash",
113
- children: /*#__PURE__*/ _jsx(DashboardContent, {
114
- publishedCount: publishedPosts.length,
115
- draftCount: draftPosts.length
116
- })
117
- }));
118
- });
@@ -1,106 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
2
- /**
3
- * Dashboard Media Routes
4
- */ import { Hono } from "hono";
5
- import { DashLayout } from "../../ui/layouts/DashLayout.js";
6
- import { dsRedirect } from "../../lib/sse.js";
7
- import { getSiteName } from "../../lib/config.js";
8
- import { getMediaUrl, getImageUrl, getPublicUrlForProvider } from "../../lib/image.js";
9
- import { MediaListContent } from "../../ui/dash/media/MediaListContent.js";
10
- import { ViewMediaContent } from "../../ui/dash/media/ViewMediaContent.js";
11
- export const mediaRoutes = new Hono();
12
- // List media
13
- mediaRoutes.get("/", async (c)=>{
14
- const mediaList = await c.var.services.media.list(100);
15
- const siteName = await getSiteName(c);
16
- return c.html(/*#__PURE__*/ _jsx(DashLayout, {
17
- c: c,
18
- title: "Media",
19
- siteName: siteName,
20
- currentPath: "/dash/media",
21
- children: /*#__PURE__*/ _jsx(MediaListContent, {
22
- mediaList: mediaList,
23
- r2PublicUrl: c.env.R2_PUBLIC_URL,
24
- imageTransformUrl: c.env.IMAGE_TRANSFORM_URL,
25
- s3PublicUrl: c.env.S3_PUBLIC_URL
26
- })
27
- }));
28
- });
29
- // Media picker (returns HTML fragment for PostForm dialog)
30
- // Must be defined before /:id to avoid "picker" matching as an ID
31
- mediaRoutes.get("/picker", async (c)=>{
32
- const mediaList = await c.var.services.media.list(100);
33
- const r2PublicUrl = c.env.R2_PUBLIC_URL;
34
- const imageTransformUrl = c.env.IMAGE_TRANSFORM_URL;
35
- const s3PublicUrl = c.env.S3_PUBLIC_URL;
36
- if (mediaList.length === 0) {
37
- return c.html(/*#__PURE__*/ _jsx("p", {
38
- class: "text-muted-foreground text-sm col-span-4",
39
- children: "No media uploaded yet. Upload media from the Media page first."
40
- }));
41
- }
42
- return c.html(/*#__PURE__*/ _jsx(_Fragment, {
43
- children: mediaList.filter((m)=>m.mimeType.startsWith("image/")).map((m)=>{
44
- const pUrl = getPublicUrlForProvider(m.provider, r2PublicUrl, s3PublicUrl);
45
- const url = getMediaUrl(m.storageKey, pUrl);
46
- const thumbUrl = getImageUrl(url, imageTransformUrl, {
47
- width: 150,
48
- quality: 80,
49
- format: "auto",
50
- fit: "cover"
51
- });
52
- return /*#__PURE__*/ _jsx("button", {
53
- type: "button",
54
- class: "aspect-square rounded-lg overflow-hidden border-2 hover:border-primary cursor-pointer transition-colors",
55
- "data-on:click": `$mediaIds.includes('${m.id}') ? ($mediaIds = $mediaIds.filter(id => id !== '${m.id}')) : ($mediaIds = [...$mediaIds, '${m.id}'])`,
56
- "data-class:border-primary": `$mediaIds.includes('${m.id}')`,
57
- "data-class:ring-2": `$mediaIds.includes('${m.id}')`,
58
- "data-class:ring-primary": `$mediaIds.includes('${m.id}')`,
59
- children: /*#__PURE__*/ _jsx("img", {
60
- src: thumbUrl,
61
- alt: m.alt || m.originalName,
62
- class: "w-full h-full object-cover",
63
- loading: "lazy"
64
- })
65
- }, m.id);
66
- })
67
- }));
68
- });
69
- // View single media
70
- mediaRoutes.get("/:id", async (c)=>{
71
- const id = c.req.param("id");
72
- const media = await c.var.services.media.getById(id);
73
- if (!media) return c.notFound();
74
- const siteName = await getSiteName(c);
75
- return c.html(/*#__PURE__*/ _jsx(DashLayout, {
76
- c: c,
77
- title: media.originalName,
78
- siteName: siteName,
79
- currentPath: "/dash/media",
80
- children: /*#__PURE__*/ _jsx(ViewMediaContent, {
81
- media: media,
82
- r2PublicUrl: c.env.R2_PUBLIC_URL,
83
- imageTransformUrl: c.env.IMAGE_TRANSFORM_URL,
84
- s3PublicUrl: c.env.S3_PUBLIC_URL
85
- })
86
- }));
87
- });
88
- // Delete media
89
- mediaRoutes.post("/:id/delete", async (c)=>{
90
- const id = c.req.param("id");
91
- const media = await c.var.services.media.getById(id);
92
- if (!media) return c.notFound();
93
- // Delete from storage
94
- const storage = c.var.storage;
95
- if (storage) {
96
- try {
97
- await storage.delete(media.storageKey);
98
- } catch (err) {
99
- // eslint-disable-next-line no-console -- Error logging is intentional
100
- console.error("Storage delete error:", err);
101
- }
102
- }
103
- // Delete from database
104
- await c.var.services.media.delete(id);
105
- return dsRedirect("/dash/media");
106
- });
@@ -1,294 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
2
- /**
3
- * Dashboard Pages & Navigation Routes
4
- *
5
- * Unified management for pages and navigation items.
6
- */ import { Hono } from "hono";
7
- import { useLingui as $_useLingui } from "@jant/core/i18n";
8
- import { DashLayout } from "../../ui/layouts/DashLayout.js";
9
- import { PageForm, ActionButtons, DangerZone } from "../../ui/dash/index.js";
10
- import { dsRedirect, dsToast } from "../../lib/sse.js";
11
- import { getSiteName } from "../../lib/config.js";
12
- import { UnifiedPagesContent } from "../../ui/dash/pages/UnifiedPagesContent.js";
13
- import { LinkFormContent } from "../../ui/dash/pages/LinkFormContent.js";
14
- export const pagesRoutes = new Hono();
15
- // =============================================================================
16
- // Inline components (small, tightly coupled to route params)
17
- // =============================================================================
18
- function NewPageContent() {
19
- const { i18n: $__i18n, _: $__ } = $_useLingui();
20
- return /*#__PURE__*/ _jsxs(_Fragment, {
21
- children: [
22
- /*#__PURE__*/ _jsx("h1", {
23
- class: "text-2xl font-semibold mb-6",
24
- children: $__i18n._({
25
- id: "GrZ6fH",
26
- message: "New Page"
27
- })
28
- }),
29
- /*#__PURE__*/ _jsx(PageForm, {
30
- action: "/dash/pages"
31
- })
32
- ]
33
- });
34
- }
35
- function ViewPageContent({ page }) {
36
- const { i18n: $__i18n, _: $__ } = $_useLingui();
37
- return /*#__PURE__*/ _jsxs(_Fragment, {
38
- children: [
39
- /*#__PURE__*/ _jsxs("div", {
40
- class: "flex items-center justify-between mb-6",
41
- children: [
42
- /*#__PURE__*/ _jsxs("div", {
43
- children: [
44
- /*#__PURE__*/ _jsx("h1", {
45
- class: "text-2xl font-semibold",
46
- children: page.title || $__i18n._({
47
- id: "6WdDG7",
48
- message: "Page"
49
- })
50
- }),
51
- /*#__PURE__*/ _jsxs("p", {
52
- class: "text-muted-foreground mt-1",
53
- children: [
54
- "/",
55
- page.slug
56
- ]
57
- })
58
- ]
59
- }),
60
- /*#__PURE__*/ _jsx(ActionButtons, {
61
- editHref: `/dash/pages/${page.id}/edit`,
62
- editLabel: $__i18n._({
63
- id: "ePK91l",
64
- message: "Edit"
65
- }),
66
- viewHref: page.status !== "draft" ? `/${page.slug}` : undefined,
67
- viewLabel: $__i18n._({
68
- id: "jpctdh",
69
- message: "View"
70
- })
71
- })
72
- ]
73
- }),
74
- /*#__PURE__*/ _jsx("div", {
75
- class: "card",
76
- children: /*#__PURE__*/ _jsx("section", {
77
- children: /*#__PURE__*/ _jsx("div", {
78
- class: "prose",
79
- dangerouslySetInnerHTML: {
80
- __html: page.bodyHtml || ""
81
- }
82
- })
83
- })
84
- }),
85
- /*#__PURE__*/ _jsx(DangerZone, {
86
- actionLabel: $__i18n._({
87
- id: "4KzVT6",
88
- message: "Delete Page"
89
- }),
90
- formAction: `/dash/pages/${page.id}/delete`,
91
- confirmMessage: "Are you sure you want to delete this page?"
92
- })
93
- ]
94
- });
95
- }
96
- function EditPageContent({ page }) {
97
- const { i18n: $__i18n, _: $__ } = $_useLingui();
98
- return /*#__PURE__*/ _jsxs(_Fragment, {
99
- children: [
100
- /*#__PURE__*/ _jsx("h1", {
101
- class: "text-2xl font-semibold mb-6",
102
- children: $__i18n._({
103
- id: "U5v6Gh",
104
- message: "Edit Page"
105
- })
106
- }),
107
- /*#__PURE__*/ _jsx(PageForm, {
108
- page: page,
109
- action: `/dash/pages/${page.id}`
110
- })
111
- ]
112
- });
113
- }
114
- // =============================================================================
115
- // Route handlers
116
- // =============================================================================
117
- pagesRoutes.get("/", async (c)=>{
118
- const [navItems, otherPages] = await Promise.all([
119
- c.var.services.navItems.list(),
120
- c.var.services.pages.listNotInNav()
121
- ]);
122
- const siteName = await getSiteName(c);
123
- return c.html(/*#__PURE__*/ _jsx(DashLayout, {
124
- c: c,
125
- title: "Pages",
126
- siteName: siteName,
127
- currentPath: "/dash/pages",
128
- children: /*#__PURE__*/ _jsx(UnifiedPagesContent, {
129
- navItems: navItems,
130
- otherPages: otherPages
131
- })
132
- }));
133
- });
134
- pagesRoutes.get("/new", async (c)=>{
135
- const siteName = await getSiteName(c);
136
- return c.html(/*#__PURE__*/ _jsx(DashLayout, {
137
- c: c,
138
- title: "New Page",
139
- siteName: siteName,
140
- currentPath: "/dash/pages",
141
- children: /*#__PURE__*/ _jsx(NewPageContent, {})
142
- }));
143
- });
144
- pagesRoutes.get("/links/new", async (c)=>{
145
- const siteName = await getSiteName(c);
146
- return c.html(/*#__PURE__*/ _jsx(DashLayout, {
147
- c: c,
148
- title: "New Link",
149
- siteName: siteName,
150
- currentPath: "/dash/pages",
151
- children: /*#__PURE__*/ _jsx(LinkFormContent, {})
152
- }));
153
- });
154
- pagesRoutes.post("/links", async (c)=>{
155
- const body = await c.req.json();
156
- if (!body.label || !body.url) {
157
- return dsToast("Label and URL are required", "error");
158
- }
159
- await c.var.services.navItems.create({
160
- type: "link",
161
- label: body.label,
162
- url: body.url
163
- });
164
- return dsRedirect("/dash/pages");
165
- });
166
- pagesRoutes.post("/reorder", async (c)=>{
167
- const body = await c.req.json();
168
- if (!Array.isArray(body.ids)) {
169
- return dsToast("Invalid request", "error");
170
- }
171
- await c.var.services.navItems.reorder(body.ids);
172
- return dsToast("Order saved");
173
- });
174
- pagesRoutes.get("/links/:id/edit", async (c)=>{
175
- const id = parseInt(c.req.param("id"), 10);
176
- if (isNaN(id)) return c.notFound();
177
- const item = await c.var.services.navItems.getById(id);
178
- if (!item) return c.notFound();
179
- const siteName = await getSiteName(c);
180
- return c.html(/*#__PURE__*/ _jsx(DashLayout, {
181
- c: c,
182
- title: "Edit Link",
183
- siteName: siteName,
184
- currentPath: "/dash/pages",
185
- children: /*#__PURE__*/ _jsx(LinkFormContent, {
186
- item: item,
187
- isEdit: true
188
- })
189
- }));
190
- });
191
- pagesRoutes.post("/links/:id", async (c)=>{
192
- const id = parseInt(c.req.param("id"), 10);
193
- if (isNaN(id)) return c.notFound();
194
- const body = await c.req.json();
195
- if (!body.label || !body.url) {
196
- return dsToast("Label and URL are required", "error");
197
- }
198
- const updated = await c.var.services.navItems.update(id, {
199
- label: body.label,
200
- url: body.url
201
- });
202
- if (!updated) return c.notFound();
203
- return dsRedirect("/dash/pages");
204
- });
205
- pagesRoutes.post("/links/:id/delete", async (c)=>{
206
- const id = parseInt(c.req.param("id"), 10);
207
- if (!isNaN(id)) {
208
- await c.var.services.navItems.delete(id);
209
- }
210
- return dsRedirect("/dash/pages");
211
- });
212
- pagesRoutes.post("/", async (c)=>{
213
- const body = await c.req.json();
214
- const page = await c.var.services.pages.create({
215
- title: body.title,
216
- body: body.body,
217
- status: body.status,
218
- slug: body.slug.toLowerCase().replace(/[^a-z0-9-]/g, "-")
219
- });
220
- return dsRedirect(`/dash/pages/${page.id}`);
221
- });
222
- pagesRoutes.post("/:id/add-to-nav", async (c)=>{
223
- const id = parseInt(c.req.param("id"), 10);
224
- if (isNaN(id)) return c.notFound();
225
- const page = await c.var.services.pages.getById(id);
226
- if (!page) return c.notFound();
227
- await c.var.services.navItems.create({
228
- type: "page",
229
- label: page.title || page.slug,
230
- url: `/${page.slug}`,
231
- pageId: page.id
232
- });
233
- return dsRedirect("/dash/pages");
234
- });
235
- pagesRoutes.post("/:id/remove-from-nav", async (c)=>{
236
- const pageId = parseInt(c.req.param("id"), 10);
237
- if (isNaN(pageId)) return c.notFound();
238
- const navItems = await c.var.services.navItems.list();
239
- const navItem = navItems.find((item)=>item.pageId === pageId);
240
- if (navItem) {
241
- await c.var.services.navItems.delete(navItem.id);
242
- }
243
- return dsRedirect("/dash/pages");
244
- });
245
- pagesRoutes.get("/:id", async (c)=>{
246
- const id = parseInt(c.req.param("id"), 10);
247
- if (isNaN(id)) return c.notFound();
248
- const page = await c.var.services.pages.getById(id);
249
- if (!page) return c.notFound();
250
- const siteName = await getSiteName(c);
251
- return c.html(/*#__PURE__*/ _jsx(DashLayout, {
252
- c: c,
253
- title: page.title || "Page",
254
- siteName: siteName,
255
- currentPath: "/dash/pages",
256
- children: /*#__PURE__*/ _jsx(ViewPageContent, {
257
- page: page
258
- })
259
- }));
260
- });
261
- pagesRoutes.get("/:id/edit", async (c)=>{
262
- const id = parseInt(c.req.param("id"), 10);
263
- if (isNaN(id)) return c.notFound();
264
- const page = await c.var.services.pages.getById(id);
265
- if (!page) return c.notFound();
266
- const siteName = await getSiteName(c);
267
- return c.html(/*#__PURE__*/ _jsx(DashLayout, {
268
- c: c,
269
- title: `Edit: ${page.title || "Page"}`,
270
- siteName: siteName,
271
- currentPath: "/dash/pages",
272
- children: /*#__PURE__*/ _jsx(EditPageContent, {
273
- page: page
274
- })
275
- }));
276
- });
277
- pagesRoutes.post("/:id", async (c)=>{
278
- const id = parseInt(c.req.param("id"), 10);
279
- if (isNaN(id)) return c.notFound();
280
- const body = await c.req.json();
281
- await c.var.services.pages.update(id, {
282
- title: body.title,
283
- body: body.body,
284
- status: body.status,
285
- slug: body.slug.toLowerCase().replace(/[^a-z0-9-]/g, "-")
286
- });
287
- return dsRedirect(`/dash/pages/${id}`);
288
- });
289
- pagesRoutes.post("/:id/delete", async (c)=>{
290
- const id = parseInt(c.req.param("id"), 10);
291
- if (isNaN(id)) return c.notFound();
292
- await c.var.services.pages.delete(id);
293
- return dsRedirect("/dash/pages");
294
- });