@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
@@ -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
- });