@jant/core 0.3.26 → 0.3.28

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