@jant/core 0.3.23 → 0.3.24

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 (169) hide show
  1. package/dist/app.js +4 -5
  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 +3 -3
  7. package/dist/lib/constants.js +1 -4
  8. package/dist/lib/excerpt.js +76 -0
  9. package/dist/lib/feed.js +18 -7
  10. package/dist/lib/navigation.js +4 -5
  11. package/dist/lib/render.js +1 -1
  12. package/dist/lib/schemas.js +80 -38
  13. package/dist/lib/theme-components.js +8 -11
  14. package/dist/lib/time.js +56 -1
  15. package/dist/lib/timeline.js +119 -0
  16. package/dist/lib/view.js +61 -72
  17. package/dist/routes/api/posts.js +29 -35
  18. package/dist/routes/api/search.js +5 -6
  19. package/dist/routes/api/upload.js +13 -13
  20. package/dist/routes/dash/collections.js +22 -40
  21. package/dist/routes/dash/index.js +2 -2
  22. package/dist/routes/dash/navigation.js +25 -24
  23. package/dist/routes/dash/pages.js +42 -57
  24. package/dist/routes/dash/posts.js +27 -35
  25. package/dist/routes/feed/rss.js +2 -4
  26. package/dist/routes/feed/sitemap.js +10 -7
  27. package/dist/routes/pages/archive.js +12 -11
  28. package/dist/routes/pages/collection.js +11 -5
  29. package/dist/routes/pages/home.js +53 -61
  30. package/dist/routes/pages/page.js +60 -29
  31. package/dist/routes/pages/post.js +5 -12
  32. package/dist/routes/pages/search.js +3 -4
  33. package/dist/services/collection.js +52 -64
  34. package/dist/services/index.js +5 -3
  35. package/dist/services/navigation.js +29 -53
  36. package/dist/services/page.js +80 -0
  37. package/dist/services/post.js +68 -69
  38. package/dist/services/search.js +24 -18
  39. package/dist/theme/components/MediaGallery.js +19 -91
  40. package/dist/theme/components/PageForm.js +15 -15
  41. package/dist/theme/components/PostForm.js +136 -129
  42. package/dist/theme/components/PostList.js +13 -8
  43. package/dist/theme/components/ThreadView.js +3 -3
  44. package/dist/theme/components/TypeBadge.js +3 -14
  45. package/dist/theme/components/VisibilityBadge.js +33 -23
  46. package/dist/themes/threads/ThreadsSiteLayout.js +172 -0
  47. package/dist/themes/threads/index.js +81 -0
  48. package/dist/themes/{minimal → threads}/pages/ArchivePage.js +32 -47
  49. package/dist/themes/threads/pages/CollectionPage.js +65 -0
  50. package/dist/themes/{minimal → threads}/pages/HomePage.js +3 -3
  51. package/dist/themes/{minimal → threads}/pages/PostPage.js +12 -9
  52. package/dist/themes/{minimal → threads}/pages/SearchPage.js +13 -14
  53. package/dist/themes/{minimal → threads}/pages/SinglePage.js +4 -4
  54. package/dist/themes/threads/timeline/LinkCard.js +68 -0
  55. package/dist/themes/threads/timeline/NoteCard.js +53 -0
  56. package/dist/themes/threads/timeline/QuoteCard.js +59 -0
  57. package/dist/themes/{minimal → threads}/timeline/ThreadPreview.js +17 -13
  58. package/dist/themes/threads/timeline/TimelineFeed.js +58 -0
  59. package/dist/themes/{minimal → threads}/timeline/TimelineItem.js +8 -16
  60. package/dist/themes/threads/timeline/TimelineLoadMore.js +23 -0
  61. package/dist/themes/threads/timeline/groupByDate.js +22 -0
  62. package/dist/themes/threads/timeline/timelineMore.js +107 -0
  63. package/dist/types.js +24 -40
  64. package/package.json +2 -1
  65. package/src/__tests__/helpers/app.ts +4 -0
  66. package/src/__tests__/helpers/db.ts +51 -74
  67. package/src/app.tsx +4 -6
  68. package/src/db/migrations/0005_v2_schema_migration.sql +268 -0
  69. package/src/db/migrations/meta/_journal.json +7 -0
  70. package/src/db/schema.ts +63 -46
  71. package/src/i18n/locales/en.po +216 -164
  72. package/src/i18n/locales/en.ts +1 -1
  73. package/src/i18n/locales/zh-Hans.po +216 -164
  74. package/src/i18n/locales/zh-Hans.ts +1 -1
  75. package/src/i18n/locales/zh-Hant.po +216 -164
  76. package/src/i18n/locales/zh-Hant.ts +1 -1
  77. package/src/index.ts +28 -12
  78. package/src/lib/__tests__/excerpt.test.ts +125 -0
  79. package/src/lib/__tests__/schemas.test.ts +166 -105
  80. package/src/lib/__tests__/theme-components.test.ts +4 -25
  81. package/src/lib/__tests__/time.test.ts +62 -0
  82. package/src/{routes/api → lib}/__tests__/timeline.test.ts +108 -66
  83. package/src/lib/__tests__/view.test.ts +199 -51
  84. package/src/lib/constants.ts +1 -4
  85. package/src/lib/excerpt.ts +87 -0
  86. package/src/lib/feed.ts +22 -7
  87. package/src/lib/navigation.ts +6 -7
  88. package/src/lib/render.tsx +1 -1
  89. package/src/lib/schemas.ts +118 -52
  90. package/src/lib/theme-components.ts +10 -13
  91. package/src/lib/time.ts +64 -0
  92. package/src/lib/timeline.ts +170 -0
  93. package/src/lib/view.ts +80 -82
  94. package/src/preset.css +45 -0
  95. package/src/routes/api/__tests__/posts.test.ts +50 -108
  96. package/src/routes/api/__tests__/search.test.ts +2 -3
  97. package/src/routes/api/posts.ts +30 -30
  98. package/src/routes/api/search.ts +4 -4
  99. package/src/routes/api/upload.ts +16 -6
  100. package/src/routes/dash/collections.tsx +18 -40
  101. package/src/routes/dash/index.tsx +2 -2
  102. package/src/routes/dash/navigation.tsx +27 -26
  103. package/src/routes/dash/pages.tsx +45 -60
  104. package/src/routes/dash/posts.tsx +44 -52
  105. package/src/routes/feed/rss.ts +2 -1
  106. package/src/routes/feed/sitemap.ts +14 -4
  107. package/src/routes/pages/archive.tsx +14 -10
  108. package/src/routes/pages/collection.tsx +17 -6
  109. package/src/routes/pages/home.tsx +56 -81
  110. package/src/routes/pages/page.tsx +64 -27
  111. package/src/routes/pages/post.tsx +5 -14
  112. package/src/routes/pages/search.tsx +2 -2
  113. package/src/services/__tests__/collection.test.ts +257 -158
  114. package/src/services/__tests__/media.test.ts +18 -18
  115. package/src/services/__tests__/navigation.test.ts +161 -87
  116. package/src/services/__tests__/post-timeline.test.ts +92 -88
  117. package/src/services/__tests__/post.test.ts +342 -206
  118. package/src/services/__tests__/search.test.ts +19 -25
  119. package/src/services/collection.ts +71 -113
  120. package/src/services/index.ts +9 -8
  121. package/src/services/navigation.ts +38 -71
  122. package/src/services/page.ts +124 -0
  123. package/src/services/post.ts +93 -103
  124. package/src/services/search.ts +38 -27
  125. package/src/theme/components/MediaGallery.tsx +27 -96
  126. package/src/theme/components/PageForm.tsx +21 -21
  127. package/src/theme/components/PostForm.tsx +122 -118
  128. package/src/theme/components/PostList.tsx +58 -49
  129. package/src/theme/components/ThreadView.tsx +6 -3
  130. package/src/theme/components/TypeBadge.tsx +9 -17
  131. package/src/theme/components/VisibilityBadge.tsx +40 -23
  132. package/src/themes/threads/ThreadsSiteLayout.tsx +194 -0
  133. package/src/themes/{minimal → threads}/index.ts +30 -13
  134. package/src/themes/{minimal → threads}/pages/ArchivePage.tsx +53 -53
  135. package/src/themes/threads/pages/CollectionPage.tsx +61 -0
  136. package/src/themes/{minimal → threads}/pages/HomePage.tsx +3 -3
  137. package/src/themes/{minimal → threads}/pages/PostPage.tsx +12 -8
  138. package/src/themes/{minimal → threads}/pages/SearchPage.tsx +15 -13
  139. package/src/themes/{minimal → threads}/pages/SinglePage.tsx +4 -4
  140. package/src/themes/threads/style.css +336 -0
  141. package/src/themes/threads/timeline/LinkCard.tsx +67 -0
  142. package/src/themes/threads/timeline/NoteCard.tsx +58 -0
  143. package/src/themes/threads/timeline/QuoteCard.tsx +63 -0
  144. package/src/themes/{minimal → threads}/timeline/ThreadPreview.tsx +15 -13
  145. package/src/themes/threads/timeline/TimelineFeed.tsx +62 -0
  146. package/src/themes/{minimal → threads}/timeline/TimelineItem.tsx +9 -17
  147. package/src/themes/threads/timeline/TimelineLoadMore.tsx +35 -0
  148. package/src/themes/threads/timeline/groupByDate.ts +30 -0
  149. package/src/themes/threads/timeline/timelineMore.tsx +130 -0
  150. package/src/types.ts +242 -98
  151. package/dist/routes/api/timeline.js +0 -120
  152. package/dist/themes/minimal/MinimalSiteLayout.js +0 -83
  153. package/dist/themes/minimal/index.js +0 -65
  154. package/dist/themes/minimal/pages/CollectionPage.js +0 -65
  155. package/dist/themes/minimal/timeline/ArticleCard.js +0 -36
  156. package/dist/themes/minimal/timeline/ImageCard.js +0 -67
  157. package/dist/themes/minimal/timeline/LinkCard.js +0 -47
  158. package/dist/themes/minimal/timeline/NoteCard.js +0 -34
  159. package/dist/themes/minimal/timeline/QuoteCard.js +0 -48
  160. package/dist/themes/minimal/timeline/TimelineFeed.js +0 -48
  161. package/src/routes/api/timeline.tsx +0 -159
  162. package/src/themes/minimal/MinimalSiteLayout.tsx +0 -100
  163. package/src/themes/minimal/pages/CollectionPage.tsx +0 -60
  164. package/src/themes/minimal/timeline/ArticleCard.tsx +0 -37
  165. package/src/themes/minimal/timeline/ImageCard.tsx +0 -63
  166. package/src/themes/minimal/timeline/LinkCard.tsx +0 -48
  167. package/src/themes/minimal/timeline/NoteCard.tsx +0 -35
  168. package/src/themes/minimal/timeline/QuoteCard.tsx +0 -49
  169. package/src/themes/minimal/timeline/TimelineFeed.tsx +0 -57
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Threads Theme - Timeline Load More
3
+ *
4
+ * Auto-loads more posts when scrolled into view.
5
+ * Passes `lastDate` to the server so it can merge date groups across pages.
6
+ */
7
+
8
+ import type { FC } from "hono/jsx";
9
+ import { useLingui } from "@lingui/react/macro";
10
+ import type { TimelineLoadMoreProps } from "../../../types.js";
11
+
12
+ export const TimelineLoadMore: FC<TimelineLoadMoreProps> = ({
13
+ nextCursor,
14
+ lastDate,
15
+ }) => {
16
+ const { t } = useLingui();
17
+ const url = lastDate
18
+ ? `/?cursor=${nextCursor}&lastDate=${lastDate}`
19
+ : `/?cursor=${nextCursor}`;
20
+
21
+ return (
22
+ <div
23
+ id="load-more-container"
24
+ class="py-6 text-center"
25
+ data-on-intersect__once={`@get('${url}')`}
26
+ >
27
+ <span class="text-sm text-muted-foreground">
28
+ {t({
29
+ message: "Loading...",
30
+ comment: "@context: Loading indicator while fetching more posts",
31
+ })}
32
+ </span>
33
+ </div>
34
+ );
35
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Groups timeline items by their publication date (YYYY-MM-DD).
3
+ *
4
+ * Shared between TimelineFeed (initial render) and timelineMore (SSE patches)
5
+ * so that both produce identical date group structure.
6
+ */
7
+
8
+ import type { TimelineItemView } from "../../../types.js";
9
+
10
+ export interface DateGroup {
11
+ dateKey: string;
12
+ label: string;
13
+ items: TimelineItemView[];
14
+ }
15
+
16
+ export function groupByDate(items: TimelineItemView[]): DateGroup[] {
17
+ const groups: DateGroup[] = [];
18
+ let current: DateGroup | null = null;
19
+
20
+ for (const item of items) {
21
+ const dateKey = item.post.publishedAt.slice(0, 10);
22
+ if (!current || current.dateKey !== dateKey) {
23
+ current = { dateKey, label: item.post.publishedAtFormatted, items: [] };
24
+ groups.push(current);
25
+ }
26
+ current.items.push(item);
27
+ }
28
+
29
+ return groups;
30
+ }
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Threads Theme - Timeline Load-More SSE Renderer
3
+ *
4
+ * Produces SSE DOM patches for incremental timeline loading.
5
+ * Uses date-grouped layout with threads-specific HTML (threads-card, threads-date-header)
6
+ * matching TimelineFeed's initial render exactly.
7
+ */
8
+
9
+ import type {
10
+ TimelineMoreProps,
11
+ TimelinePatch,
12
+ TimelineItemView,
13
+ } from "../../../types.js";
14
+ import { groupByDate } from "./groupByDate.js";
15
+ import { TimelineItem } from "./TimelineItem.js";
16
+ import { ThreadPreview as DefaultThreadPreview } from "./ThreadPreview.js";
17
+ import { TimelineLoadMore as DefaultTimelineLoadMore } from "./TimelineLoadMore.js";
18
+
19
+ function renderItem(item: TimelineItemView, props: TimelineMoreProps): string {
20
+ const theme = props.theme;
21
+ const ResolvedThreadPreview = theme?.ThreadPreview ?? DefaultThreadPreview;
22
+
23
+ if (item.threadPreview) {
24
+ return (
25
+ <ResolvedThreadPreview
26
+ rootPost={item.post}
27
+ previewReplies={item.threadPreview.replies}
28
+ totalReplyCount={item.threadPreview.totalReplyCount}
29
+ theme={theme}
30
+ />
31
+ ).toString();
32
+ }
33
+ return (<TimelineItem item={item} theme={theme} />).toString();
34
+ }
35
+
36
+ /**
37
+ * Renders SSE patches for the threads theme's load-more response.
38
+ *
39
+ * @param props - Timeline more props with items, pagination, and theme
40
+ * @returns Array of DOM patch instructions for the SSE stream
41
+ */
42
+ export function timelineMore(props: TimelineMoreProps): TimelinePatch[] {
43
+ const { items, lastDate, hasMore, nextCursor, theme } = props;
44
+ const patches: TimelinePatch[] = [];
45
+ const groups = groupByDate(items);
46
+
47
+ if (groups.length === 0) return patches;
48
+
49
+ const firstGroup = groups[0]!;
50
+ const isContinuation = lastDate === firstGroup.dateKey;
51
+
52
+ // Continuation items: append into the existing date group's container
53
+ if (isContinuation) {
54
+ const continuationHtml = firstGroup.items
55
+ .map((item) => {
56
+ const content = renderItem(item, props);
57
+ return `<div><hr class="border-border my-5"/>${content}</div>`;
58
+ })
59
+ .join("");
60
+
61
+ if (continuationHtml) {
62
+ patches.push({
63
+ selector: `#date-items-${lastDate}`,
64
+ content: continuationHtml,
65
+ mode: "append",
66
+ });
67
+ }
68
+ }
69
+
70
+ // New date groups: append to #timeline-feed
71
+ const newGroups = isContinuation ? groups.slice(1) : groups;
72
+ if (newGroups.length > 0) {
73
+ const newGroupsHtml = newGroups
74
+ .map((group) => {
75
+ const itemsHtml = group.items
76
+ .map((item, i) => {
77
+ const content = renderItem(item, props);
78
+ return i > 0
79
+ ? `<div><hr class="border-border my-5"/>${content}</div>`
80
+ : `<div>${content}</div>`;
81
+ })
82
+ .join("");
83
+
84
+ return (
85
+ <div class="threads-card">
86
+ <div class="threads-date-header">
87
+ <span>{group.label}</span>
88
+ </div>
89
+ <div
90
+ id={`date-items-${group.dateKey}`}
91
+ class="flex flex-col"
92
+ dangerouslySetInnerHTML={{ __html: itemsHtml }}
93
+ />
94
+ </div>
95
+ ).toString();
96
+ })
97
+ .join("");
98
+
99
+ patches.push({
100
+ selector: "#timeline-feed",
101
+ content: newGroupsHtml,
102
+ mode: "append",
103
+ });
104
+ }
105
+
106
+ // Load-more button
107
+ const ResolvedLoadMore = theme?.TimelineLoadMore ?? DefaultTimelineLoadMore;
108
+ const lastGroupDate = groups.at(-1)?.dateKey;
109
+
110
+ if (hasMore && nextCursor) {
111
+ patches.push({
112
+ selector: "#load-more-container",
113
+ content: (
114
+ <ResolvedLoadMore
115
+ nextCursor={nextCursor}
116
+ lastDate={lastGroupDate}
117
+ theme={theme}
118
+ />
119
+ ).toString(),
120
+ });
121
+ } else {
122
+ patches.push({
123
+ selector: "#load-more-container",
124
+ content: "",
125
+ mode: "remove",
126
+ });
127
+ }
128
+
129
+ return patches;
130
+ }