@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,107 +0,0 @@
1
- /**
2
- * Media Gallery Component
3
- *
4
- * Renders media attachments on public post pages.
5
- * Layout adapts based on the number of images.
6
- */ import { jsx as _jsx, jsxs as _jsxs } 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
- if (images.length === 1) {
11
- const [img] = images;
12
- if (!img) return null;
13
- return /*#__PURE__*/ _jsx("div", {
14
- class: "mt-3",
15
- children: /*#__PURE__*/ _jsx("a", {
16
- href: img.url,
17
- target: "_blank",
18
- rel: "noopener noreferrer",
19
- children: /*#__PURE__*/ _jsx("img", {
20
- src: img.thumbnailUrl,
21
- alt: img.altText || "",
22
- width: img.width ?? undefined,
23
- height: img.height ?? undefined,
24
- class: "rounded-lg max-w-full h-auto",
25
- loading: "lazy"
26
- })
27
- })
28
- });
29
- }
30
- if (images.length === 2) {
31
- return /*#__PURE__*/ _jsx("div", {
32
- class: "mt-3 grid grid-cols-2 gap-1 rounded-lg overflow-hidden",
33
- children: images.map((img)=>/*#__PURE__*/ _jsx("a", {
34
- href: img.url,
35
- target: "_blank",
36
- rel: "noopener noreferrer",
37
- class: "aspect-square",
38
- children: /*#__PURE__*/ _jsx("img", {
39
- src: img.thumbnailUrl,
40
- alt: img.altText || "",
41
- class: "w-full h-full object-cover",
42
- loading: "lazy"
43
- })
44
- }, img.id))
45
- });
46
- }
47
- if (images.length === 3) {
48
- const [first, ...rest] = images;
49
- if (!first) return null;
50
- return /*#__PURE__*/ _jsxs("div", {
51
- class: "mt-3 grid grid-cols-2 gap-1 rounded-lg overflow-hidden",
52
- children: [
53
- /*#__PURE__*/ _jsx("a", {
54
- href: first.url,
55
- target: "_blank",
56
- rel: "noopener noreferrer",
57
- class: "row-span-2",
58
- children: /*#__PURE__*/ _jsx("img", {
59
- src: first.thumbnailUrl,
60
- alt: first.altText || "",
61
- class: "w-full h-full object-cover",
62
- loading: "lazy"
63
- })
64
- }),
65
- rest.map((img)=>/*#__PURE__*/ _jsx("a", {
66
- href: img.url,
67
- target: "_blank",
68
- rel: "noopener noreferrer",
69
- class: "aspect-square",
70
- children: /*#__PURE__*/ _jsx("img", {
71
- src: img.thumbnailUrl,
72
- alt: img.altText || "",
73
- class: "w-full h-full object-cover",
74
- loading: "lazy"
75
- })
76
- }, img.id))
77
- ]
78
- });
79
- }
80
- // 4+ images: 2-column grid, show first 4 with remaining count
81
- const shown = images.slice(0, 4);
82
- const remaining = images.length - 4;
83
- return /*#__PURE__*/ _jsx("div", {
84
- class: "mt-3 grid grid-cols-2 gap-1 rounded-lg overflow-hidden",
85
- children: shown.map((img, i)=>/*#__PURE__*/ _jsxs("a", {
86
- href: img.url,
87
- target: "_blank",
88
- rel: "noopener noreferrer",
89
- class: "relative aspect-square",
90
- children: [
91
- /*#__PURE__*/ _jsx("img", {
92
- src: img.thumbnailUrl,
93
- alt: img.altText || "",
94
- class: "w-full h-full object-cover",
95
- loading: "lazy"
96
- }),
97
- i === 3 && remaining > 0 && /*#__PURE__*/ _jsxs("div", {
98
- class: "absolute inset-0 bg-black/50 flex items-center justify-center text-white text-xl font-semibold",
99
- children: [
100
- "+",
101
- remaining
102
- ]
103
- })
104
- ]
105
- }, img.id))
106
- });
107
- };
@@ -1,37 +0,0 @@
1
- /**
2
- * Visibility Badge Component
3
- *
4
- * Displays a badge indicating the visibility level of a post
5
- */ import { jsx as _jsx } from "hono/jsx/jsx-runtime";
6
- import { useLingui as $_useLingui } from "@jant/core/i18n";
7
- export const VisibilityBadge = ({ visibility })=>{
8
- const { i18n: $__i18n, _: $__ } = $_useLingui();
9
- const variants = {
10
- featured: "badge-primary",
11
- quiet: "badge-secondary",
12
- unlisted: "badge-outline",
13
- draft: "badge-outline"
14
- };
15
- const labels = {
16
- featured: $__i18n._({
17
- id: "FkMol5",
18
- message: "Featured"
19
- }),
20
- quiet: $__i18n._({
21
- id: "r1MpXi",
22
- message: "Quiet"
23
- }),
24
- unlisted: $__i18n._({
25
- id: "WDcQq9",
26
- message: "Unlisted"
27
- }),
28
- draft: $__i18n._({
29
- id: "eneWvv",
30
- message: "Draft"
31
- })
32
- };
33
- return /*#__PURE__*/ _jsx("span", {
34
- class: variants[visibility],
35
- children: labels[visibility]
36
- });
37
- };
@@ -1,18 +0,0 @@
1
- /**
2
- * Jant Theme - Shared Infrastructure
3
- *
4
- * Exports shared layouts, components, and color themes used by all themes.
5
- * Individual theme packages (minimal, card, etc.) import from here.
6
- *
7
- * @example
8
- * ```typescript
9
- * // In a theme package:
10
- * import { MediaGallery, Pagination } from "@jant/core/theme";
11
- * import type { ColorTheme } from "@jant/core/theme";
12
- * ```
13
- */ // Layout components (BaseLayout, DashLayout)
14
- export * from "./layouts/index.js";
15
- // Shared UI components (MediaGallery, Pagination, EmptyState, etc.)
16
- export * from "./components/index.js";
17
- // Color themes
18
- export * from "./color-themes.js";
@@ -1,2 +0,0 @@
1
- export { BaseLayout } from "./BaseLayout.js";
2
- export { DashLayout } from "./DashLayout.js";
@@ -1,83 +0,0 @@
1
- /**
2
- * Minimal Theme - Site Layout
3
- *
4
- * Single-column, centered layout with horizontal nav.
5
- * Inspired by Tufte CSS and Manton.org.
6
- */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
7
- function NavLinks({ links }) {
8
- return /*#__PURE__*/ _jsx(_Fragment, {
9
- children: links.map((link)=>/*#__PURE__*/ _jsxs("a", {
10
- href: link.url,
11
- class: `text-sm ${link.isActive ? "text-foreground font-medium" : "text-muted-foreground hover:text-foreground"}`,
12
- ...link.isExternal ? {
13
- target: "_blank",
14
- rel: "noopener noreferrer"
15
- } : {},
16
- children: [
17
- link.label,
18
- link.isExternal && /*#__PURE__*/ _jsx("span", {
19
- class: "ml-0.5 text-xs opacity-50",
20
- children: "↗"
21
- })
22
- ]
23
- }, link.id))
24
- });
25
- }
26
- export const SiteLayout = ({ siteName, links, children })=>{
27
- return /*#__PURE__*/ _jsxs("div", {
28
- class: "max-w-2xl mx-auto px-4 py-8",
29
- "data-signals": JSON.stringify({
30
- _menuOpen: false
31
- }),
32
- children: [
33
- /*#__PURE__*/ _jsxs("header", {
34
- class: "mb-12",
35
- children: [
36
- /*#__PURE__*/ _jsxs("div", {
37
- class: "flex items-center justify-between",
38
- children: [
39
- /*#__PURE__*/ _jsx("a", {
40
- href: "/",
41
- class: "text-xl font-semibold",
42
- children: siteName
43
- }),
44
- links.length > 0 && /*#__PURE__*/ _jsx("button", {
45
- "data-on:click": "$_menuOpen = !$_menuOpen",
46
- class: "p-2 -mr-2 text-muted-foreground hover:text-foreground sm:hidden",
47
- "aria-label": "Toggle menu",
48
- children: /*#__PURE__*/ _jsx("svg", {
49
- class: "size-5",
50
- fill: "none",
51
- viewBox: "0 0 24 24",
52
- "stroke-width": "1.5",
53
- stroke: "currentColor",
54
- children: /*#__PURE__*/ _jsx("path", {
55
- "stroke-linecap": "round",
56
- "stroke-linejoin": "round",
57
- d: "M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
58
- })
59
- })
60
- })
61
- ]
62
- }),
63
- links.length > 0 && /*#__PURE__*/ _jsx("nav", {
64
- class: "hidden sm:flex flex-wrap gap-x-4 gap-y-1 mt-3",
65
- children: /*#__PURE__*/ _jsx(NavLinks, {
66
- links: links
67
- })
68
- }),
69
- links.length > 0 && /*#__PURE__*/ _jsx("nav", {
70
- class: "sm:hidden flex flex-col gap-1 mt-3 overflow-hidden",
71
- "data-show": "$_menuOpen",
72
- children: /*#__PURE__*/ _jsx(NavLinks, {
73
- links: links
74
- })
75
- })
76
- ]
77
- }),
78
- /*#__PURE__*/ _jsx("main", {
79
- children: children
80
- })
81
- ]
82
- });
83
- };
@@ -1,65 +0,0 @@
1
- /**
2
- * Minimal Theme
3
- *
4
- * A content-first, borderless theme inspired by Tufte CSS and Manton.org.
5
- * Single-column layout with serif-friendly typography and generous whitespace.
6
- *
7
- * This is the default theme for Jant.
8
- */ // Layout
9
- import { SiteLayout } from "./MinimalSiteLayout.js";
10
- // Pages
11
- import { HomePage } from "./pages/HomePage.js";
12
- import { PostPage } from "./pages/PostPage.js";
13
- import { SinglePage } from "./pages/SinglePage.js";
14
- import { ArchivePage } from "./pages/ArchivePage.js";
15
- import { SearchPage } from "./pages/SearchPage.js";
16
- import { CollectionPage } from "./pages/CollectionPage.js";
17
- // Timeline
18
- import { NoteCard } from "./timeline/NoteCard.js";
19
- import { ArticleCard } from "./timeline/ArticleCard.js";
20
- import { LinkCard } from "./timeline/LinkCard.js";
21
- import { QuoteCard } from "./timeline/QuoteCard.js";
22
- import { ImageCard } from "./timeline/ImageCard.js";
23
- import { ThreadPreview } from "./timeline/ThreadPreview.js";
24
- import { TimelineFeed } from "./timeline/TimelineFeed.js";
25
- /**
26
- * Create the minimal theme configuration.
27
- *
28
- * @param options - Optional overrides for components, CSS variables, or color themes
29
- * @returns A JantTheme configuration object
30
- *
31
- * @example
32
- * ```typescript
33
- * import { createApp } from "@jant/core";
34
- * import { minimalTheme } from "@jant/core";
35
- *
36
- * export default createApp({
37
- * theme: minimalTheme(), // re-exported as minimalTheme from @jant/core
38
- * });
39
- * ```
40
- */ export function theme(options) {
41
- return {
42
- name: "minimal",
43
- components: {
44
- SiteLayout,
45
- HomePage,
46
- PostPage,
47
- SinglePage,
48
- ArchivePage,
49
- SearchPage,
50
- CollectionPage,
51
- NoteCard,
52
- ArticleCard,
53
- LinkCard,
54
- QuoteCard,
55
- ImageCard,
56
- ThreadPreview,
57
- TimelineFeed,
58
- ...options?.components
59
- },
60
- cssVariables: {
61
- ...options?.cssVariables
62
- },
63
- colorThemes: options?.colorThemes
64
- };
65
- }
@@ -1,65 +0,0 @@
1
- /**
2
- * Minimal Theme - Collection Page
3
- *
4
- * Simple list of posts in a collection.
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
- children: [
11
- /*#__PURE__*/ _jsxs("header", {
12
- class: "mb-8",
13
- children: [
14
- /*#__PURE__*/ _jsx("h1", {
15
- class: "text-2xl font-semibold",
16
- children: collection.title
17
- }),
18
- collection.description && /*#__PURE__*/ _jsx("p", {
19
- class: "text-muted-foreground mt-2",
20
- children: collection.description
21
- })
22
- ]
23
- }),
24
- /*#__PURE__*/ _jsx("main", {
25
- class: "flex flex-col",
26
- children: posts.length === 0 ? /*#__PURE__*/ _jsx("p", {
27
- class: "text-muted-foreground",
28
- children: $__i18n._({
29
- id: "J4FNfC",
30
- message: "No posts in this collection."
31
- })
32
- }) : posts.map((post, i)=>/*#__PURE__*/ _jsxs("article", {
33
- class: "h-entry",
34
- children: [
35
- i > 0 && /*#__PURE__*/ _jsx("hr", {
36
- class: "my-6 border-border"
37
- }),
38
- post.title && /*#__PURE__*/ _jsx("h2", {
39
- class: "p-name text-lg font-medium mb-2",
40
- children: /*#__PURE__*/ _jsx("a", {
41
- href: post.permalink,
42
- class: "u-url hover:underline",
43
- children: post.title
44
- })
45
- }),
46
- /*#__PURE__*/ _jsx("div", {
47
- class: "e-content prose prose-sm",
48
- dangerouslySetInnerHTML: {
49
- __html: post.contentHtml || ""
50
- }
51
- }),
52
- /*#__PURE__*/ _jsx("footer", {
53
- class: "mt-2 text-sm text-muted-foreground",
54
- children: /*#__PURE__*/ _jsx("time", {
55
- class: "dt-published",
56
- datetime: post.publishedAt,
57
- children: post.publishedAtFormatted
58
- })
59
- })
60
- ]
61
- }, post.id))
62
- })
63
- ]
64
- });
65
- };
@@ -1,25 +0,0 @@
1
- /**
2
- * Minimal Theme - Home Page
3
- *
4
- * Renders the timeline feed with thread previews.
5
- */ import { jsx as _jsx, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
6
- import { useLingui as $_useLingui } from "@jant/core/i18n";
7
- import { TimelineFeed as DefaultTimelineFeed } from "../timeline/TimelineFeed.js";
8
- export const HomePage = ({ items, hasMore, nextCursor, theme })=>{
9
- const { i18n: $__i18n, _: $__ } = $_useLingui();
10
- const Feed = theme?.TimelineFeed ?? DefaultTimelineFeed;
11
- return /*#__PURE__*/ _jsx(_Fragment, {
12
- children: items.length === 0 ? /*#__PURE__*/ _jsx("p", {
13
- class: "text-muted-foreground",
14
- children: $__i18n._({
15
- id: "ODiSoW",
16
- message: "No posts yet."
17
- })
18
- }) : /*#__PURE__*/ _jsx(Feed, {
19
- items: items,
20
- hasMore: hasMore,
21
- nextCursor: nextCursor,
22
- theme: theme
23
- })
24
- });
25
- };
@@ -1,36 +0,0 @@
1
- /**
2
- * Minimal Theme - Article Card
3
- *
4
- * Title + excerpt, borderless, for type="article" posts.
5
- */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
6
- export const ArticleCard = ({ post, compact })=>{
7
- return /*#__PURE__*/ _jsxs("article", {
8
- class: `h-entry${compact ? " text-sm" : ""}`,
9
- children: [
10
- post.title && /*#__PURE__*/ _jsx("h2", {
11
- class: `p-name font-semibold ${compact ? "text-sm" : "text-lg"}`,
12
- children: /*#__PURE__*/ _jsx("a", {
13
- href: post.permalink,
14
- class: "u-url hover:underline",
15
- children: post.title
16
- })
17
- }),
18
- !compact && post.excerpt && /*#__PURE__*/ _jsx("p", {
19
- class: "e-content text-muted-foreground mt-1 line-clamp-3",
20
- children: post.excerpt
21
- }),
22
- /*#__PURE__*/ _jsx("footer", {
23
- class: "mt-2",
24
- children: /*#__PURE__*/ _jsx("a", {
25
- href: post.permalink,
26
- class: "u-url text-xs text-muted-foreground hover:text-foreground",
27
- children: /*#__PURE__*/ _jsx("time", {
28
- class: "dt-published",
29
- datetime: post.publishedAt,
30
- children: post.publishedAtFormatted
31
- })
32
- })
33
- })
34
- ]
35
- });
36
- };
@@ -1,67 +0,0 @@
1
- /**
2
- * Minimal Theme - Image Card
3
- *
4
- * Inline images with no card frame for type="image" posts.
5
- */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
6
- import { MediaGallery } from "../../../theme/components/MediaGallery.js";
7
- export const ImageCard = ({ post, compact })=>{
8
- if (compact) {
9
- return /*#__PURE__*/ _jsxs("article", {
10
- class: "h-entry text-sm",
11
- children: [
12
- post.title && /*#__PURE__*/ _jsx("h2", {
13
- class: "p-name font-medium text-sm",
14
- children: /*#__PURE__*/ _jsx("a", {
15
- href: post.permalink,
16
- class: "u-url hover:underline",
17
- children: post.title
18
- })
19
- }),
20
- post.contentHtml && /*#__PURE__*/ _jsx("div", {
21
- class: "e-content prose prose-sm text-muted-foreground",
22
- dangerouslySetInnerHTML: {
23
- __html: post.contentHtml
24
- }
25
- }),
26
- /*#__PURE__*/ _jsx("footer", {
27
- class: "mt-1",
28
- children: /*#__PURE__*/ _jsx("a", {
29
- href: post.permalink,
30
- class: "u-url text-xs text-muted-foreground hover:text-foreground",
31
- children: /*#__PURE__*/ _jsx("time", {
32
- class: "dt-published",
33
- datetime: post.publishedAt,
34
- children: post.publishedAtFormatted
35
- })
36
- })
37
- })
38
- ]
39
- });
40
- }
41
- return /*#__PURE__*/ _jsxs("article", {
42
- class: "h-entry",
43
- children: [
44
- post.contentHtml && /*#__PURE__*/ _jsx("div", {
45
- class: "e-content prose prose-sm",
46
- dangerouslySetInnerHTML: {
47
- __html: post.contentHtml
48
- }
49
- }),
50
- post.media.length > 0 && /*#__PURE__*/ _jsx(MediaGallery, {
51
- attachments: post.media
52
- }),
53
- /*#__PURE__*/ _jsx("footer", {
54
- class: "mt-2",
55
- children: /*#__PURE__*/ _jsx("a", {
56
- href: post.permalink,
57
- class: "u-url text-xs text-muted-foreground hover:text-foreground",
58
- children: /*#__PURE__*/ _jsx("time", {
59
- class: "dt-published",
60
- datetime: post.publishedAt,
61
- children: post.publishedAtFormatted
62
- })
63
- })
64
- })
65
- ]
66
- });
67
- };
@@ -1,47 +0,0 @@
1
- /**
2
- * Minimal Theme - Link Card
3
- *
4
- * Subtle external link indicator for type="link" posts.
5
- */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
6
- export const LinkCard = ({ post, compact })=>{
7
- return /*#__PURE__*/ _jsxs("article", {
8
- class: `h-entry${compact ? " text-sm" : ""}`,
9
- children: [
10
- post.title && /*#__PURE__*/ _jsx("h2", {
11
- class: `p-name font-semibold ${compact ? "text-sm" : "text-base"}`,
12
- children: /*#__PURE__*/ _jsx("a", {
13
- href: post.sourceUrl || post.permalink,
14
- class: "u-url hover:underline",
15
- target: post.sourceUrl ? "_blank" : undefined,
16
- rel: post.sourceUrl ? "noopener noreferrer" : undefined,
17
- children: post.title
18
- })
19
- }),
20
- post.sourceDomain && /*#__PURE__*/ _jsxs("div", {
21
- class: "text-xs text-muted-foreground mt-0.5",
22
- children: [
23
- "↗ ",
24
- post.sourceDomain
25
- ]
26
- }),
27
- !compact && post.contentHtml && /*#__PURE__*/ _jsx("div", {
28
- class: "e-content prose prose-sm text-muted-foreground mt-1",
29
- dangerouslySetInnerHTML: {
30
- __html: post.contentHtml
31
- }
32
- }),
33
- /*#__PURE__*/ _jsx("footer", {
34
- class: "mt-2",
35
- children: /*#__PURE__*/ _jsx("a", {
36
- href: post.permalink,
37
- class: "text-xs text-muted-foreground hover:text-foreground",
38
- children: /*#__PURE__*/ _jsx("time", {
39
- class: "dt-published",
40
- datetime: post.publishedAt,
41
- children: post.publishedAtFormatted
42
- })
43
- })
44
- })
45
- ]
46
- });
47
- };
@@ -1,34 +0,0 @@
1
- /**
2
- * Minimal Theme - Note Card
3
- *
4
- * Borderless, content-first card for type="note" posts.
5
- */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
6
- import { MediaGallery } from "../../../theme/components/MediaGallery.js";
7
- export const NoteCard = ({ post, compact })=>{
8
- return /*#__PURE__*/ _jsxs("article", {
9
- class: `h-entry${compact ? " text-sm" : ""}`,
10
- children: [
11
- post.contentHtml && /*#__PURE__*/ _jsx("div", {
12
- class: `e-content prose ${compact ? "prose-sm" : ""}`,
13
- dangerouslySetInnerHTML: {
14
- __html: post.contentHtml
15
- }
16
- }),
17
- !compact && post.media.length > 0 && /*#__PURE__*/ _jsx(MediaGallery, {
18
- attachments: post.media
19
- }),
20
- /*#__PURE__*/ _jsx("footer", {
21
- class: "mt-2",
22
- children: /*#__PURE__*/ _jsx("a", {
23
- href: post.permalink,
24
- class: "u-url text-xs text-muted-foreground hover:text-foreground",
25
- children: /*#__PURE__*/ _jsx("time", {
26
- class: "dt-published",
27
- datetime: post.publishedAt,
28
- children: post.publishedAtFormatted
29
- })
30
- })
31
- })
32
- ]
33
- });
34
- };
@@ -1,48 +0,0 @@
1
- /**
2
- * Minimal Theme - Timeline Feed
3
- *
4
- * Divider-separated stream of posts with load-more button.
5
- */ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
6
- import { useLingui as $_useLingui } from "@jant/core/i18n";
7
- import { TimelineItem } from "./TimelineItem.js";
8
- import { ThreadPreview as DefaultThreadPreview } from "./ThreadPreview.js";
9
- export const TimelineFeed = ({ items, hasMore, nextCursor, theme })=>{
10
- const { i18n: $__i18n, _: $__ } = $_useLingui();
11
- const ResolvedThreadPreview = theme?.ThreadPreview ?? DefaultThreadPreview;
12
- return /*#__PURE__*/ _jsxs("div", {
13
- children: [
14
- /*#__PURE__*/ _jsx("div", {
15
- id: "timeline-feed",
16
- class: "flex flex-col",
17
- children: items.map((item, i)=>/*#__PURE__*/ _jsxs("div", {
18
- children: [
19
- i > 0 && /*#__PURE__*/ _jsx("hr", {
20
- class: "my-6 border-border"
21
- }),
22
- item.threadPreview ? /*#__PURE__*/ _jsx(ResolvedThreadPreview, {
23
- rootPost: item.post,
24
- previewReplies: item.threadPreview.replies,
25
- totalReplyCount: item.threadPreview.totalReplyCount,
26
- theme: theme
27
- }) : /*#__PURE__*/ _jsx(TimelineItem, {
28
- item: item,
29
- theme: theme
30
- })
31
- ]
32
- }, item.post.id))
33
- }),
34
- hasMore && nextCursor && /*#__PURE__*/ _jsx("div", {
35
- id: "load-more-container",
36
- class: "mt-8 text-center",
37
- children: /*#__PURE__*/ _jsx("button", {
38
- class: "text-sm text-muted-foreground hover:text-foreground hover:underline",
39
- "data-on:click": `@get('/api/timeline?cursor=${nextCursor}')`,
40
- children: $__i18n._({
41
- id: "yQ2kGp",
42
- message: "Load more"
43
- })
44
- })
45
- })
46
- ]
47
- });
48
- };