@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,122 +0,0 @@
1
- /**
2
- * Search Page
3
- *
4
- * Search form and results — divider-separated instead of bordered cards.
5
- */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
6
- import { useLingui as $_useLingui } from "@jant/core/i18n";
7
- import { PagePagination } from "../shared/Pagination.js";
8
- export const SearchPage = ({ query, results, error, hasMore, page })=>{
9
- const { i18n: $__i18n, _: $__ } = $_useLingui();
10
- const searchTitle = $__i18n._({
11
- id: "A1taO8",
12
- message: "Search"
13
- });
14
- return /*#__PURE__*/ _jsxs("div", {
15
- class: "py-6",
16
- "data-page": "search",
17
- children: [
18
- /*#__PURE__*/ _jsx("h1", {
19
- class: "text-2xl font-semibold mb-6",
20
- children: searchTitle
21
- }),
22
- /*#__PURE__*/ _jsx("form", {
23
- method: "get",
24
- action: "/search",
25
- class: "mb-8",
26
- children: /*#__PURE__*/ _jsxs("div", {
27
- class: "flex gap-2",
28
- children: [
29
- /*#__PURE__*/ _jsx("input", {
30
- type: "search",
31
- name: "q",
32
- class: "input flex-1",
33
- placeholder: $__i18n._({
34
- id: "MqghUt",
35
- message: "Search posts..."
36
- }),
37
- value: query,
38
- autofocus: true
39
- }),
40
- /*#__PURE__*/ _jsx("button", {
41
- type: "submit",
42
- class: "btn",
43
- children: $__i18n._({
44
- id: "A1taO8",
45
- message: "Search"
46
- })
47
- })
48
- ]
49
- })
50
- }),
51
- error && /*#__PURE__*/ _jsx("div", {
52
- class: "alert-destructive mb-6",
53
- children: /*#__PURE__*/ _jsx("h2", {
54
- children: error
55
- })
56
- }),
57
- query && !error && /*#__PURE__*/ _jsxs("div", {
58
- children: [
59
- /*#__PURE__*/ _jsx("p", {
60
- class: "text-sm text-muted-foreground mb-4",
61
- children: results.length === 0 ? $__i18n._({
62
- id: "MZbQHL",
63
- message: "No results found."
64
- }) : results.length === 1 ? $__i18n._({
65
- id: "z8ajIE",
66
- message: "Found 1 result"
67
- }) : $__i18n._({
68
- id: "zH6KqE",
69
- message: "Found {count} results"
70
- })
71
- }),
72
- results.length > 0 && /*#__PURE__*/ _jsxs(_Fragment, {
73
- children: [
74
- /*#__PURE__*/ _jsx("div", {
75
- class: "divide-y divide-border",
76
- children: results.map((result)=>/*#__PURE__*/ _jsx("article", {
77
- class: "py-4",
78
- "data-post": true,
79
- "data-format": result.post.format,
80
- children: /*#__PURE__*/ _jsxs("a", {
81
- href: result.post.permalink,
82
- class: "block",
83
- children: [
84
- /*#__PURE__*/ _jsx("h2", {
85
- class: "font-medium hover:underline",
86
- children: result.post.title || result.post.excerpt?.slice(0, 60) || "Post #" + result.post.id
87
- }),
88
- result.snippet && /*#__PURE__*/ _jsx("p", {
89
- class: "text-sm text-muted-foreground mt-2 line-clamp-2",
90
- dangerouslySetInnerHTML: {
91
- __html: result.snippet
92
- }
93
- }),
94
- /*#__PURE__*/ _jsxs("footer", {
95
- class: "flex items-center gap-2 mt-2 text-xs text-muted-foreground",
96
- children: [
97
- /*#__PURE__*/ _jsx("span", {
98
- class: "badge-outline",
99
- children: result.post.format
100
- }),
101
- /*#__PURE__*/ _jsx("time", {
102
- datetime: result.post.publishedAt,
103
- children: result.post.publishedAtFormatted
104
- })
105
- ]
106
- })
107
- ]
108
- })
109
- }, result.post.id))
110
- }),
111
- /*#__PURE__*/ _jsx(PagePagination, {
112
- baseUrl: "/search?q=" + encodeURIComponent(query),
113
- currentPage: page,
114
- hasMore: hasMore
115
- })
116
- ]
117
- })
118
- ]
119
- })
120
- ]
121
- });
122
- };
@@ -1,23 +0,0 @@
1
- /**
2
- * Single Page (Custom Page)
3
- *
4
- * Custom page view — clean centered content.
5
- */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
6
- export const SinglePage = ({ page })=>{
7
- return /*#__PURE__*/ _jsxs("article", {
8
- class: "h-entry py-6",
9
- "data-page": "single-page",
10
- children: [
11
- page.title && /*#__PURE__*/ _jsx("h1", {
12
- class: "p-name text-2xl font-semibold mb-6",
13
- children: page.title
14
- }),
15
- /*#__PURE__*/ _jsx("div", {
16
- class: "e-content prose",
17
- dangerouslySetInnerHTML: {
18
- __html: page.bodyHtml || ""
19
- }
20
- })
21
- ]
22
- });
23
- };
@@ -1,27 +0,0 @@
1
- /**
2
- * Empty State Component
3
- *
4
- * Displays a message when a list or collection has no items,
5
- * optionally with a call-to-action button
6
- */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
7
- export const EmptyState = ({ message, ctaText, ctaHref, centered = true })=>{
8
- if (!centered) {
9
- return /*#__PURE__*/ _jsx("p", {
10
- class: "text-muted-foreground",
11
- children: message
12
- });
13
- }
14
- return /*#__PURE__*/ _jsxs("div", {
15
- class: "text-center py-12 text-muted-foreground",
16
- children: [
17
- /*#__PURE__*/ _jsx("p", {
18
- children: message
19
- }),
20
- ctaText && ctaHref && /*#__PURE__*/ _jsx("a", {
21
- href: ctaHref,
22
- class: "btn mt-4",
23
- children: ctaText
24
- })
25
- ]
26
- });
27
- };
@@ -1,35 +0,0 @@
1
- /**
2
- * Media Gallery Component
3
- *
4
- * Renders media attachments in a horizontal scrollable row,
5
- * similar to an image carousel.
6
- */ import { jsx as _jsx } from "hono/jsx/jsx-runtime";
7
- export const MediaGallery = ({ attachments })=>{
8
- const images = attachments.filter((a)=>a.mimeType.startsWith("image/"));
9
- if (images.length === 0) return null;
10
- const single = images.length === 1;
11
- return /*#__PURE__*/ _jsx("div", {
12
- class: `mt-3 flex gap-2 ${single ? "" : "overflow-x-auto scroll-smooth snap-x snap-mandatory"}`,
13
- style: single ? undefined : "scrollbar-width: none; -ms-overflow-style: none;",
14
- children: images.map((img)=>{
15
- const aspectRatio = img.width && img.height ? img.width / img.height : 4 / 3;
16
- const itemWidth = single ? undefined : `${Math.round(320 * Math.min(Math.max(aspectRatio, 0.6), 1.6))}px`;
17
- return /*#__PURE__*/ _jsx("a", {
18
- href: img.url,
19
- target: "_blank",
20
- rel: "noopener noreferrer",
21
- class: `${single ? "" : "shrink-0 snap-start"} block rounded-lg overflow-hidden`,
22
- style: single ? undefined : {
23
- width: itemWidth,
24
- maxWidth: "85%"
25
- },
26
- children: /*#__PURE__*/ _jsx("img", {
27
- src: img.thumbnailUrl,
28
- alt: img.altText || "",
29
- class: single ? "rounded-lg max-w-full max-h-96 h-auto object-contain" : "h-80 w-full object-cover",
30
- loading: "lazy"
31
- })
32
- }, img.id);
33
- })
34
- });
35
- };
@@ -1,195 +0,0 @@
1
- /**
2
- * Pagination Component
3
- *
4
- * Cursor-based pagination for post lists
5
- */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
6
- import { useLingui as $_useLingui } from "@jant/core/i18n";
7
- import { getPageNumbers } from "../../lib/pagination.js";
8
- export const Pagination = ({ baseUrl, hasMore, nextCursor, prevCursor, cursorParam = "cursor" })=>{
9
- const { i18n: $__i18n, _: $__ } = $_useLingui();
10
- const hasPrev = prevCursor !== undefined;
11
- const hasNext = hasMore && nextCursor !== undefined;
12
- if (!hasPrev && !hasNext) {
13
- return null;
14
- }
15
- // Build URL with cursor parameter
16
- const buildUrl = (cursor)=>{
17
- const url = new URL(baseUrl, "http://localhost");
18
- url.searchParams.set(cursorParam, String(cursor));
19
- return `${url.pathname}${url.search}`;
20
- };
21
- const prevText = $__i18n._({
22
- id: "DHhJ7s",
23
- message: "Previous"
24
- });
25
- const nextText = $__i18n._({
26
- id: "hXzOVo",
27
- message: "Next"
28
- });
29
- return /*#__PURE__*/ _jsxs("nav", {
30
- class: "flex items-center justify-between py-4",
31
- "aria-label": "Pagination",
32
- children: [
33
- /*#__PURE__*/ _jsx("div", {
34
- children: hasPrev ? /*#__PURE__*/ _jsxs("a", {
35
- href: buildUrl(prevCursor),
36
- class: "btn-outline text-sm",
37
- children: [
38
- "← ",
39
- prevText
40
- ]
41
- }) : /*#__PURE__*/ _jsxs("span", {
42
- class: "btn-outline text-sm opacity-50 cursor-not-allowed",
43
- children: [
44
- "← ",
45
- prevText
46
- ]
47
- })
48
- }),
49
- /*#__PURE__*/ _jsx("div", {
50
- children: hasNext ? /*#__PURE__*/ _jsxs("a", {
51
- href: buildUrl(nextCursor),
52
- class: "btn-outline text-sm",
53
- children: [
54
- nextText,
55
- " →"
56
- ]
57
- }) : /*#__PURE__*/ _jsxs("span", {
58
- class: "btn-outline text-sm opacity-50 cursor-not-allowed",
59
- children: [
60
- nextText,
61
- " →"
62
- ]
63
- })
64
- })
65
- ]
66
- });
67
- };
68
- export const LoadMore = ({ href, hasMore, text })=>{
69
- const { i18n: $__i18n, _: $__ } = $_useLingui();
70
- if (!hasMore) {
71
- return null;
72
- }
73
- const buttonText = text ?? $__i18n._({
74
- id: "yQ2kGp",
75
- message: "Load more"
76
- });
77
- return /*#__PURE__*/ _jsx("div", {
78
- class: "text-center py-4",
79
- children: /*#__PURE__*/ _jsx("a", {
80
- href: href,
81
- class: "btn-outline",
82
- children: buttonText
83
- })
84
- });
85
- };
86
- export const PagePagination = ({ baseUrl, currentPage, hasMore, totalPages, pageParam = "page" })=>{
87
- const { i18n: $__i18n, _: $__ } = $_useLingui();
88
- const hasPrev = currentPage > 1;
89
- const hasNext = totalPages ? currentPage < totalPages : hasMore ?? false;
90
- if (!hasPrev && !hasNext) {
91
- return null;
92
- }
93
- // Build URL with page parameter
94
- const buildUrl = (page)=>{
95
- const url = new URL(baseUrl, "http://localhost");
96
- if (page > 1) {
97
- url.searchParams.set(pageParam, String(page));
98
- } else {
99
- url.searchParams.delete(pageParam);
100
- }
101
- return `${url.pathname}${url.search}`;
102
- };
103
- const prevText = $__i18n._({
104
- id: "DHhJ7s",
105
- message: "Previous"
106
- });
107
- const nextText = $__i18n._({
108
- id: "hXzOVo",
109
- message: "Next"
110
- });
111
- // Numbered pagination when totalPages is known
112
- if (totalPages && totalPages > 1) {
113
- const pageNumbers = getPageNumbers(currentPage, totalPages);
114
- return /*#__PURE__*/ _jsxs("nav", {
115
- class: "flex items-center justify-center gap-4 py-6 text-sm",
116
- "aria-label": "Pagination",
117
- children: [
118
- hasPrev ? /*#__PURE__*/ _jsx("a", {
119
- href: buildUrl(currentPage - 1),
120
- class: "underline text-muted-foreground hover:text-foreground",
121
- children: prevText
122
- }) : /*#__PURE__*/ _jsx("span", {
123
- class: "text-muted-foreground/50",
124
- children: prevText
125
- }),
126
- pageNumbers.map((page, i)=>page === 0 ? /*#__PURE__*/ _jsx("span", {
127
- class: "text-muted-foreground",
128
- children: "..."
129
- }, `ellipsis-${i}`) : page === currentPage ? /*#__PURE__*/ _jsx("span", {
130
- "aria-current": "page",
131
- children: page
132
- }, page) : /*#__PURE__*/ _jsx("a", {
133
- href: buildUrl(page),
134
- class: "underline text-muted-foreground hover:text-foreground",
135
- children: page
136
- }, page)),
137
- hasNext ? /*#__PURE__*/ _jsx("a", {
138
- href: buildUrl(currentPage + 1),
139
- class: "underline text-muted-foreground hover:text-foreground",
140
- children: nextText
141
- }) : /*#__PURE__*/ _jsx("span", {
142
- class: "text-muted-foreground/50",
143
- children: nextText
144
- })
145
- ]
146
- });
147
- }
148
- // Simple prev/next fallback when totalPages is unknown
149
- const pageText = $__i18n._({
150
- id: "tiq7kl",
151
- message: "Page {page}"
152
- });
153
- return /*#__PURE__*/ _jsxs("nav", {
154
- class: "flex items-center justify-between py-4",
155
- "aria-label": "Pagination",
156
- children: [
157
- /*#__PURE__*/ _jsx("div", {
158
- children: hasPrev ? /*#__PURE__*/ _jsxs("a", {
159
- href: buildUrl(currentPage - 1),
160
- class: "btn-outline text-sm",
161
- children: [
162
- "← ",
163
- prevText
164
- ]
165
- }) : /*#__PURE__*/ _jsxs("span", {
166
- class: "btn-outline text-sm opacity-50 cursor-not-allowed",
167
- children: [
168
- "← ",
169
- prevText
170
- ]
171
- })
172
- }),
173
- /*#__PURE__*/ _jsx("span", {
174
- class: "text-sm text-muted-foreground",
175
- children: pageText
176
- }),
177
- /*#__PURE__*/ _jsx("div", {
178
- children: hasNext ? /*#__PURE__*/ _jsxs("a", {
179
- href: buildUrl(currentPage + 1),
180
- class: "btn-outline text-sm",
181
- children: [
182
- nextText,
183
- " →"
184
- ]
185
- }) : /*#__PURE__*/ _jsxs("span", {
186
- class: "btn-outline text-sm opacity-50 cursor-not-allowed",
187
- children: [
188
- nextText,
189
- " →"
190
- ]
191
- })
192
- })
193
- ]
194
- });
195
- };
@@ -1,108 +0,0 @@
1
- /**
2
- * Thread View Component
3
- *
4
- * Displays a thread of posts with reply chain visualization
5
- */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
6
- import { useLingui as $_useLingui } from "@jant/core/i18n";
7
- import * as sqid from "../../lib/sqid.js";
8
- import * as time from "../../lib/time.js";
9
- const ThreadPost = ({ post, isCurrent, isRoot })=>{
10
- const { i18n: $__i18n, _: $__ } = $_useLingui();
11
- return /*#__PURE__*/ _jsxs("article", {
12
- id: `post-${post.id}`,
13
- class: `h-entry p-4 rounded-lg border ${isCurrent ? "border-primary bg-primary/5 ring-2 ring-primary/20" : "border-border hover:border-muted-foreground/30"}`,
14
- children: [
15
- post.title && /*#__PURE__*/ _jsx("h2", {
16
- class: "p-name text-lg font-medium mb-2",
17
- children: /*#__PURE__*/ _jsx("a", {
18
- href: `${post.path ? `/${post.path}` : `/p/${sqid.encode(post.id)}`}`,
19
- class: "u-url hover:underline",
20
- children: post.title
21
- })
22
- }),
23
- /*#__PURE__*/ _jsx("div", {
24
- class: "e-content prose prose-sm",
25
- dangerouslySetInnerHTML: {
26
- __html: post.bodyHtml || ""
27
- }
28
- }),
29
- /*#__PURE__*/ _jsxs("footer", {
30
- class: "mt-3 flex items-center gap-3 text-sm text-muted-foreground",
31
- children: [
32
- /*#__PURE__*/ _jsx("time", {
33
- class: "dt-published",
34
- datetime: time.toISOString(post.publishedAt),
35
- children: time.formatDate(post.publishedAt)
36
- }),
37
- isRoot && /*#__PURE__*/ _jsx("span", {
38
- class: "text-xs",
39
- children: $__i18n._({
40
- id: "sGajR7",
41
- message: "Thread start"
42
- })
43
- }),
44
- !isCurrent && /*#__PURE__*/ _jsx("a", {
45
- href: `${post.path ? `/${post.path}` : `/p/${sqid.encode(post.id)}`}`,
46
- class: "text-xs hover:underline",
47
- children: $__i18n._({
48
- id: "D9Oea+",
49
- message: "Permalink"
50
- })
51
- })
52
- ]
53
- })
54
- ]
55
- });
56
- };
57
- export const ThreadView = ({ posts, currentPostId })=>{
58
- const { i18n: $__i18n, _: $__ } = $_useLingui();
59
- if (posts.length === 0) {
60
- return null;
61
- }
62
- const rootPost = posts[0];
63
- const isThread = posts.length > 1;
64
- // Single post, no thread
65
- if (!isThread) {
66
- return(// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Early return for empty array at line 73 guarantees posts[0] exists
67
- /*#__PURE__*/ _jsx(ThreadPost, {
68
- post: rootPost,
69
- isCurrent: true,
70
- isRoot: false
71
- }));
72
- }
73
- const threadLabel = posts.length === 1 ? $__i18n._({
74
- id: "rzNUSl",
75
- message: "Thread with 1 post"
76
- }) : $__i18n._({
77
- id: "RwGhWy",
78
- message: "Thread with {count} posts"
79
- });
80
- return /*#__PURE__*/ _jsxs("div", {
81
- class: "thread-view",
82
- children: [
83
- /*#__PURE__*/ _jsx("div", {
84
- class: "mb-4 text-sm text-muted-foreground",
85
- children: threadLabel
86
- }),
87
- /*#__PURE__*/ _jsx("div", {
88
- class: "flex flex-col gap-3",
89
- children: posts.map((post, index)=>/*#__PURE__*/ _jsxs("div", {
90
- class: "relative",
91
- children: [
92
- index > 0 && /*#__PURE__*/ _jsx("div", {
93
- class: "absolute left-6 -top-3 w-0.5 h-3 bg-border"
94
- }),
95
- index < posts.length - 1 && /*#__PURE__*/ _jsx("div", {
96
- class: "absolute left-6 -bottom-3 w-0.5 h-3 bg-border"
97
- }),
98
- /*#__PURE__*/ _jsx(ThreadPost, {
99
- post: post,
100
- isCurrent: post.id === currentPostId,
101
- isRoot: index === 0
102
- })
103
- ]
104
- }, post.id))
105
- })
106
- ]
107
- });
108
- };
@@ -1,5 +0,0 @@
1
- export { EmptyState } from "./EmptyState.js";
2
- export { MediaGallery } from "./MediaGallery.js";
3
- export { Pagination, LoadMore, PagePagination } from "./Pagination.js";
4
- export { getPageNumbers } from "../../lib/pagination.js";
5
- export { ThreadView } from "./ThreadView.js";