@jant/core 0.1.2 → 0.2.0

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 (288) hide show
  1. package/dist/app.d.ts +34 -0
  2. package/dist/app.d.ts.map +1 -0
  3. package/dist/app.js +474 -0
  4. package/dist/assets/datastar.min.js +1775 -0
  5. package/dist/auth.d.ts +23 -0
  6. package/dist/auth.d.ts.map +1 -0
  7. package/dist/auth.js +34 -0
  8. package/{src/client.ts → dist/client.d.ts} +1 -1
  9. package/dist/client.d.ts.map +1 -0
  10. package/dist/client.js +4 -0
  11. package/dist/db/index.d.ts +10 -0
  12. package/dist/db/index.d.ts.map +1 -0
  13. package/dist/db/index.js +10 -0
  14. package/dist/db/schema.d.ts +1507 -0
  15. package/dist/db/schema.d.ts.map +1 -0
  16. package/dist/db/schema.js +183 -0
  17. package/{src/i18n/Trans.tsx → dist/i18n/Trans.d.ts} +4 -10
  18. package/dist/i18n/Trans.d.ts.map +1 -0
  19. package/dist/i18n/Trans.js +24 -0
  20. package/dist/i18n/context.d.ts +69 -0
  21. package/dist/i18n/context.d.ts.map +1 -0
  22. package/dist/i18n/context.js +61 -0
  23. package/dist/i18n/detect.d.ts +31 -0
  24. package/dist/i18n/detect.d.ts.map +1 -0
  25. package/dist/i18n/detect.js +77 -0
  26. package/{src/i18n/i18n.ts → dist/i18n/i18n.d.ts} +5 -25
  27. package/dist/i18n/i18n.d.ts.map +1 -0
  28. package/dist/i18n/i18n.js +55 -0
  29. package/dist/i18n/index.d.ts +41 -0
  30. package/dist/i18n/index.d.ts.map +1 -0
  31. package/{src/i18n/index.ts → dist/i18n/index.js} +3 -24
  32. package/dist/i18n/locales/en.d.ts +3 -0
  33. package/dist/i18n/locales/en.d.ts.map +1 -0
  34. package/dist/i18n/locales/en.js +1 -0
  35. package/dist/i18n/locales/zh-Hans.d.ts +3 -0
  36. package/dist/i18n/locales/zh-Hans.d.ts.map +1 -0
  37. package/dist/i18n/locales/zh-Hans.js +1 -0
  38. package/dist/i18n/locales/zh-Hant.d.ts +3 -0
  39. package/dist/i18n/locales/zh-Hant.d.ts.map +1 -0
  40. package/dist/i18n/locales/zh-Hant.js +1 -0
  41. package/dist/i18n/locales.d.ts +11 -0
  42. package/dist/i18n/locales.d.ts.map +1 -0
  43. package/dist/i18n/locales.js +13 -0
  44. package/dist/i18n/middleware.d.ts +24 -0
  45. package/dist/i18n/middleware.d.ts.map +1 -0
  46. package/dist/i18n/middleware.js +41 -0
  47. package/dist/index.d.ts +16 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/{src/index.ts → dist/index.js} +1 -28
  50. package/dist/lib/assets.d.ts +19 -0
  51. package/dist/lib/assets.d.ts.map +1 -0
  52. package/dist/lib/assets.js +33 -0
  53. package/dist/lib/constants.d.ts +36 -0
  54. package/dist/lib/constants.d.ts.map +1 -0
  55. package/dist/lib/constants.js +50 -0
  56. package/{src/lib/image.ts → dist/lib/image.d.ts} +13 -47
  57. package/dist/lib/image.d.ts.map +1 -0
  58. package/dist/lib/image.js +77 -0
  59. package/{src/lib/index.ts → dist/lib/index.d.ts} +1 -1
  60. package/dist/lib/index.d.ts.map +1 -0
  61. package/dist/lib/index.js +7 -0
  62. package/dist/lib/markdown.d.ts +60 -0
  63. package/dist/lib/markdown.d.ts.map +1 -0
  64. package/{src/lib/markdown.ts → dist/lib/markdown.js} +16 -26
  65. package/dist/lib/schemas.d.ts +113 -0
  66. package/dist/lib/schemas.d.ts.map +1 -0
  67. package/dist/lib/schemas.js +71 -0
  68. package/dist/lib/sqid.d.ts +60 -0
  69. package/dist/lib/sqid.d.ts.map +1 -0
  70. package/{src/lib/sqid.ts → dist/lib/sqid.js} +15 -22
  71. package/dist/lib/sse.d.ts +95 -0
  72. package/dist/lib/sse.d.ts.map +1 -0
  73. package/dist/lib/sse.js +81 -0
  74. package/dist/lib/time.d.ts +90 -0
  75. package/dist/lib/time.d.ts.map +1 -0
  76. package/{src/lib/time.ts → dist/lib/time.js} +20 -33
  77. package/{src/lib/url.ts → dist/lib/url.d.ts} +5 -30
  78. package/dist/lib/url.d.ts.map +1 -0
  79. package/dist/lib/url.js +89 -0
  80. package/dist/middleware/auth.d.ts +24 -0
  81. package/dist/middleware/auth.d.ts.map +1 -0
  82. package/dist/middleware/auth.js +52 -0
  83. package/dist/routes/api/posts.d.ts +13 -0
  84. package/dist/routes/api/posts.d.ts.map +1 -0
  85. package/dist/routes/api/posts.js +124 -0
  86. package/dist/routes/api/search.d.ts +13 -0
  87. package/dist/routes/api/search.d.ts.map +1 -0
  88. package/dist/routes/api/search.js +49 -0
  89. package/dist/routes/api/upload.d.ts +16 -0
  90. package/dist/routes/api/upload.d.ts.map +1 -0
  91. package/dist/routes/api/upload.js +227 -0
  92. package/dist/routes/dash/collections.d.ts +13 -0
  93. package/dist/routes/dash/collections.d.ts.map +1 -0
  94. package/dist/routes/dash/collections.js +512 -0
  95. package/dist/routes/dash/index.d.ts +15 -0
  96. package/dist/routes/dash/index.d.ts.map +1 -0
  97. package/dist/routes/dash/index.js +117 -0
  98. package/dist/routes/dash/media.d.ts +16 -0
  99. package/dist/routes/dash/media.d.ts.map +1 -0
  100. package/dist/routes/dash/media.js +589 -0
  101. package/dist/routes/dash/pages.d.ts +15 -0
  102. package/dist/routes/dash/pages.d.ts.map +1 -0
  103. package/dist/routes/dash/pages.js +290 -0
  104. package/dist/routes/dash/posts.d.ts +13 -0
  105. package/dist/routes/dash/posts.d.ts.map +1 -0
  106. package/dist/routes/dash/posts.js +226 -0
  107. package/dist/routes/dash/redirects.d.ts +13 -0
  108. package/dist/routes/dash/redirects.d.ts.map +1 -0
  109. package/dist/routes/dash/redirects.js +237 -0
  110. package/dist/routes/dash/settings.d.ts +13 -0
  111. package/dist/routes/dash/settings.d.ts.map +1 -0
  112. package/dist/routes/dash/settings.js +154 -0
  113. package/dist/routes/feed/rss.d.ts +13 -0
  114. package/dist/routes/feed/rss.d.ts.map +1 -0
  115. package/dist/routes/feed/rss.js +95 -0
  116. package/dist/routes/feed/sitemap.d.ts +13 -0
  117. package/dist/routes/feed/sitemap.d.ts.map +1 -0
  118. package/dist/routes/feed/sitemap.js +59 -0
  119. package/dist/routes/pages/archive.d.ts +15 -0
  120. package/dist/routes/pages/archive.d.ts.map +1 -0
  121. package/dist/routes/pages/archive.js +255 -0
  122. package/dist/routes/pages/collection.d.ts +13 -0
  123. package/dist/routes/pages/collection.d.ts.map +1 -0
  124. package/dist/routes/pages/collection.js +93 -0
  125. package/dist/routes/pages/home.d.ts +13 -0
  126. package/dist/routes/pages/home.d.ts.map +1 -0
  127. package/dist/routes/pages/home.js +122 -0
  128. package/dist/routes/pages/page.d.ts +15 -0
  129. package/dist/routes/pages/page.d.ts.map +1 -0
  130. package/dist/routes/pages/page.js +69 -0
  131. package/dist/routes/pages/post.d.ts +13 -0
  132. package/dist/routes/pages/post.d.ts.map +1 -0
  133. package/dist/routes/pages/post.js +90 -0
  134. package/dist/routes/pages/search.d.ts +13 -0
  135. package/dist/routes/pages/search.d.ts.map +1 -0
  136. package/dist/routes/pages/search.js +180 -0
  137. package/dist/services/collection.d.ts +31 -0
  138. package/dist/services/collection.d.ts.map +1 -0
  139. package/dist/services/collection.js +108 -0
  140. package/dist/services/index.d.ts +28 -0
  141. package/dist/services/index.d.ts.map +1 -0
  142. package/dist/services/index.js +20 -0
  143. package/dist/services/media.d.ts +27 -0
  144. package/dist/services/media.d.ts.map +1 -0
  145. package/dist/services/media.js +62 -0
  146. package/dist/services/post.d.ts +31 -0
  147. package/dist/services/post.d.ts.map +1 -0
  148. package/dist/services/post.js +191 -0
  149. package/dist/services/redirect.d.ts +15 -0
  150. package/dist/services/redirect.d.ts.map +1 -0
  151. package/dist/services/redirect.js +48 -0
  152. package/dist/services/search.d.ts +26 -0
  153. package/dist/services/search.d.ts.map +1 -0
  154. package/dist/services/search.js +61 -0
  155. package/dist/services/settings.d.ts +17 -0
  156. package/dist/services/settings.d.ts.map +1 -0
  157. package/dist/services/settings.js +65 -0
  158. package/dist/theme/components/ActionButtons.d.ts +43 -0
  159. package/dist/theme/components/ActionButtons.d.ts.map +1 -0
  160. package/dist/theme/components/ActionButtons.js +50 -0
  161. package/dist/theme/components/CrudPageHeader.d.ts +23 -0
  162. package/dist/theme/components/CrudPageHeader.d.ts.map +1 -0
  163. package/dist/theme/components/CrudPageHeader.js +22 -0
  164. package/dist/theme/components/DangerZone.d.ts +36 -0
  165. package/dist/theme/components/DangerZone.d.ts.map +1 -0
  166. package/dist/theme/components/DangerZone.js +39 -0
  167. package/dist/theme/components/EmptyState.d.ts +27 -0
  168. package/dist/theme/components/EmptyState.d.ts.map +1 -0
  169. package/dist/theme/components/EmptyState.js +27 -0
  170. package/dist/theme/components/ListItemRow.d.ts +15 -0
  171. package/dist/theme/components/ListItemRow.d.ts.map +1 -0
  172. package/dist/theme/components/ListItemRow.js +21 -0
  173. package/dist/theme/components/PageForm.d.ts +14 -0
  174. package/dist/theme/components/PageForm.d.ts.map +1 -0
  175. package/dist/theme/components/PageForm.js +173 -0
  176. package/dist/theme/components/Pagination.d.ts +46 -0
  177. package/dist/theme/components/Pagination.d.ts.map +1 -0
  178. package/dist/theme/components/Pagination.js +159 -0
  179. package/dist/theme/components/PostForm.d.ts +12 -0
  180. package/dist/theme/components/PostForm.d.ts.map +1 -0
  181. package/dist/theme/components/PostForm.js +230 -0
  182. package/dist/theme/components/PostList.d.ts +10 -0
  183. package/dist/theme/components/PostList.d.ts.map +1 -0
  184. package/dist/theme/components/PostList.js +73 -0
  185. package/dist/theme/components/ThreadView.d.ts +15 -0
  186. package/dist/theme/components/ThreadView.d.ts.map +1 -0
  187. package/dist/theme/components/ThreadView.js +111 -0
  188. package/dist/theme/components/TypeBadge.d.ts +12 -0
  189. package/dist/theme/components/TypeBadge.d.ts.map +1 -0
  190. package/dist/theme/components/TypeBadge.js +39 -0
  191. package/dist/theme/components/VisibilityBadge.d.ts +12 -0
  192. package/dist/theme/components/VisibilityBadge.d.ts.map +1 -0
  193. package/dist/theme/components/VisibilityBadge.js +37 -0
  194. package/{src/theme/components/index.ts → dist/theme/components/index.d.ts} +1 -0
  195. package/dist/theme/components/index.d.ts.map +1 -0
  196. package/dist/theme/components/index.js +12 -0
  197. package/dist/theme/index.d.ts +21 -0
  198. package/dist/theme/index.d.ts.map +1 -0
  199. package/{src/theme/index.ts → dist/theme/index.js} +1 -4
  200. package/dist/theme/layouts/BaseLayout.d.ts +16 -0
  201. package/dist/theme/layouts/BaseLayout.d.ts.map +1 -0
  202. package/dist/theme/layouts/BaseLayout.js +58 -0
  203. package/dist/theme/layouts/DashLayout.d.ts +15 -0
  204. package/dist/theme/layouts/DashLayout.d.ts.map +1 -0
  205. package/dist/theme/layouts/DashLayout.js +139 -0
  206. package/{src/theme/layouts/index.ts → dist/theme/layouts/index.d.ts} +1 -0
  207. package/dist/theme/layouts/index.d.ts.map +1 -0
  208. package/dist/theme/layouts/index.js +2 -0
  209. package/dist/theme/styles/main.css +2 -0
  210. package/dist/types.d.ts +179 -0
  211. package/dist/types.d.ts.map +1 -0
  212. package/dist/types.js +19 -0
  213. package/package.json +26 -26
  214. package/drizzle.config.ts +0 -10
  215. package/lingui.config.ts +0 -16
  216. package/src/app.tsx +0 -377
  217. package/src/assets/datastar.min.js +0 -8
  218. package/src/auth.ts +0 -38
  219. package/src/db/index.ts +0 -14
  220. package/src/db/migrations/0000_solid_moon_knight.sql +0 -118
  221. package/src/db/migrations/0001_add_search_fts.sql +0 -40
  222. package/src/db/migrations/0002_collection_path.sql +0 -2
  223. package/src/db/migrations/0003_collection_path_nullable.sql +0 -21
  224. package/src/db/migrations/0004_media_uuid.sql +0 -35
  225. package/src/db/migrations/meta/0000_snapshot.json +0 -784
  226. package/src/db/migrations/meta/_journal.json +0 -41
  227. package/src/db/schema.ts +0 -159
  228. package/src/i18n/EXAMPLES.md +0 -235
  229. package/src/i18n/README.md +0 -296
  230. package/src/i18n/context.tsx +0 -101
  231. package/src/i18n/detect.ts +0 -100
  232. package/src/i18n/locales/en.po +0 -875
  233. package/src/i18n/locales/en.ts +0 -1
  234. package/src/i18n/locales/zh-Hans.po +0 -875
  235. package/src/i18n/locales/zh-Hans.ts +0 -1
  236. package/src/i18n/locales/zh-Hant.po +0 -875
  237. package/src/i18n/locales/zh-Hant.ts +0 -1
  238. package/src/i18n/locales.ts +0 -14
  239. package/src/i18n/middleware.ts +0 -59
  240. package/src/lib/assets.ts +0 -47
  241. package/src/lib/constants.ts +0 -67
  242. package/src/lib/schemas.ts +0 -92
  243. package/src/lib/sse.ts +0 -152
  244. package/src/middleware/auth.ts +0 -59
  245. package/src/routes/api/posts.ts +0 -127
  246. package/src/routes/api/search.ts +0 -53
  247. package/src/routes/api/upload.ts +0 -240
  248. package/src/routes/dash/collections.tsx +0 -341
  249. package/src/routes/dash/index.tsx +0 -89
  250. package/src/routes/dash/media.tsx +0 -551
  251. package/src/routes/dash/pages.tsx +0 -245
  252. package/src/routes/dash/posts.tsx +0 -202
  253. package/src/routes/dash/redirects.tsx +0 -155
  254. package/src/routes/dash/settings.tsx +0 -93
  255. package/src/routes/feed/rss.ts +0 -119
  256. package/src/routes/feed/sitemap.ts +0 -75
  257. package/src/routes/pages/archive.tsx +0 -223
  258. package/src/routes/pages/collection.tsx +0 -79
  259. package/src/routes/pages/home.tsx +0 -93
  260. package/src/routes/pages/page.tsx +0 -64
  261. package/src/routes/pages/post.tsx +0 -81
  262. package/src/routes/pages/search.tsx +0 -162
  263. package/src/services/collection.ts +0 -180
  264. package/src/services/index.ts +0 -40
  265. package/src/services/media.ts +0 -97
  266. package/src/services/post.ts +0 -279
  267. package/src/services/redirect.ts +0 -74
  268. package/src/services/search.ts +0 -117
  269. package/src/services/settings.ts +0 -76
  270. package/src/theme/components/ActionButtons.tsx +0 -98
  271. package/src/theme/components/CrudPageHeader.tsx +0 -48
  272. package/src/theme/components/DangerZone.tsx +0 -77
  273. package/src/theme/components/EmptyState.tsx +0 -56
  274. package/src/theme/components/ListItemRow.tsx +0 -24
  275. package/src/theme/components/PageForm.tsx +0 -114
  276. package/src/theme/components/Pagination.tsx +0 -196
  277. package/src/theme/components/PostForm.tsx +0 -122
  278. package/src/theme/components/PostList.tsx +0 -68
  279. package/src/theme/components/ThreadView.tsx +0 -118
  280. package/src/theme/components/TypeBadge.tsx +0 -28
  281. package/src/theme/components/VisibilityBadge.tsx +0 -33
  282. package/src/theme/layouts/BaseLayout.tsx +0 -49
  283. package/src/theme/layouts/DashLayout.tsx +0 -108
  284. package/src/theme/styles/main.css +0 -52
  285. package/src/types.ts +0 -222
  286. package/tsconfig.json +0 -16
  287. package/vite.config.ts +0 -82
  288. package/wrangler.toml +0 -21
