@jant/core 0.3.23 → 0.3.25

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 (248) hide show
  1. package/dist/app.js +50 -26
  2. package/dist/db/schema.js +72 -47
  3. package/dist/i18n/locales/en.js +1 -1
  4. package/dist/i18n/locales/zh-Hans.js +1 -1
  5. package/dist/i18n/locales/zh-Hant.js +1 -1
  6. package/dist/index.js +5 -11
  7. package/dist/lib/constants.js +2 -4
  8. package/dist/lib/excerpt.js +76 -0
  9. package/dist/lib/feed.js +18 -7
  10. package/dist/lib/nav-reorder.js +1 -1
  11. package/dist/lib/navigation.js +30 -6
  12. package/dist/lib/pagination.js +44 -0
  13. package/dist/lib/render.js +7 -11
  14. package/dist/lib/schemas.js +80 -38
  15. package/dist/lib/theme.js +4 -4
  16. package/dist/lib/time.js +56 -1
  17. package/dist/lib/timeline.js +95 -0
  18. package/dist/lib/view.js +61 -72
  19. package/dist/routes/api/collections.js +124 -0
  20. package/dist/routes/api/nav-items.js +104 -0
  21. package/dist/routes/api/pages.js +91 -0
  22. package/dist/routes/api/posts.js +27 -33
  23. package/dist/routes/api/search.js +4 -5
  24. package/dist/routes/api/settings.js +68 -0
  25. package/dist/routes/api/upload.js +13 -13
  26. package/dist/routes/compose.js +48 -0
  27. package/dist/routes/dash/collections.js +24 -42
  28. package/dist/routes/dash/index.js +3 -3
  29. package/dist/routes/dash/media.js +2 -2
  30. package/dist/routes/dash/pages.js +440 -106
  31. package/dist/routes/dash/posts.js +27 -37
  32. package/dist/routes/dash/redirects.js +2 -2
  33. package/dist/routes/dash/settings.js +79 -5
  34. package/dist/routes/feed/rss.js +4 -6
  35. package/dist/routes/feed/sitemap.js +11 -8
  36. package/dist/routes/pages/archive.js +13 -15
  37. package/dist/routes/pages/collection.js +12 -9
  38. package/dist/routes/pages/collections.js +28 -0
  39. package/dist/routes/pages/featured.js +32 -0
  40. package/dist/routes/pages/home.js +19 -68
  41. package/dist/routes/pages/page.js +57 -29
  42. package/dist/routes/pages/post.js +7 -17
  43. package/dist/routes/pages/search.js +5 -9
  44. package/dist/services/collection.js +52 -64
  45. package/dist/services/index.js +5 -3
  46. package/dist/services/navigation.js +29 -53
  47. package/dist/services/page.js +84 -0
  48. package/dist/services/post.js +102 -69
  49. package/dist/services/search.js +24 -18
  50. package/dist/types.js +24 -40
  51. package/dist/ui/compose/ComposeDialog.js +452 -0
  52. package/dist/ui/compose/ComposePrompt.js +55 -0
  53. package/dist/{theme/components/TypeBadge.js → ui/dash/FormatBadge.js} +3 -15
  54. package/dist/{theme/components → ui/dash}/PageForm.js +15 -15
  55. package/dist/{theme/components → ui/dash}/PostForm.js +117 -137
  56. package/dist/{theme/components → ui/dash}/PostList.js +18 -13
  57. package/dist/ui/dash/StatusBadge.js +46 -0
  58. package/dist/{theme/components → ui/dash}/index.js +3 -6
  59. package/dist/ui/feed/LinkCard.js +72 -0
  60. package/dist/ui/feed/NoteCard.js +58 -0
  61. package/dist/{themes/minimal/timeline → ui/feed}/QuoteCard.js +29 -14
  62. package/dist/{themes/minimal/timeline → ui/feed}/ThreadPreview.js +20 -18
  63. package/dist/ui/feed/TimelineFeed.js +41 -0
  64. package/dist/ui/feed/TimelineItem.js +27 -0
  65. package/dist/{theme → ui}/layouts/BaseLayout.js +10 -0
  66. package/dist/{theme → ui}/layouts/DashLayout.js +0 -8
  67. package/dist/ui/layouts/SiteLayout.js +141 -0
  68. package/dist/{themes/minimal → ui}/pages/ArchivePage.js +37 -50
  69. package/dist/ui/pages/CollectionPage.js +70 -0
  70. package/dist/ui/pages/CollectionsPage.js +76 -0
  71. package/dist/ui/pages/FeaturedPage.js +24 -0
  72. package/dist/ui/pages/HomePage.js +24 -0
  73. package/dist/{themes/minimal → ui}/pages/PostPage.js +20 -12
  74. package/dist/{themes/minimal → ui}/pages/SearchPage.js +19 -18
  75. package/dist/{themes/minimal → ui}/pages/SinglePage.js +5 -4
  76. package/dist/ui/shared/MediaGallery.js +35 -0
  77. package/dist/{theme/components → ui/shared}/Pagination.js +41 -2
  78. package/dist/{theme/components → ui/shared}/ThreadView.js +3 -3
  79. package/dist/ui/shared/index.js +5 -0
  80. package/package.json +2 -9
  81. package/src/__tests__/helpers/app.ts +4 -0
  82. package/src/__tests__/helpers/db.ts +53 -73
  83. package/src/app.tsx +56 -28
  84. package/src/db/migrations/0005_v2_schema_migration.sql +268 -0
  85. package/src/db/migrations/0006_rename_slug_to_path.sql +5 -0
  86. package/src/db/migrations/meta/_journal.json +14 -0
  87. package/src/db/schema.ts +63 -46
  88. package/src/i18n/locales/en.po +443 -240
  89. package/src/i18n/locales/en.ts +1 -1
  90. package/src/i18n/locales/zh-Hans.po +443 -240
  91. package/src/i18n/locales/zh-Hans.ts +1 -1
  92. package/src/i18n/locales/zh-Hant.po +443 -240
  93. package/src/i18n/locales/zh-Hant.ts +1 -1
  94. package/src/index.ts +29 -42
  95. package/src/lib/__tests__/excerpt.test.ts +125 -0
  96. package/src/lib/__tests__/schemas.test.ts +201 -99
  97. package/src/lib/__tests__/time.test.ts +62 -0
  98. package/src/{routes/api → lib}/__tests__/timeline.test.ts +81 -75
  99. package/src/lib/__tests__/view.test.ts +204 -50
  100. package/src/lib/constants.ts +2 -4
  101. package/src/lib/excerpt.ts +87 -0
  102. package/src/lib/feed.ts +22 -7
  103. package/src/lib/nav-reorder.ts +1 -1
  104. package/src/lib/navigation.ts +45 -8
  105. package/src/lib/pagination.ts +50 -0
  106. package/src/lib/render.tsx +7 -14
  107. package/src/lib/schemas.ts +119 -51
  108. package/src/lib/theme.ts +5 -5
  109. package/src/lib/time.ts +64 -0
  110. package/src/lib/timeline.ts +141 -0
  111. package/src/lib/view.ts +80 -82
  112. package/src/preset.css +46 -0
  113. package/src/routes/__tests__/compose.test.ts +199 -0
  114. package/src/routes/api/__tests__/collections.test.ts +249 -0
  115. package/src/routes/api/__tests__/nav-items.test.ts +222 -0
  116. package/src/routes/api/__tests__/pages.test.ts +218 -0
  117. package/src/routes/api/__tests__/posts.test.ts +50 -108
  118. package/src/routes/api/__tests__/search.test.ts +2 -3
  119. package/src/routes/api/__tests__/settings.test.ts +132 -0
  120. package/src/routes/api/collections.ts +143 -0
  121. package/src/routes/api/nav-items.ts +115 -0
  122. package/src/routes/api/pages.ts +101 -0
  123. package/src/routes/api/posts.ts +28 -28
  124. package/src/routes/api/search.ts +3 -3
  125. package/src/routes/api/settings.ts +91 -0
  126. package/src/routes/api/upload.ts +16 -6
  127. package/src/routes/compose.ts +63 -0
  128. package/src/routes/dash/__tests__/pages.test.ts +225 -0
  129. package/src/routes/dash/collections.tsx +20 -42
  130. package/src/routes/dash/index.tsx +3 -3
  131. package/src/routes/dash/media.tsx +2 -2
  132. package/src/routes/dash/pages.tsx +480 -122
  133. package/src/routes/dash/posts.tsx +42 -54
  134. package/src/routes/dash/redirects.tsx +2 -2
  135. package/src/routes/dash/settings.tsx +83 -5
  136. package/src/routes/feed/rss.ts +4 -3
  137. package/src/routes/feed/sitemap.ts +15 -5
  138. package/src/routes/pages/__tests__/collections.test.ts +94 -0
  139. package/src/routes/pages/__tests__/featured.test.ts +94 -0
  140. package/src/routes/pages/archive.tsx +15 -15
  141. package/src/routes/pages/collection.tsx +16 -9
  142. package/src/routes/pages/collections.tsx +36 -0
  143. package/src/routes/pages/featured.tsx +38 -0
  144. package/src/routes/pages/home.tsx +21 -92
  145. package/src/routes/pages/page.tsx +62 -27
  146. package/src/routes/pages/post.tsx +6 -18
  147. package/src/routes/pages/search.tsx +3 -7
  148. package/src/services/__tests__/collection.test.ts +257 -158
  149. package/src/services/__tests__/media.test.ts +18 -18
  150. package/src/services/__tests__/navigation.test.ts +161 -87
  151. package/src/services/__tests__/page.test.ts +106 -0
  152. package/src/services/__tests__/post-timeline.test.ts +92 -88
  153. package/src/services/__tests__/post.test.ts +432 -197
  154. package/src/services/__tests__/search.test.ts +19 -25
  155. package/src/services/collection.ts +71 -113
  156. package/src/services/index.ts +9 -8
  157. package/src/services/navigation.ts +38 -71
  158. package/src/services/page.ts +136 -0
  159. package/src/services/post.ts +141 -101
  160. package/src/services/search.ts +38 -27
  161. package/src/styles/tokens.css +47 -0
  162. package/src/styles/ui.css +491 -0
  163. package/src/types.ts +212 -198
  164. package/src/ui/compose/ComposeDialog.tsx +395 -0
  165. package/src/ui/compose/ComposePrompt.tsx +55 -0
  166. package/src/ui/dash/FormatBadge.tsx +28 -0
  167. package/src/{theme/components → ui/dash}/PageForm.tsx +21 -21
  168. package/src/{theme/components → ui/dash}/PostForm.tsx +110 -131
  169. package/src/ui/dash/PostList.tsx +101 -0
  170. package/src/ui/dash/StatusBadge.tsx +61 -0
  171. package/src/ui/dash/index.ts +10 -0
  172. package/src/ui/feed/LinkCard.tsx +72 -0
  173. package/src/ui/feed/NoteCard.tsx +63 -0
  174. package/src/ui/feed/QuoteCard.tsx +68 -0
  175. package/src/ui/feed/ThreadPreview.tsx +48 -0
  176. package/src/ui/feed/TimelineFeed.tsx +49 -0
  177. package/src/ui/feed/TimelineItem.tsx +45 -0
  178. package/src/{theme → ui}/layouts/BaseLayout.tsx +11 -1
  179. package/src/{theme → ui}/layouts/DashLayout.tsx +0 -10
  180. package/src/ui/layouts/SiteLayout.tsx +150 -0
  181. package/src/ui/pages/ArchivePage.tsx +162 -0
  182. package/src/ui/pages/CollectionPage.tsx +70 -0
  183. package/src/ui/pages/CollectionsPage.tsx +73 -0
  184. package/src/ui/pages/FeaturedPage.tsx +31 -0
  185. package/src/ui/pages/HomePage.tsx +37 -0
  186. package/src/ui/pages/PostPage.tsx +56 -0
  187. package/src/{themes/minimal → ui}/pages/SearchPage.tsx +24 -20
  188. package/src/{themes/minimal → ui}/pages/SinglePage.tsx +5 -5
  189. package/src/ui/shared/MediaGallery.tsx +59 -0
  190. package/src/{theme/components → ui/shared}/Pagination.tsx +67 -4
  191. package/src/{theme/components → ui/shared}/ThreadView.tsx +6 -3
  192. package/src/ui/shared/__tests__/pagination.test.ts +46 -0
  193. package/src/ui/shared/index.ts +12 -0
  194. package/bin/jant.js +0 -185
  195. package/dist/lib/theme-components.js +0 -49
  196. package/dist/routes/api/timeline.js +0 -120
  197. package/dist/routes/dash/navigation.js +0 -288
  198. package/dist/theme/components/MediaGallery.js +0 -107
  199. package/dist/theme/components/VisibilityBadge.js +0 -37
  200. package/dist/theme/index.js +0 -18
  201. package/dist/theme/layouts/index.js +0 -2
  202. package/dist/themes/minimal/MinimalSiteLayout.js +0 -83
  203. package/dist/themes/minimal/index.js +0 -65
  204. package/dist/themes/minimal/pages/CollectionPage.js +0 -65
  205. package/dist/themes/minimal/pages/HomePage.js +0 -25
  206. package/dist/themes/minimal/timeline/ArticleCard.js +0 -36
  207. package/dist/themes/minimal/timeline/ImageCard.js +0 -67
  208. package/dist/themes/minimal/timeline/LinkCard.js +0 -47
  209. package/dist/themes/minimal/timeline/NoteCard.js +0 -34
  210. package/dist/themes/minimal/timeline/TimelineFeed.js +0 -48
  211. package/dist/themes/minimal/timeline/TimelineItem.js +0 -44
  212. package/src/lib/__tests__/theme-components.test.ts +0 -126
  213. package/src/lib/theme-components.ts +0 -68
  214. package/src/routes/api/timeline.tsx +0 -159
  215. package/src/routes/dash/navigation.tsx +0 -316
  216. package/src/theme/components/MediaGallery.tsx +0 -128
  217. package/src/theme/components/PostList.tsx +0 -92
  218. package/src/theme/components/TypeBadge.tsx +0 -37
  219. package/src/theme/components/VisibilityBadge.tsx +0 -45
  220. package/src/theme/components/index.ts +0 -23
  221. package/src/theme/index.ts +0 -22
  222. package/src/theme/layouts/index.ts +0 -7
  223. package/src/themes/minimal/MinimalSiteLayout.tsx +0 -100
  224. package/src/themes/minimal/index.ts +0 -83
  225. package/src/themes/minimal/pages/ArchivePage.tsx +0 -157
  226. package/src/themes/minimal/pages/CollectionPage.tsx +0 -60
  227. package/src/themes/minimal/pages/HomePage.tsx +0 -41
  228. package/src/themes/minimal/pages/PostPage.tsx +0 -43
  229. package/src/themes/minimal/timeline/ArticleCard.tsx +0 -37
  230. package/src/themes/minimal/timeline/ImageCard.tsx +0 -63
  231. package/src/themes/minimal/timeline/LinkCard.tsx +0 -48
  232. package/src/themes/minimal/timeline/NoteCard.tsx +0 -35
  233. package/src/themes/minimal/timeline/QuoteCard.tsx +0 -49
  234. package/src/themes/minimal/timeline/ThreadPreview.tsx +0 -47
  235. package/src/themes/minimal/timeline/TimelineFeed.tsx +0 -57
  236. package/src/themes/minimal/timeline/TimelineItem.tsx +0 -75
  237. /package/dist/{theme → ui}/color-themes.js +0 -0
  238. /package/dist/{theme/components → ui/dash}/ActionButtons.js +0 -0
  239. /package/dist/{theme/components → ui/dash}/CrudPageHeader.js +0 -0
  240. /package/dist/{theme/components → ui/dash}/DangerZone.js +0 -0
  241. /package/dist/{theme/components → ui/dash}/ListItemRow.js +0 -0
  242. /package/dist/{theme/components → ui/shared}/EmptyState.js +0 -0
  243. /package/src/{theme → ui}/color-themes.ts +0 -0
  244. /package/src/{theme/components → ui/dash}/ActionButtons.tsx +0 -0
  245. /package/src/{theme/components → ui/dash}/CrudPageHeader.tsx +0 -0
  246. /package/src/{theme/components → ui/dash}/DangerZone.tsx +0 -0
  247. /package/src/{theme/components → ui/dash}/ListItemRow.tsx +0 -0
  248. /package/src/{theme/components → ui/shared}/EmptyState.tsx +0 -0
