@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.
- package/dist/app.js +4 -5
- package/dist/db/schema.js +72 -47
- package/dist/i18n/locales/en.js +1 -1
- package/dist/i18n/locales/zh-Hans.js +1 -1
- package/dist/i18n/locales/zh-Hant.js +1 -1
- package/dist/index.js +3 -3
- package/dist/lib/constants.js +1 -4
- package/dist/lib/excerpt.js +76 -0
- package/dist/lib/feed.js +18 -7
- package/dist/lib/navigation.js +4 -5
- package/dist/lib/render.js +1 -1
- package/dist/lib/schemas.js +80 -38
- package/dist/lib/theme-components.js +8 -11
- package/dist/lib/time.js +56 -1
- package/dist/lib/timeline.js +119 -0
- package/dist/lib/view.js +61 -72
- package/dist/routes/api/posts.js +29 -35
- package/dist/routes/api/search.js +5 -6
- package/dist/routes/api/upload.js +13 -13
- package/dist/routes/dash/collections.js +22 -40
- package/dist/routes/dash/index.js +2 -2
- package/dist/routes/dash/navigation.js +25 -24
- package/dist/routes/dash/pages.js +42 -57
- package/dist/routes/dash/posts.js +27 -35
- package/dist/routes/feed/rss.js +2 -4
- package/dist/routes/feed/sitemap.js +10 -7
- package/dist/routes/pages/archive.js +12 -11
- package/dist/routes/pages/collection.js +11 -5
- package/dist/routes/pages/home.js +53 -61
- package/dist/routes/pages/page.js +60 -29
- package/dist/routes/pages/post.js +5 -12
- package/dist/routes/pages/search.js +3 -4
- package/dist/services/collection.js +52 -64
- package/dist/services/index.js +5 -3
- package/dist/services/navigation.js +29 -53
- package/dist/services/page.js +80 -0
- package/dist/services/post.js +68 -69
- package/dist/services/search.js +24 -18
- package/dist/theme/components/MediaGallery.js +19 -91
- package/dist/theme/components/PageForm.js +15 -15
- package/dist/theme/components/PostForm.js +136 -129
- package/dist/theme/components/PostList.js +13 -8
- package/dist/theme/components/ThreadView.js +3 -3
- package/dist/theme/components/TypeBadge.js +3 -14
- package/dist/theme/components/VisibilityBadge.js +33 -23
- package/dist/themes/threads/ThreadsSiteLayout.js +172 -0
- package/dist/themes/threads/index.js +81 -0
- package/dist/themes/{minimal → threads}/pages/ArchivePage.js +32 -47
- package/dist/themes/threads/pages/CollectionPage.js +65 -0
- package/dist/themes/{minimal → threads}/pages/HomePage.js +3 -3
- package/dist/themes/{minimal → threads}/pages/PostPage.js +12 -9
- package/dist/themes/{minimal → threads}/pages/SearchPage.js +13 -14
- package/dist/themes/{minimal → threads}/pages/SinglePage.js +4 -4
- package/dist/themes/threads/timeline/LinkCard.js +68 -0
- package/dist/themes/threads/timeline/NoteCard.js +53 -0
- package/dist/themes/threads/timeline/QuoteCard.js +59 -0
- package/dist/themes/{minimal → threads}/timeline/ThreadPreview.js +17 -13
- package/dist/themes/threads/timeline/TimelineFeed.js +58 -0
- package/dist/themes/{minimal → threads}/timeline/TimelineItem.js +8 -16
- package/dist/themes/threads/timeline/TimelineLoadMore.js +23 -0
- package/dist/themes/threads/timeline/groupByDate.js +22 -0
- package/dist/themes/threads/timeline/timelineMore.js +107 -0
- package/dist/types.js +24 -40
- package/package.json +2 -1
- package/src/__tests__/helpers/app.ts +4 -0
- package/src/__tests__/helpers/db.ts +51 -74
- package/src/app.tsx +4 -6
- package/src/db/migrations/0005_v2_schema_migration.sql +268 -0
- package/src/db/migrations/meta/_journal.json +7 -0
- package/src/db/schema.ts +63 -46
- package/src/i18n/locales/en.po +216 -164
- package/src/i18n/locales/en.ts +1 -1
- package/src/i18n/locales/zh-Hans.po +216 -164
- package/src/i18n/locales/zh-Hans.ts +1 -1
- package/src/i18n/locales/zh-Hant.po +216 -164
- package/src/i18n/locales/zh-Hant.ts +1 -1
- package/src/index.ts +28 -12
- package/src/lib/__tests__/excerpt.test.ts +125 -0
- package/src/lib/__tests__/schemas.test.ts +166 -105
- package/src/lib/__tests__/theme-components.test.ts +4 -25
- package/src/lib/__tests__/time.test.ts +62 -0
- package/src/{routes/api → lib}/__tests__/timeline.test.ts +108 -66
- package/src/lib/__tests__/view.test.ts +199 -51
- package/src/lib/constants.ts +1 -4
- package/src/lib/excerpt.ts +87 -0
- package/src/lib/feed.ts +22 -7
- package/src/lib/navigation.ts +6 -7
- package/src/lib/render.tsx +1 -1
- package/src/lib/schemas.ts +118 -52
- package/src/lib/theme-components.ts +10 -13
- package/src/lib/time.ts +64 -0
- package/src/lib/timeline.ts +170 -0
- package/src/lib/view.ts +80 -82
- package/src/preset.css +45 -0
- package/src/routes/api/__tests__/posts.test.ts +50 -108
- package/src/routes/api/__tests__/search.test.ts +2 -3
- package/src/routes/api/posts.ts +30 -30
- package/src/routes/api/search.ts +4 -4
- package/src/routes/api/upload.ts +16 -6
- package/src/routes/dash/collections.tsx +18 -40
- package/src/routes/dash/index.tsx +2 -2
- package/src/routes/dash/navigation.tsx +27 -26
- package/src/routes/dash/pages.tsx +45 -60
- package/src/routes/dash/posts.tsx +44 -52
- package/src/routes/feed/rss.ts +2 -1
- package/src/routes/feed/sitemap.ts +14 -4
- package/src/routes/pages/archive.tsx +14 -10
- package/src/routes/pages/collection.tsx +17 -6
- package/src/routes/pages/home.tsx +56 -81
- package/src/routes/pages/page.tsx +64 -27
- package/src/routes/pages/post.tsx +5 -14
- package/src/routes/pages/search.tsx +2 -2
- package/src/services/__tests__/collection.test.ts +257 -158
- package/src/services/__tests__/media.test.ts +18 -18
- package/src/services/__tests__/navigation.test.ts +161 -87
- package/src/services/__tests__/post-timeline.test.ts +92 -88
- package/src/services/__tests__/post.test.ts +342 -206
- package/src/services/__tests__/search.test.ts +19 -25
- package/src/services/collection.ts +71 -113
- package/src/services/index.ts +9 -8
- package/src/services/navigation.ts +38 -71
- package/src/services/page.ts +124 -0
- package/src/services/post.ts +93 -103
- package/src/services/search.ts +38 -27
- package/src/theme/components/MediaGallery.tsx +27 -96
- package/src/theme/components/PageForm.tsx +21 -21
- package/src/theme/components/PostForm.tsx +122 -118
- package/src/theme/components/PostList.tsx +58 -49
- package/src/theme/components/ThreadView.tsx +6 -3
- package/src/theme/components/TypeBadge.tsx +9 -17
- package/src/theme/components/VisibilityBadge.tsx +40 -23
- package/src/themes/threads/ThreadsSiteLayout.tsx +194 -0
- package/src/themes/{minimal → threads}/index.ts +30 -13
- package/src/themes/{minimal → threads}/pages/ArchivePage.tsx +53 -53
- package/src/themes/threads/pages/CollectionPage.tsx +61 -0
- package/src/themes/{minimal → threads}/pages/HomePage.tsx +3 -3
- package/src/themes/{minimal → threads}/pages/PostPage.tsx +12 -8
- package/src/themes/{minimal → threads}/pages/SearchPage.tsx +15 -13
- package/src/themes/{minimal → threads}/pages/SinglePage.tsx +4 -4
- package/src/themes/threads/style.css +336 -0
- package/src/themes/threads/timeline/LinkCard.tsx +67 -0
- package/src/themes/threads/timeline/NoteCard.tsx +58 -0
- package/src/themes/threads/timeline/QuoteCard.tsx +63 -0
- package/src/themes/{minimal → threads}/timeline/ThreadPreview.tsx +15 -13
- package/src/themes/threads/timeline/TimelineFeed.tsx +62 -0
- package/src/themes/{minimal → threads}/timeline/TimelineItem.tsx +9 -17
- package/src/themes/threads/timeline/TimelineLoadMore.tsx +35 -0
- package/src/themes/threads/timeline/groupByDate.ts +30 -0
- package/src/themes/threads/timeline/timelineMore.tsx +130 -0
- package/src/types.ts +242 -98
- package/dist/routes/api/timeline.js +0 -120
- package/dist/themes/minimal/MinimalSiteLayout.js +0 -83
- package/dist/themes/minimal/index.js +0 -65
- package/dist/themes/minimal/pages/CollectionPage.js +0 -65
- package/dist/themes/minimal/timeline/ArticleCard.js +0 -36
- package/dist/themes/minimal/timeline/ImageCard.js +0 -67
- package/dist/themes/minimal/timeline/LinkCard.js +0 -47
- package/dist/themes/minimal/timeline/NoteCard.js +0 -34
- package/dist/themes/minimal/timeline/QuoteCard.js +0 -48
- package/dist/themes/minimal/timeline/TimelineFeed.js +0 -48
- package/src/routes/api/timeline.tsx +0 -159
- package/src/themes/minimal/MinimalSiteLayout.tsx +0 -100
- package/src/themes/minimal/pages/CollectionPage.tsx +0 -60
- package/src/themes/minimal/timeline/ArticleCard.tsx +0 -37
- package/src/themes/minimal/timeline/ImageCard.tsx +0 -63
- package/src/themes/minimal/timeline/LinkCard.tsx +0 -48
- package/src/themes/minimal/timeline/NoteCard.tsx +0 -35
- package/src/themes/minimal/timeline/QuoteCard.tsx +0 -49
- 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
|
+
}
|