@@ -0,0 +1,512 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
2
+ /**
3
+ * Dashboard Collections Routes
4
+ */ import { Hono } from "hono";
5
+ import { useLingui } from "../../i18n/index.js";
6
+ import { DashLayout } from "../../theme/layouts/index.js";
7
+ import { EmptyState, ListItemRow, ActionButtons, CrudPageHeader, DangerZone } from "../../theme/components/index.js";
8
+ import * as sqid from "../../lib/sqid.js";
9
+ export const collectionsRoutes = new Hono();
10
+ function CollectionsListContent({ collections }) {
11
+ const { t } = useLingui();
12
+ return /*#__PURE__*/ _jsxs(_Fragment, {
13
+ children: [
14
+ /*#__PURE__*/ _jsx(CrudPageHeader, {
15
+ title: t({
16
+ message: "Collections",
17
+ comment: "@context: Dashboard heading"
18
+ }),
19
+ ctaLabel: t({
20
+ message: "New Collection",
21
+ comment: "@context: Button to create new collection"
22
+ }),
23
+ ctaHref: "/dash/collections/new"
24
+ }),
25
+ collections.length === 0 ? /*#__PURE__*/ _jsx(EmptyState, {
26
+ message: t({
27
+ message: "No collections yet.",
28
+ comment: "@context: Empty state message"
29
+ }),
30
+ ctaText: t({
31
+ message: "New Collection",
32
+ comment: "@context: Button to create new collection"
33
+ }),
34
+ ctaHref: "/dash/collections/new"
35
+ }) : /*#__PURE__*/ _jsx("div", {
36
+ class: "flex flex-col divide-y",
37
+ children: collections.map((col)=>/*#__PURE__*/ _jsxs(ListItemRow, {
38
+ actions: /*#__PURE__*/ _jsx(ActionButtons, {
39
+ editHref: `/dash/collections/${col.id}/edit`,
40
+ editLabel: t({
41
+ message: "Edit",
42
+ comment: "@context: Button to edit collection"
43
+ }),
44
+ viewHref: `/c/${col.path}`,
45
+ viewLabel: t({
46
+ message: "View",
47
+ comment: "@context: Button to view collection"
48
+ })
49
+ }),
50
+ children: [
51
+ /*#__PURE__*/ _jsx("a", {
52
+ href: `/dash/collections/${col.id}`,
53
+ class: "font-medium hover:underline",
54
+ children: col.title
55
+ }),
56
+ /*#__PURE__*/ _jsxs("p", {
57
+ class: "text-sm text-muted-foreground",
58
+ children: [
59
+ "/",
60
+ col.path
61
+ ]
62
+ }),
63
+ col.description && /*#__PURE__*/ _jsx("p", {
64
+ class: "text-sm text-muted-foreground mt-1",
65
+ children: col.description
66
+ })
67
+ ]
68
+ }, col.id))
69
+ })
70
+ ]
71
+ });
72
+ }
73
+ function NewCollectionContent() {
74
+ const { t } = useLingui();
75
+ return /*#__PURE__*/ _jsxs(_Fragment, {
76
+ children: [
77
+ /*#__PURE__*/ _jsx("h1", {
78
+ class: "text-2xl font-semibold mb-6",
79
+ children: t({
80
+ message: "New Collection",
81
+ comment: "@context: Page heading"
82
+ })
83
+ }),
84
+ /*#__PURE__*/ _jsxs("form", {
85
+ method: "post",
86
+ action: "/dash/collections",
87
+ class: "flex flex-col gap-4 max-w-lg",
88
+ children: [
89
+ /*#__PURE__*/ _jsxs("div", {
90
+ class: "field",
91
+ children: [
92
+ /*#__PURE__*/ _jsx("label", {
93
+ class: "label",
94
+ children: t({
95
+ message: "Title",
96
+ comment: "@context: Collection form field"
97
+ })
98
+ }),
99
+ /*#__PURE__*/ _jsx("input", {
100
+ type: "text",
101
+ name: "title",
102
+ class: "input",
103
+ required: true,
104
+ placeholder: t({
105
+ message: "My Collection",
106
+ comment: "@context: Collection title placeholder"
107
+ })
108
+ })
109
+ ]
110
+ }),
111
+ /*#__PURE__*/ _jsxs("div", {
112
+ class: "field",
113
+ children: [
114
+ /*#__PURE__*/ _jsx("label", {
115
+ class: "label",
116
+ children: t({
117
+ message: "Slug",
118
+ comment: "@context: Collection form field"
119
+ })
120
+ }),
121
+ /*#__PURE__*/ _jsx("input", {
122
+ type: "text",
123
+ name: "path",
124
+ class: "input",
125
+ required: true,
126
+ placeholder: "my-collection",
127
+ pattern: "[a-z0-9-]+"
128
+ }),
129
+ /*#__PURE__*/ _jsx("p", {
130
+ class: "text-xs text-muted-foreground mt-1",
131
+ children: t({
132
+ message: "URL-safe identifier (lowercase, numbers, hyphens)",
133
+ comment: "@context: Collection path help text"
134
+ })
135
+ })
136
+ ]
137
+ }),
138
+ /*#__PURE__*/ _jsxs("div", {
139
+ class: "field",
140
+ children: [
141
+ /*#__PURE__*/ _jsx("label", {
142
+ class: "label",
143
+ children: t({
144
+ message: "Description (optional)",
145
+ comment: "@context: Collection form field"
146
+ })
147
+ }),
148
+ /*#__PURE__*/ _jsx("textarea", {
149
+ name: "description",
150
+ class: "textarea",
151
+ rows: 3,
152
+ placeholder: t({
153
+ message: "What's this collection about?",
154
+ comment: "@context: Collection description placeholder"
155
+ })
156
+ })
157
+ ]
158
+ }),
159
+ /*#__PURE__*/ _jsxs("div", {
160
+ class: "flex gap-2",
161
+ children: [
162
+ /*#__PURE__*/ _jsx("button", {
163
+ type: "submit",
164
+ class: "btn",
165
+ children: t({
166
+ message: "Create Collection",
167
+ comment: "@context: Button to save new collection"
168
+ })
169
+ }),
170
+ /*#__PURE__*/ _jsx("a", {
171
+ href: "/dash/collections",
172
+ class: "btn-outline",
173
+ children: t({
174
+ message: "Cancel",
175
+ comment: "@context: Button to cancel form"
176
+ })
177
+ })
178
+ ]
179
+ })
180
+ ]
181
+ })
182
+ ]
183
+ });
184
+ }
185
+ function ViewCollectionContent({ collection, posts }) {
186
+ const { t } = useLingui();
187
+ const postsHeader = t({
188
+ message: "Posts in Collection ({count})",
189
+ comment: "@context: Collection posts section heading",
190
+ values: {
191
+ count: String(posts.length)
192
+ }
193
+ });
194
+ return /*#__PURE__*/ _jsxs(_Fragment, {
195
+ children: [
196
+ /*#__PURE__*/ _jsxs("div", {
197
+ class: "flex items-center justify-between mb-6",
198
+ children: [
199
+ /*#__PURE__*/ _jsxs("div", {
200
+ children: [
201
+ /*#__PURE__*/ _jsx("h1", {
202
+ class: "text-2xl font-semibold",
203
+ children: collection.title
204
+ }),
205
+ /*#__PURE__*/ _jsxs("p", {
206
+ class: "text-sm text-muted-foreground",
207
+ children: [
208
+ "/",
209
+ collection.path
210
+ ]
211
+ })
212
+ ]
213
+ }),
214
+ /*#__PURE__*/ _jsx(ActionButtons, {
215
+ editHref: `/dash/collections/${collection.id}/edit`,
216
+ editLabel: t({
217
+ message: "Edit",
218
+ comment: "@context: Button to edit collection"
219
+ }),
220
+ viewHref: `/c/${collection.path}`,
221
+ viewLabel: t({
222
+ message: "View",
223
+ comment: "@context: Button to view collection"
224
+ })
225
+ })
226
+ ]
227
+ }),
228
+ collection.description && /*#__PURE__*/ _jsx("p", {
229
+ class: "text-muted-foreground mb-6",
230
+ children: collection.description
231
+ }),
232
+ /*#__PURE__*/ _jsxs("div", {
233
+ class: "card",
234
+ children: [
235
+ /*#__PURE__*/ _jsx("header", {
236
+ children: /*#__PURE__*/ _jsx("h2", {
237
+ children: postsHeader
238
+ })
239
+ }),
240
+ /*#__PURE__*/ _jsx("section", {
241
+ children: posts.length === 0 ? /*#__PURE__*/ _jsx("p", {
242
+ class: "text-muted-foreground",
243
+ children: t({
244
+ message: "No posts in this collection.",
245
+ comment: "@context: Empty state message"
246
+ })
247
+ }) : /*#__PURE__*/ _jsx("div", {
248
+ class: "flex flex-col divide-y",
249
+ children: posts.map((post)=>/*#__PURE__*/ _jsxs("div", {
250
+ class: "py-3 flex items-center gap-4",
251
+ children: [
252
+ /*#__PURE__*/ _jsx("div", {
253
+ class: "flex-1 min-w-0",
254
+ children: /*#__PURE__*/ _jsx("a", {
255
+ href: `/dash/posts/${sqid.encode(post.id)}`,
256
+ class: "font-medium hover:underline",
257
+ children: post.title || post.content?.slice(0, 50) || `Post #${post.id}`
258
+ })
259
+ }),
260
+ /*#__PURE__*/ _jsxs("form", {
261
+ method: "post",
262
+ action: `/dash/collections/${collection.id}/remove-post`,
263
+ children: [
264
+ /*#__PURE__*/ _jsx("input", {
265
+ type: "hidden",
266
+ name: "postId",
267
+ value: post.id
268
+ }),
269
+ /*#__PURE__*/ _jsx("button", {
270
+ type: "submit",
271
+ class: "btn-sm-ghost text-destructive",
272
+ children: t({
273
+ message: "Remove",
274
+ comment: "@context: Button to remove post from collection"
275
+ })
276
+ })
277
+ ]
278
+ })
279
+ ]
280
+ }, post.id))
281
+ })
282
+ })
283
+ ]
284
+ }),
285
+ /*#__PURE__*/ _jsx("div", {
286
+ class: "mt-6",
287
+ children: /*#__PURE__*/ _jsx("a", {
288
+ href: "/dash/collections",
289
+ class: "text-sm hover:underline",
290
+ children: t({
291
+ message: "← Back to Collections",
292
+ comment: "@context: Navigation link"
293
+ })
294
+ })
295
+ })
296
+ ]
297
+ });
298
+ }
299
+ function EditCollectionContent({ collection }) {
300
+ const { t } = useLingui();
301
+ return /*#__PURE__*/ _jsxs(_Fragment, {
302
+ children: [
303
+ /*#__PURE__*/ _jsx("h1", {
304
+ class: "text-2xl font-semibold mb-6",
305
+ children: t({
306
+ message: "Edit Collection",
307
+ comment: "@context: Page heading"
308
+ })
309
+ }),
310
+ /*#__PURE__*/ _jsxs("form", {
311
+ method: "post",
312
+ action: `/dash/collections/${collection.id}`,
313
+ class: "flex flex-col gap-4 max-w-lg",
314
+ children: [
315
+ /*#__PURE__*/ _jsxs("div", {
316
+ class: "field",
317
+ children: [
318
+ /*#__PURE__*/ _jsx("label", {
319
+ class: "label",
320
+ children: t({
321
+ message: "Title",
322
+ comment: "@context: Collection form field"
323
+ })
324
+ }),
325
+ /*#__PURE__*/ _jsx("input", {
326
+ type: "text",
327
+ name: "title",
328
+ class: "input",
329
+ required: true,
330
+ value: collection.title
331
+ })
332
+ ]
333
+ }),
334
+ /*#__PURE__*/ _jsxs("div", {
335
+ class: "field",
336
+ children: [
337
+ /*#__PURE__*/ _jsx("label", {
338
+ class: "label",
339
+ children: t({
340
+ message: "Slug",
341
+ comment: "@context: Collection form field"
342
+ })
343
+ }),
344
+ /*#__PURE__*/ _jsx("input", {
345
+ type: "text",
346
+ name: "path",
347
+ class: "input",
348
+ required: true,
349
+ value: collection.path ?? "",
350
+ pattern: "[a-z0-9-]+"
351
+ })
352
+ ]
353
+ }),
354
+ /*#__PURE__*/ _jsxs("div", {
355
+ class: "field",
356
+ children: [
357
+ /*#__PURE__*/ _jsx("label", {
358
+ class: "label",
359
+ children: t({
360
+ message: "Description (optional)",
361
+ comment: "@context: Collection form field"
362
+ })
363
+ }),
364
+ /*#__PURE__*/ _jsx("textarea", {
365
+ name: "description",
366
+ class: "textarea",
367
+ rows: 3,
368
+ children: collection.description ?? ""
369
+ })
370
+ ]
371
+ }),
372
+ /*#__PURE__*/ _jsxs("div", {
373
+ class: "flex gap-2",
374
+ children: [
375
+ /*#__PURE__*/ _jsx("button", {
376
+ type: "submit",
377
+ class: "btn",
378
+ children: t({
379
+ message: "Update Collection",
380
+ comment: "@context: Button to save collection changes"
381
+ })
382
+ }),
383
+ /*#__PURE__*/ _jsx("a", {
384
+ href: `/dash/collections/${collection.id}`,
385
+ class: "btn-outline",
386
+ children: t({
387
+ message: "Cancel",
388
+ comment: "@context: Button to cancel form"
389
+ })
390
+ })
391
+ ]
392
+ })
393
+ ]
394
+ }),
395
+ /*#__PURE__*/ _jsx(DangerZone, {
396
+ actionLabel: t({
397
+ message: "Delete Collection",
398
+ comment: "@context: Button to delete collection"
399
+ }),
400
+ formAction: `/dash/collections/${collection.id}/delete`,
401
+ confirmMessage: "Are you sure you want to delete this collection?"
402
+ })
403
+ ]
404
+ });
405
+ }
406
+ // List collections
407
+ collectionsRoutes.get("/", async (c)=>{
408
+ const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
409
+ const collections = await c.var.services.collections.list();
410
+ return c.html(/*#__PURE__*/ _jsx(DashLayout, {
411
+ c: c,
412
+ title: "Collections",
413
+ siteName: siteName,
414
+ currentPath: "/dash/collections",
415
+ children: /*#__PURE__*/ _jsx(CollectionsListContent, {
416
+ collections: collections
417
+ })
418
+ }));
419
+ });
420
+ // New collection form
421
+ collectionsRoutes.get("/new", async (c)=>{
422
+ const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
423
+ return c.html(/*#__PURE__*/ _jsx(DashLayout, {
424
+ c: c,
425
+ title: "New Collection",
426
+ siteName: siteName,
427
+ currentPath: "/dash/collections",
428
+ children: /*#__PURE__*/ _jsx(NewCollectionContent, {})
429
+ }));
430
+ });
431
+ // Create collection
432
+ collectionsRoutes.post("/", async (c)=>{
433
+ const formData = await c.req.formData();
434
+ const title = formData.get("title");
435
+ const path = formData.get("path");
436
+ const description = formData.get("description");
437
+ const collection = await c.var.services.collections.create({
438
+ title,
439
+ path,
440
+ description: description || undefined
441
+ });
442
+ return c.redirect(`/dash/collections/${collection.id}`);
443
+ });
444
+ // View single collection
445
+ collectionsRoutes.get("/:id", async (c)=>{
446
+ const id = parseInt(c.req.param("id"), 10);
447
+ if (isNaN(id)) return c.notFound();
448
+ const collection = await c.var.services.collections.getById(id);
449
+ if (!collection) return c.notFound();
450
+ const posts = await c.var.services.collections.getPosts(id);
451
+ const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
452
+ return c.html(/*#__PURE__*/ _jsx(DashLayout, {
453
+ c: c,
454
+ title: collection.title,
455
+ siteName: siteName,
456
+ currentPath: "/dash/collections",
457
+ children: /*#__PURE__*/ _jsx(ViewCollectionContent, {
458
+ collection: collection,
459
+ posts: posts
460
+ })
461
+ }));
462
+ });
463
+ // Edit collection form
464
+ collectionsRoutes.get("/:id/edit", async (c)=>{
465
+ const id = parseInt(c.req.param("id"), 10);
466
+ if (isNaN(id)) return c.notFound();
467
+ const collection = await c.var.services.collections.getById(id);
468
+ if (!collection) return c.notFound();
469
+ const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
470
+ return c.html(/*#__PURE__*/ _jsx(DashLayout, {
471
+ c: c,
472
+ title: `Edit: ${collection.title}`,
473
+ siteName: siteName,
474
+ currentPath: "/dash/collections",
475
+ children: /*#__PURE__*/ _jsx(EditCollectionContent, {
476
+ collection: collection
477
+ })
478
+ }));
479
+ });
480
+ // Update collection
481
+ collectionsRoutes.post("/:id", async (c)=>{
482
+ const id = parseInt(c.req.param("id"), 10);
483
+ if (isNaN(id)) return c.notFound();
484
+ const formData = await c.req.formData();
485
+ const title = formData.get("title");
486
+ const path = formData.get("path");
487
+ const description = formData.get("description");
488
+ await c.var.services.collections.update(id, {
489
+ title,
490
+ path,
491
+ description: description || undefined
492
+ });
493
+ return c.redirect(`/dash/collections/${id}`);
494
+ });
495
+ // Delete collection
496
+ collectionsRoutes.post("/:id/delete", async (c)=>{
497
+ const id = parseInt(c.req.param("id"), 10);
498
+ if (isNaN(id)) return c.notFound();
499
+ await c.var.services.collections.delete(id);
500
+ return c.redirect("/dash/collections");
501
+ });
502
+ // Remove post from collection
503
+ collectionsRoutes.post("/:id/remove-post", async (c)=>{
504
+ const id = parseInt(c.req.param("id"), 10);
505
+ if (isNaN(id)) return c.notFound();
506
+ const formData = await c.req.formData();
507
+ const postId = parseInt(formData.get("postId"), 10);
508
+ if (!isNaN(postId)) {
509
+ await c.var.services.collections.removePost(id, postId);
510
+ }
511
+ return c.redirect(`/dash/collections/${id}`);
512
+ });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Dashboard Index Route
3
+ *
4
+ * Example of using @lingui/react/macro with Hono JSX!
5
+ */
6
+ import { Hono } from "hono";
7
+ import type { Bindings } from "../../types.js";
8
+ import type { AppVariables } from "../../app.js";
9
+ type Env = {
10
+ Bindings: Bindings;
11
+ Variables: AppVariables;
12
+ };
13
+ export declare const dashIndexRoutes: Hono<Env, import("hono/types").BlankSchema, "/">;
14
+ export {};
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/index.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,eAAe,kDAAkB,CAAC"}
@@ -0,0 +1,117 @@
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 { Trans, useLingui } from "../../i18n/index.js";
8
+ import { DashLayout } from "../../theme/layouts/index.js";
9
+ export const dashIndexRoutes = new Hono();
10
+ /**
11
+ * Dashboard content component
12
+ * Uses useLingui() from @lingui/react/macro - works with Hono JSX!
13
+ */ function DashboardContent({ publishedCount, draftCount }) {
14
+ // 🎉 Single layer! Just like React!
15
+ const { t } = useLingui();
16
+ return /*#__PURE__*/ _jsxs("div", {
17
+ class: "container py-8",
18
+ children: [
19
+ /*#__PURE__*/ _jsx("h1", {
20
+ class: "text-2xl font-semibold mb-6",
21
+ children: t({
22
+ message: "Dashboard",
23
+ comment: "@context: Dashboard main heading"
24
+ })
25
+ }),
26
+ /*#__PURE__*/ _jsxs("div", {
27
+ class: "grid gap-4 md:grid-cols-3 mb-6",
28
+ children: [
29
+ /*#__PURE__*/ _jsxs("div", {
30
+ class: "p-4 border rounded",
31
+ children: [
32
+ /*#__PURE__*/ _jsx("p", {
33
+ class: "text-sm text-muted-foreground",
34
+ children: t({
35
+ message: "Published",
36
+ comment: "@context: Post status label"
37
+ })
38
+ }),
39
+ /*#__PURE__*/ _jsx("p", {
40
+ class: "text-3xl font-bold",
41
+ children: publishedCount
42
+ })
43
+ ]
44
+ }),
45
+ /*#__PURE__*/ _jsxs("div", {
46
+ class: "p-4 border rounded",
47
+ children: [
48
+ /*#__PURE__*/ _jsx("p", {
49
+ class: "text-sm text-muted-foreground",
50
+ children: t({
51
+ message: "Drafts",
52
+ comment: "@context: Post status label"
53
+ })
54
+ }),
55
+ /*#__PURE__*/ _jsx("p", {
56
+ class: "text-3xl font-bold",
57
+ children: draftCount
58
+ })
59
+ ]
60
+ }),
61
+ /*#__PURE__*/ _jsxs("div", {
62
+ class: "p-4 border rounded",
63
+ children: [
64
+ /*#__PURE__*/ _jsx("p", {
65
+ class: "text-sm text-muted-foreground mb-2",
66
+ children: t({
67
+ message: "Quick Actions",
68
+ comment: "@context: Dashboard section title"
69
+ })
70
+ }),
71
+ /*#__PURE__*/ _jsx("a", {
72
+ href: "/dash/posts/new",
73
+ class: "btn btn-primary w-full",
74
+ children: t({
75
+ message: "New Post",
76
+ comment: "@context: Button to create new post"
77
+ })
78
+ })
79
+ ]
80
+ })
81
+ ]
82
+ }),
83
+ /*#__PURE__*/ _jsx("p", {
84
+ children: /*#__PURE__*/ _jsxs(Trans, {
85
+ comment: "@context: Help text with link",
86
+ children: [
87
+ "Need help? Visit the ",
88
+ /*#__PURE__*/ _jsx("a", {
89
+ href: "/docs",
90
+ class: "underline",
91
+ children: "documentation"
92
+ })
93
+ ]
94
+ })
95
+ })
96
+ ]
97
+ });
98
+ }
99
+ dashIndexRoutes.get("/", async (c)=>{
100
+ const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
101
+ // Get some stats
102
+ const allPosts = await c.var.services.posts.list({
103
+ limit: 1000
104
+ });
105
+ const publishedPosts = allPosts.filter((p)=>p.visibility !== "draft");
106
+ const draftPosts = allPosts.filter((p)=>p.visibility === "draft");
107
+ return c.html(/*#__PURE__*/ _jsx(DashLayout, {
108
+ c: c,
109
+ title: "Dashboard",
110
+ siteName: siteName,
111
+ currentPath: "/dash",
112
+ children: /*#__PURE__*/ _jsx(DashboardContent, {
113
+ publishedCount: publishedPosts.length,
114
+ draftCount: draftPosts.length
115
+ })
116
+ }));
117
+ });
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Dashboard Media Routes
3
+ *
4
+ * Media management with Datastar-powered uploads.
5
+ * Uses SSE for real-time UI updates without page reloads.
6
+ */
7
+ import { Hono } from "hono";
8
+ import type { Bindings } from "../../types.js";
9
+ import type { AppVariables } from "../../app.js";
10
+ type Env = {
11
+ Bindings: Bindings;
12
+ Variables: AppVariables;
13
+ };
14
+ export declare const mediaRoutes: Hono<Env, import("hono/types").BlankSchema, "/">;
15
+ export {};
16
+ //# sourceMappingURL=media.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/media.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAS,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAOjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,WAAW,kDAAkB,CAAC"}