@@ -1,41 +1,56 @@
1
1
  /**
2
- * Minimal Theme - Quote Card
2
+ * Quote Card
3
3
  *
4
- * Subtle blockquote with left border for type="quote" posts.
4
+ * Left-border accent blockquote with full date in footer.
5
+ *
6
+ * Fields:
7
+ * - quoteText: the quoted text
8
+ * - title: attribution (who said it)
9
+ * - url: source link
10
+ * - bodyHtml: commentary
5
11
  */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
6
12
  export const QuoteCard = ({ post, compact })=>{
7
13
  return /*#__PURE__*/ _jsxs("article", {
8
- class: `h-entry${compact ? " text-sm" : ""}`,
14
+ class: `h-entry${compact ? " feed-compact" : ""}`,
15
+ "data-post": true,
16
+ "data-format": "quote",
9
17
  children: [
10
- post.contentHtml && /*#__PURE__*/ _jsx("blockquote", {
11
- class: `e-content border-l-2 border-muted-foreground/30 pl-4 italic ${compact ? "text-sm" : ""} leading-relaxed`,
18
+ post.quoteText && /*#__PURE__*/ _jsx("blockquote", {
19
+ class: "feed-quote",
12
20
  children: /*#__PURE__*/ _jsx("div", {
13
- dangerouslySetInnerHTML: {
14
- __html: post.contentHtml
15
- }
21
+ class: `e-content ${compact ? "text-sm" : "text-base"} leading-relaxed`,
22
+ children: post.quoteText
16
23
  })
17
24
  }),
18
- !compact && (post.sourceName || post.sourceUrl) && /*#__PURE__*/ _jsxs("div", {
25
+ !compact && (post.title || post.url) && /*#__PURE__*/ _jsxs("div", {
19
26
  class: "mt-2 text-sm text-muted-foreground",
20
27
  children: [
21
28
  "—",
22
29
  " ",
23
- post.sourceUrl ? /*#__PURE__*/ _jsx("a", {
24
- href: post.sourceUrl,
30
+ post.url ? /*#__PURE__*/ _jsx("a", {
31
+ href: post.url,
25
32
  class: "hover:underline",
26
33
  target: "_blank",
27
34
  rel: "noopener noreferrer",
28
- children: post.sourceName || post.sourceDomain || "Source"
35
+ children: post.title || "Source"
29
36
  }) : /*#__PURE__*/ _jsx("span", {
30
- children: post.sourceName
37
+ children: post.title
31
38
  })
32
39
  ]
33
40
  }),
41
+ !compact && post.bodyHtml && /*#__PURE__*/ _jsx("div", {
42
+ class: "mt-3 prose text-muted-foreground",
43
+ "data-post-body": true,
44
+ dangerouslySetInnerHTML: {
45
+ __html: post.bodyHtml
46
+ }
47
+ }),
34
48
  /*#__PURE__*/ _jsx("footer", {
35
49
  class: "mt-2",
50
+ "data-post-meta": true,
36
51
  children: /*#__PURE__*/ _jsx("a", {
37
52
  href: post.permalink,
38
- class: "u-url text-xs text-muted-foreground hover:text-foreground",
53
+ class: "u-url text-xs text-muted-foreground hover:underline",
39
54
  children: /*#__PURE__*/ _jsx("time", {
40
55
  class: "dt-published",
41
56
  datetime: post.publishedAt,
@@ -1,12 +1,12 @@
1
1
  /**
2
- * Minimal Theme - Thread Preview
2
+ * Thread Preview
3
3
  *
4
- * Minimal thread indicator: root post + compact replies + "show more" link.
4
+ * Root post + vertical line connector + compact replies underneath.
5
5
  */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
6
6
  import { useLingui as $_useLingui } from "@jant/core/i18n";
7
7
  import { TimelineItem } from "./TimelineItem.js";
8
8
  import { TimelineItemFromPost } from "./TimelineItem.js";
9
- export const ThreadPreview = ({ rootPost, previewReplies, totalReplyCount, theme })=>{
9
+ export const ThreadPreview = ({ rootPost, previewReplies, totalReplyCount })=>{
10
10
  const { i18n: $__i18n, _: $__ } = $_useLingui();
11
11
  const remainingCount = totalReplyCount - previewReplies.length;
12
12
  return /*#__PURE__*/ _jsxs("div", {
@@ -14,29 +14,31 @@ export const ThreadPreview = ({ rootPost, previewReplies, totalReplyCount, theme
14
14
  /*#__PURE__*/ _jsx(TimelineItem, {
15
15
  item: {
16
16
  post: rootPost
17
- },
18
- theme: theme
17
+ }
19
18
  }),
20
19
  previewReplies.length > 0 && /*#__PURE__*/ _jsxs("div", {
21
- class: "ml-4 mt-2 border-l border-border pl-4 flex flex-col gap-3",
20
+ class: "feed-replies",
22
21
  children: [
23
22
  previewReplies.map((reply)=>/*#__PURE__*/ _jsx("div", {
23
+ class: "feed-reply",
24
24
  children: /*#__PURE__*/ _jsx(TimelineItemFromPost, {
25
25
  post: reply,
26
- compact: true,
27
- theme: theme
26
+ compact: true
28
27
  })
29
28
  }, reply.id)),
30
- remainingCount > 0 && /*#__PURE__*/ _jsx("a", {
31
- href: rootPost.permalink,
32
- class: "text-sm text-muted-foreground hover:text-foreground hover:underline",
33
- children: $__i18n._({
34
- id: "smzF8S",
35
- message: "Show {remainingCount} more {0}",
36
- values: {
37
- remainingCount: remainingCount,
38
- 0: remainingCount === 1 ? "reply" : "replies"
39
- }
29
+ remainingCount > 0 && /*#__PURE__*/ _jsx("div", {
30
+ class: "feed-reply",
31
+ children: /*#__PURE__*/ _jsx("a", {
32
+ href: rootPost.permalink,
33
+ class: "text-sm text-muted-foreground hover:text-foreground hover:underline",
34
+ children: $__i18n._({
35
+ id: "smzF8S",
36
+ message: "Show {remainingCount} more {0}",
37
+ values: {
38
+ remainingCount: remainingCount,
39
+ 0: remainingCount === 1 ? "reply" : "replies"
40
+ }
41
+ })
40
42
  })
41
43
  })
42
44
  ]
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Timeline Feed
3
+ *
4
+ * Flat list of posts separated by simple dividers.
5
+ */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
6
+ import { TimelineItem } from "./TimelineItem.js";
7
+ import { ThreadPreview } from "./ThreadPreview.js";
8
+ import { PagePagination } from "../shared/Pagination.js";
9
+ export const TimelineFeed = ({ items, currentPage, totalPages })=>{
10
+ return /*#__PURE__*/ _jsxs("div", {
11
+ "data-feed": true,
12
+ children: [
13
+ /*#__PURE__*/ _jsx("div", {
14
+ id: "timeline-feed",
15
+ children: /*#__PURE__*/ _jsx("div", {
16
+ id: "timeline-items",
17
+ class: "flex flex-col",
18
+ children: items.map((item, i)=>/*#__PURE__*/ _jsxs("div", {
19
+ children: [
20
+ i > 0 && /*#__PURE__*/ _jsx("hr", {
21
+ class: "feed-divider"
22
+ }),
23
+ item.threadPreview ? /*#__PURE__*/ _jsx(ThreadPreview, {
24
+ rootPost: item.post,
25
+ previewReplies: item.threadPreview.replies,
26
+ totalReplyCount: item.threadPreview.totalReplyCount
27
+ }) : /*#__PURE__*/ _jsx(TimelineItem, {
28
+ item: item
29
+ })
30
+ ]
31
+ }, item.post.id))
32
+ })
33
+ }),
34
+ currentPage !== undefined && totalPages !== undefined && totalPages > 1 && /*#__PURE__*/ _jsx(PagePagination, {
35
+ baseUrl: "/",
36
+ currentPage: currentPage,
37
+ totalPages: totalPages
38
+ })
39
+ ]
40
+ });
41
+ };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Timeline Item
3
+ *
4
+ * Dispatches to the correct card component based on post format.
5
+ */ import { jsx as _jsx } from "hono/jsx/jsx-runtime";
6
+ import { NoteCard } from "./NoteCard.js";
7
+ import { LinkCard } from "./LinkCard.js";
8
+ import { QuoteCard } from "./QuoteCard.js";
9
+ const CARD_MAP = {
10
+ note: NoteCard,
11
+ link: LinkCard,
12
+ quote: QuoteCard
13
+ };
14
+ export const TimelineItem = ({ item, compact })=>{
15
+ const Card = CARD_MAP[item.post.format];
16
+ return /*#__PURE__*/ _jsx(Card, {
17
+ post: item.post,
18
+ compact: compact
19
+ });
20
+ };
21
+ export const TimelineItemFromPost = ({ post, compact })=>{
22
+ const Card = CARD_MAP[post.format];
23
+ return /*#__PURE__*/ _jsx(Card, {
24
+ post: post,
25
+ compact: compact
26
+ });
27
+ };
@@ -18,6 +18,10 @@ export const BaseLayout = ({ title, description, lang, c, toast, children })=>{
18
18
  }) : children;
19
19
  // Read theme style from Hono context if available
20
20
  const themeStyle = c ? c.get("themeStyle") : undefined;
21
+ // Read custom CSS from Hono context if available
22
+ const customCSS = c ? c.get("customCSS") : undefined;
23
+ // Check authentication status for data attribute
24
+ const isAuthenticated = c ? c.get("isAuthenticated") : false;
21
25
  return /*#__PURE__*/ _jsxs("html", {
22
26
  lang: resolvedLang,
23
27
  children: [
@@ -45,6 +49,9 @@ export const BaseLayout = ({ title, description, lang, c, toast, children })=>{
45
49
  themeStyle && /*#__PURE__*/ _jsx("style", {
46
50
  children: themeStyle
47
51
  }),
52
+ customCSS && /*#__PURE__*/ _jsx("style", {
53
+ children: customCSS
54
+ }),
48
55
  /*#__PURE__*/ _jsx(Script, {
49
56
  src: "/src/client.ts"
50
57
  })
@@ -52,6 +59,9 @@ export const BaseLayout = ({ title, description, lang, c, toast, children })=>{
52
59
  }),
53
60
  /*#__PURE__*/ _jsxs("body", {
54
61
  class: "bg-background text-foreground antialiased",
62
+ ...isAuthenticated ? {
63
+ "data-authenticated": true
64
+ } : {},
55
65
  children: [
56
66
  content,
57
67
  /*#__PURE__*/ _jsx("div", {
@@ -107,14 +107,6 @@ function DashLayoutContent({ siteName, currentPath, children }) {
107
107
  message: "Redirects"
108
108
  })
109
109
  }),
110
- /*#__PURE__*/ _jsx("a", {
111
- href: "/dash/navigation",
112
- class: navClass("/dash/navigation", /^\/dash\/navigation/),
113
- children: $__i18n._({
114
- id: "UxKoFf",
115
- message: "Navigation"
116
- })
117
- }),
118
110
  /*#__PURE__*/ _jsx("a", {
119
111
  href: "/dash/settings",
120
112
  class: navClass("/dash/settings", /^\/dash\/settings/),
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Site Layout
3
+ *
4
+ * Vertical header: site name on top, custom nav links below, description under nav.
5
+ * Content area with browse filter tabs and compose prompt/dialog for authenticated users.
6
+ */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
7
+ import { useLingui as $_useLingui } from "@jant/core/i18n";
8
+ import { ComposeDialog } from "../compose/ComposeDialog.js";
9
+ import { ComposePrompt } from "../compose/ComposePrompt.js";
10
+ function HeaderLink({ link }) {
11
+ return /*#__PURE__*/ _jsx("a", {
12
+ href: link.url,
13
+ class: `site-header-link ${link.isActive ? "site-header-link-active" : ""}`,
14
+ ...link.isExternal ? {
15
+ target: "_blank",
16
+ rel: "noopener noreferrer"
17
+ } : {},
18
+ children: link.label
19
+ });
20
+ }
21
+ export const SiteLayout = ({ siteName, siteDescription, links, currentPath, isAuthenticated, collections, children })=>{
22
+ const { i18n: $__i18n, _: $__ } = $_useLingui();
23
+ const browseLinks = [
24
+ {
25
+ href: "/",
26
+ label: $__i18n._({
27
+ id: "wL3cK8",
28
+ message: "Latest"
29
+ })
30
+ },
31
+ {
32
+ href: "/featured",
33
+ label: $__i18n._({
34
+ id: "FkMol5",
35
+ message: "Featured"
36
+ })
37
+ }
38
+ ];
39
+ const searchLabel = $__i18n._({
40
+ id: "A1taO8",
41
+ message: "Search"
42
+ });
43
+ const isHomePage = currentPath === "/" || currentPath === "/featured";
44
+ return /*#__PURE__*/ _jsxs("div", {
45
+ class: "site-page",
46
+ children: [
47
+ /*#__PURE__*/ _jsx("header", {
48
+ class: "site-header",
49
+ children: /*#__PURE__*/ _jsxs("div", {
50
+ class: "site-header-inner",
51
+ children: [
52
+ /*#__PURE__*/ _jsxs("div", {
53
+ class: "site-header-top site-header-top-bordered",
54
+ children: [
55
+ /*#__PURE__*/ _jsx("a", {
56
+ href: "/",
57
+ class: "site-logo",
58
+ children: siteName
59
+ }),
60
+ /*#__PURE__*/ _jsxs("div", {
61
+ class: "site-header-right",
62
+ children: [
63
+ links.length > 0 && /*#__PURE__*/ _jsx("nav", {
64
+ class: "site-header-nav",
65
+ children: links.map((link)=>/*#__PURE__*/ _jsx(HeaderLink, {
66
+ link: link
67
+ }, link.id))
68
+ }),
69
+ /*#__PURE__*/ _jsx("a", {
70
+ href: "/search",
71
+ class: `site-header-search ${currentPath === "/search" ? "site-header-search-active" : ""}`,
72
+ "aria-label": searchLabel,
73
+ title: searchLabel,
74
+ children: /*#__PURE__*/ _jsxs("svg", {
75
+ xmlns: "http://www.w3.org/2000/svg",
76
+ width: "16",
77
+ height: "16",
78
+ viewBox: "0 0 24 24",
79
+ fill: "none",
80
+ stroke: "currentColor",
81
+ "stroke-width": "2",
82
+ "stroke-linecap": "round",
83
+ "stroke-linejoin": "round",
84
+ children: [
85
+ /*#__PURE__*/ _jsx("circle", {
86
+ cx: "11",
87
+ cy: "11",
88
+ r: "8"
89
+ }),
90
+ /*#__PURE__*/ _jsx("path", {
91
+ d: "m21 21-4.35-4.35"
92
+ })
93
+ ]
94
+ })
95
+ })
96
+ ]
97
+ })
98
+ ]
99
+ }),
100
+ isHomePage && siteDescription && /*#__PURE__*/ _jsx("p", {
101
+ class: "site-description",
102
+ children: siteDescription
103
+ })
104
+ ]
105
+ })
106
+ }),
107
+ /*#__PURE__*/ _jsx("main", {
108
+ class: "site-main",
109
+ children: /*#__PURE__*/ _jsx("div", {
110
+ class: "site-container",
111
+ children: /*#__PURE__*/ _jsxs("div", {
112
+ class: "site-content",
113
+ children: [
114
+ isHomePage && /*#__PURE__*/ _jsx("nav", {
115
+ class: "site-browse-nav",
116
+ children: browseLinks.map((link, i)=>/*#__PURE__*/ _jsxs(_Fragment, {
117
+ children: [
118
+ i > 0 && /*#__PURE__*/ _jsx("span", {
119
+ class: "site-browse-sep",
120
+ children: "/"
121
+ }),
122
+ /*#__PURE__*/ _jsx("a", {
123
+ href: link.href,
124
+ class: `site-browse-link ${currentPath === link.href ? "site-browse-link-active" : ""}`,
125
+ children: link.label
126
+ }, link.href)
127
+ ]
128
+ }))
129
+ }),
130
+ isHomePage && isAuthenticated && /*#__PURE__*/ _jsx(ComposePrompt, {}),
131
+ children
132
+ ]
133
+ })
134
+ })
135
+ }),
136
+ isAuthenticated && /*#__PURE__*/ _jsx(ComposeDialog, {
137
+ collections: collections
138
+ })
139
+ ]
140
+ });
141
+ };
@@ -1,22 +1,18 @@
1
1
  /**
2
- * Minimal Theme - Archive Page
2
+ * Archive Page
3
3
  *
4
- * Date-first list with type filter and cursor pagination.
4
+ * Posts grouped by year-month with format filter and cursor pagination.
5
5
  */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
6
6
  import { useLingui as $_useLingui } from "@jant/core/i18n";
7
- import { POST_TYPES } from "../../../types.js";
8
- import { Pagination as DefaultPagination } from "../../../theme/components/Pagination.js";
9
- function getTypeLabel(type) {
7
+ import { FORMATS } from "../../types.js";
8
+ import { Pagination } from "../shared/Pagination.js";
9
+ function getFormatLabel(format) {
10
10
  const { i18n: $__i18n, _: $__ } = $_useLingui();
11
11
  const labels = {
12
12
  note: $__i18n._({
13
13
  id: "KiJn9B",
14
14
  message: "Note"
15
15
  }),
16
- article: $__i18n._({
17
- id: "f6e0Ry",
18
- message: "Article"
19
- }),
20
16
  link: $__i18n._({
21
17
  id: "yzF66j",
22
18
  message: "Link"
@@ -24,29 +20,17 @@ function getTypeLabel(type) {
24
20
  quote: $__i18n._({
25
21
  id: "ZhhOwV",
26
22
  message: "Quote"
27
- }),
28
- image: $__i18n._({
29
- id: "hG89Ed",
30
- message: "Image"
31
- }),
32
- page: $__i18n._({
33
- id: "6WdDG7",
34
- message: "Page"
35
23
  })
36
24
  };
37
- return labels[type] ?? type;
25
+ return labels[format] ?? format;
38
26
  }
39
- function getTypeLabelPlural(type) {
27
+ function getFormatLabelPlural(format) {
40
28
  const { i18n: $__i18n, _: $__ } = $_useLingui();
41
29
  const labels = {
42
30
  note: $__i18n._({
43
31
  id: "1DBGsz",
44
32
  message: "Notes"
45
33
  }),
46
- article: $__i18n._({
47
- id: "Tt5T6+",
48
- message: "Articles"
49
- }),
50
34
  link: $__i18n._({
51
35
  id: "Rj01Fz",
52
36
  message: "Links"
@@ -54,26 +38,19 @@ function getTypeLabelPlural(type) {
54
38
  quote: $__i18n._({
55
39
  id: "eWLklq",
56
40
  message: "Quotes"
57
- }),
58
- image: $__i18n._({
59
- id: "an5hVd",
60
- message: "Images"
61
- }),
62
- page: $__i18n._({
63
- id: "wRR604",
64
- message: "Pages"
65
41
  })
66
42
  };
67
- return labels[type] ?? `${type}s`;
43
+ return labels[format] ?? format + "s";
68
44
  }
69
- export const ArchivePage = ({ groups, hasMore, nextCursor, type, theme })=>{
45
+ export const ArchivePage = ({ groups, hasMore, nextCursor, format, featured })=>{
70
46
  const { i18n: $__i18n, _: $__ } = $_useLingui();
71
- const title = type ? getTypeLabelPlural(type) : $__i18n._({
47
+ const title = format ? getFormatLabelPlural(format) : $__i18n._({
72
48
  id: "B495Gs",
73
49
  message: "Archive"
74
50
  });
75
- const PaginationComponent = theme?.Pagination ?? DefaultPagination;
76
51
  return /*#__PURE__*/ _jsxs("div", {
52
+ class: "py-6",
53
+ "data-page": "archive",
77
54
  children: [
78
55
  /*#__PURE__*/ _jsxs("header", {
79
56
  class: "mb-8",
@@ -87,17 +64,25 @@ export const ArchivePage = ({ groups, hasMore, nextCursor, type, theme })=>{
87
64
  children: [
88
65
  /*#__PURE__*/ _jsx("a", {
89
66
  href: "/archive",
90
- class: `text-sm ${!type ? "font-medium text-foreground" : "text-muted-foreground hover:text-foreground"}`,
67
+ class: "badge " + (!format && !featured ? "badge-primary" : "badge-outline"),
91
68
  children: $__i18n._({
92
69
  id: "N40H+G",
93
70
  message: "All"
94
71
  })
95
72
  }),
96
- POST_TYPES.filter((t)=>t !== "page").map((typeKey)=>/*#__PURE__*/ _jsx("a", {
97
- href: `/archive?type=${typeKey}`,
98
- class: `text-sm ${type === typeKey ? "font-medium text-foreground" : "text-muted-foreground hover:text-foreground"}`,
99
- children: getTypeLabelPlural(typeKey)
100
- }, typeKey))
73
+ FORMATS.map((formatKey)=>/*#__PURE__*/ _jsx("a", {
74
+ href: "/archive?format=" + formatKey,
75
+ class: "badge " + (format === formatKey ? "badge-primary" : "badge-outline"),
76
+ children: getFormatLabelPlural(formatKey)
77
+ }, formatKey)),
78
+ /*#__PURE__*/ _jsx("a", {
79
+ href: "/archive?featured=true",
80
+ class: "badge " + (featured ? "badge-primary" : "badge-outline"),
81
+ children: $__i18n._({
82
+ id: "FkMol5",
83
+ message: "Featured"
84
+ })
85
+ })
101
86
  ]
102
87
  })
103
88
  ]
@@ -117,9 +102,11 @@ export const ArchivePage = ({ groups, hasMore, nextCursor, type, theme })=>{
117
102
  children: group.label
118
103
  }),
119
104
  /*#__PURE__*/ _jsx("div", {
120
- class: "flex flex-col gap-3",
105
+ class: "divide-y divide-border",
121
106
  children: group.posts.map((post)=>/*#__PURE__*/ _jsxs("article", {
122
- class: "flex items-baseline gap-4",
107
+ class: "flex items-baseline gap-4 py-2.5",
108
+ "data-post": true,
109
+ "data-format": post.format,
123
110
  children: [
124
111
  /*#__PURE__*/ _jsx("time", {
125
112
  class: "text-sm text-muted-foreground w-12 shrink-0",
@@ -132,11 +119,11 @@ export const ArchivePage = ({ groups, hasMore, nextCursor, type, theme })=>{
132
119
  /*#__PURE__*/ _jsx("a", {
133
120
  href: post.permalink,
134
121
  class: "hover:underline",
135
- children: post.title || post.content?.slice(0, 80) || `Post #${post.id}`
122
+ children: post.title || post.excerpt?.slice(0, 80) || "Post #" + post.id
136
123
  }),
137
- !type && /*#__PURE__*/ _jsx("span", {
138
- class: "ml-2 text-xs text-muted-foreground",
139
- children: getTypeLabel(post.type)
124
+ !format && /*#__PURE__*/ _jsx("span", {
125
+ class: "ml-2 badge-outline text-xs",
126
+ children: getFormatLabel(post.format)
140
127
  })
141
128
  ]
142
129
  })
@@ -144,10 +131,10 @@ export const ArchivePage = ({ groups, hasMore, nextCursor, type, theme })=>{
144
131
  }, post.id))
145
132
  })
146
133
  ]
147
- }, `${group.year}-${group.month}`))
134
+ }, group.year + "-" + group.month))
148
135
  }),
149
- /*#__PURE__*/ _jsx(PaginationComponent, {
150
- baseUrl: type ? `/archive?type=${type}` : "/archive",
136
+ /*#__PURE__*/ _jsx(Pagination, {
137
+ baseUrl: format ? "/archive?format=" + format : featured ? "/archive?featured=true" : "/archive",
151
138
  hasMore: hasMore,
152
139
  nextCursor: nextCursor
153
140
  })
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Collection Page
3
+ *
4
+ * Collection header with divider-separated post list.
5
+ */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
6
+ import { useLingui as $_useLingui } from "@jant/core/i18n";
7
+ export const CollectionPage = ({ collection, posts })=>{
8
+ const { i18n: $__i18n, _: $__ } = $_useLingui();
9
+ return /*#__PURE__*/ _jsxs("div", {
10
+ class: "py-6",
11
+ "data-page": "collection",
12
+ children: [
13
+ /*#__PURE__*/ _jsxs("header", {
14
+ class: "mb-8",
15
+ children: [
16
+ /*#__PURE__*/ _jsx("h1", {
17
+ class: "text-2xl font-semibold",
18
+ children: collection.title
19
+ }),
20
+ collection.description && /*#__PURE__*/ _jsx("p", {
21
+ class: "text-muted-foreground mt-2",
22
+ children: collection.description
23
+ })
24
+ ]
25
+ }),
26
+ /*#__PURE__*/ _jsx("main", {
27
+ children: posts.length === 0 ? /*#__PURE__*/ _jsx("p", {
28
+ class: "text-muted-foreground",
29
+ children: $__i18n._({
30
+ id: "J4FNfC",
31
+ message: "No posts in this collection."
32
+ })
33
+ }) : /*#__PURE__*/ _jsx("div", {
34
+ class: "divide-y divide-border",
35
+ children: posts.map((post)=>/*#__PURE__*/ _jsxs("article", {
36
+ class: "h-entry py-4",
37
+ "data-post": true,
38
+ "data-format": post.format,
39
+ children: [
40
+ post.title && /*#__PURE__*/ _jsx("h2", {
41
+ class: "p-name text-lg font-medium mb-2",
42
+ children: /*#__PURE__*/ _jsx("a", {
43
+ href: post.permalink,
44
+ class: "u-url hover:underline",
45
+ children: post.title
46
+ })
47
+ }),
48
+ /*#__PURE__*/ _jsx("div", {
49
+ class: "e-content prose prose-sm",
50
+ "data-post-body": true,
51
+ dangerouslySetInnerHTML: {
52
+ __html: post.bodyHtml || ""
53
+ }
54
+ }),
55
+ /*#__PURE__*/ _jsx("footer", {
56
+ class: "mt-2 text-sm text-muted-foreground",
57
+ "data-post-meta": true,
58
+ children: /*#__PURE__*/ _jsx("time", {
59
+ class: "dt-published",
60
+ datetime: post.publishedAt,
61
+ children: post.publishedAtFormatted
62
+ })
63
+ })
64
+ ]
65
+ }, post.id))
66
+ })
67
+ })
68
+ ]
69
+ });
70
+ };