@jant/core 0.3.7 → 0.3.8
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 -0
- package/dist/client.js +1 -0
- package/dist/db/schema.js +13 -0
- 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/lib/image.js +3 -3
- package/dist/lib/media-helpers.js +43 -0
- package/dist/lib/nav-reorder.js +27 -0
- package/dist/lib/navigation.js +35 -0
- package/dist/lib/theme-components.js +49 -0
- package/dist/routes/api/timeline.js +115 -0
- package/dist/routes/api/upload.js +9 -5
- package/dist/routes/dash/navigation.js +274 -0
- package/dist/routes/pages/archive.js +14 -27
- package/dist/routes/pages/collection.js +10 -19
- package/dist/routes/pages/home.js +83 -126
- package/dist/routes/pages/page.js +19 -38
- package/dist/routes/pages/post.js +38 -51
- package/dist/routes/pages/search.js +13 -26
- package/dist/services/index.js +3 -1
- package/dist/services/media.js +1 -1
- package/dist/services/navigation.js +115 -0
- package/dist/services/post.js +26 -1
- package/dist/theme/components/PostList.js +5 -0
- package/dist/theme/components/index.js +2 -0
- package/dist/theme/components/timeline/ArticleCard.js +50 -0
- package/dist/theme/components/timeline/ImageCard.js +86 -0
- package/dist/theme/components/timeline/LinkCard.js +62 -0
- package/dist/theme/components/timeline/NoteCard.js +37 -0
- package/dist/theme/components/timeline/QuoteCard.js +51 -0
- package/dist/theme/components/timeline/ThreadPreview.js +52 -0
- package/dist/theme/components/timeline/TimelineFeed.js +43 -0
- package/dist/theme/components/timeline/TimelineItem.js +25 -0
- package/dist/theme/components/timeline/index.js +8 -0
- package/dist/theme/layouts/DashLayout.js +8 -0
- package/dist/theme/layouts/SiteLayout.js +160 -0
- package/dist/theme/layouts/index.js +1 -0
- package/dist/types/sortablejs.d.js +5 -0
- package/package.json +3 -2
- package/src/__tests__/helpers/db.ts +10 -0
- package/src/app.tsx +4 -0
- package/src/client.ts +1 -0
- package/src/db/migrations/0003_add_navigation_links.sql +8 -0
- package/src/db/migrations/meta/0003_snapshot.json +821 -0
- package/src/db/migrations/meta/_journal.json +14 -0
- package/src/db/schema.ts +13 -0
- package/src/i18n/locales/en.po +100 -32
- package/src/i18n/locales/en.ts +1 -1
- package/src/i18n/locales/zh-Hans.po +102 -55
- package/src/i18n/locales/zh-Hans.ts +1 -1
- package/src/i18n/locales/zh-Hant.po +102 -55
- package/src/i18n/locales/zh-Hant.ts +1 -1
- package/src/index.ts +5 -0
- package/src/lib/__tests__/theme-components.test.ts +107 -0
- package/src/lib/image.ts +3 -3
- package/src/lib/media-helpers.ts +54 -0
- package/src/lib/nav-reorder.ts +26 -0
- package/src/lib/navigation.ts +46 -0
- package/src/lib/theme-components.ts +76 -0
- package/src/routes/api/__tests__/posts.test.ts +8 -8
- package/src/routes/api/__tests__/timeline.test.ts +242 -0
- package/src/routes/api/timeline.tsx +145 -0
- package/src/routes/api/upload.ts +9 -5
- package/src/routes/dash/navigation.tsx +306 -0
- package/src/routes/pages/archive.tsx +15 -23
- package/src/routes/pages/collection.tsx +8 -15
- package/src/routes/pages/home.tsx +111 -122
- package/src/routes/pages/page.tsx +17 -30
- package/src/routes/pages/post.tsx +33 -42
- package/src/routes/pages/search.tsx +18 -22
- package/src/services/__tests__/media.test.ts +34 -7
- package/src/services/__tests__/navigation.test.ts +213 -0
- package/src/services/__tests__/post-timeline.test.ts +220 -0
- package/src/services/index.ts +7 -0
- package/src/services/media.ts +2 -1
- package/src/services/navigation.ts +165 -0
- package/src/services/post.ts +48 -1
- package/src/styles/components.css +59 -0
- package/src/theme/components/PostList.tsx +7 -0
- package/src/theme/components/index.ts +12 -0
- package/src/theme/components/timeline/ArticleCard.tsx +57 -0
- package/src/theme/components/timeline/ImageCard.tsx +80 -0
- package/src/theme/components/timeline/LinkCard.tsx +66 -0
- package/src/theme/components/timeline/NoteCard.tsx +41 -0
- package/src/theme/components/timeline/QuoteCard.tsx +55 -0
- package/src/theme/components/timeline/ThreadPreview.tsx +49 -0
- package/src/theme/components/timeline/TimelineFeed.tsx +52 -0
- package/src/theme/components/timeline/TimelineItem.tsx +39 -0
- package/src/theme/components/timeline/index.ts +8 -0
- package/src/theme/layouts/DashLayout.tsx +10 -0
- package/src/theme/layouts/SiteLayout.tsx +184 -0
- package/src/theme/layouts/index.ts +1 -0
- package/src/types/sortablejs.d.ts +23 -0
- package/src/types.ts +61 -0
- package/dist/app.d.ts +0 -38
- package/dist/app.d.ts.map +0 -1
- package/dist/auth.d.ts +0 -25
- package/dist/auth.d.ts.map +0 -1
- package/dist/db/index.d.ts +0 -10
- package/dist/db/index.d.ts.map +0 -1
- package/dist/db/schema.d.ts +0 -1543
- package/dist/db/schema.d.ts.map +0 -1
- package/dist/i18n/Trans.d.ts +0 -25
- package/dist/i18n/Trans.d.ts.map +0 -1
- package/dist/i18n/context.d.ts +0 -69
- package/dist/i18n/context.d.ts.map +0 -1
- package/dist/i18n/detect.d.ts +0 -20
- package/dist/i18n/detect.d.ts.map +0 -1
- package/dist/i18n/i18n.d.ts +0 -32
- package/dist/i18n/i18n.d.ts.map +0 -1
- package/dist/i18n/index.d.ts +0 -41
- package/dist/i18n/index.d.ts.map +0 -1
- package/dist/i18n/locales/en.d.ts +0 -3
- package/dist/i18n/locales/en.d.ts.map +0 -1
- package/dist/i18n/locales/zh-Hans.d.ts +0 -3
- package/dist/i18n/locales/zh-Hans.d.ts.map +0 -1
- package/dist/i18n/locales/zh-Hant.d.ts +0 -3
- package/dist/i18n/locales/zh-Hant.d.ts.map +0 -1
- package/dist/i18n/locales.d.ts +0 -11
- package/dist/i18n/locales.d.ts.map +0 -1
- package/dist/i18n/middleware.d.ts +0 -21
- package/dist/i18n/middleware.d.ts.map +0 -1
- package/dist/index.d.ts +0 -16
- package/dist/index.d.ts.map +0 -1
- package/dist/lib/config.d.ts +0 -83
- package/dist/lib/config.d.ts.map +0 -1
- package/dist/lib/constants.d.ts +0 -37
- package/dist/lib/constants.d.ts.map +0 -1
- package/dist/lib/image.d.ts +0 -73
- package/dist/lib/image.d.ts.map +0 -1
- package/dist/lib/index.d.ts +0 -9
- package/dist/lib/index.d.ts.map +0 -1
- package/dist/lib/markdown.d.ts +0 -60
- package/dist/lib/markdown.d.ts.map +0 -1
- package/dist/lib/schemas.d.ts +0 -130
- package/dist/lib/schemas.d.ts.map +0 -1
- package/dist/lib/sqid.d.ts +0 -60
- package/dist/lib/sqid.d.ts.map +0 -1
- package/dist/lib/sse.d.ts +0 -192
- package/dist/lib/sse.d.ts.map +0 -1
- package/dist/lib/theme.d.ts +0 -44
- package/dist/lib/theme.d.ts.map +0 -1
- package/dist/lib/time.d.ts +0 -90
- package/dist/lib/time.d.ts.map +0 -1
- package/dist/lib/url.d.ts +0 -82
- package/dist/lib/url.d.ts.map +0 -1
- package/dist/middleware/auth.d.ts +0 -24
- package/dist/middleware/auth.d.ts.map +0 -1
- package/dist/middleware/onboarding.d.ts +0 -26
- package/dist/middleware/onboarding.d.ts.map +0 -1
- package/dist/routes/api/posts.d.ts +0 -13
- package/dist/routes/api/posts.d.ts.map +0 -1
- package/dist/routes/api/search.d.ts +0 -13
- package/dist/routes/api/search.d.ts.map +0 -1
- package/dist/routes/api/upload.d.ts +0 -16
- package/dist/routes/api/upload.d.ts.map +0 -1
- package/dist/routes/dash/collections.d.ts +0 -13
- package/dist/routes/dash/collections.d.ts.map +0 -1
- package/dist/routes/dash/index.d.ts +0 -15
- package/dist/routes/dash/index.d.ts.map +0 -1
- package/dist/routes/dash/media.d.ts +0 -16
- package/dist/routes/dash/media.d.ts.map +0 -1
- package/dist/routes/dash/pages.d.ts +0 -15
- package/dist/routes/dash/pages.d.ts.map +0 -1
- package/dist/routes/dash/posts.d.ts +0 -13
- package/dist/routes/dash/posts.d.ts.map +0 -1
- package/dist/routes/dash/redirects.d.ts +0 -13
- package/dist/routes/dash/redirects.d.ts.map +0 -1
- package/dist/routes/dash/settings.d.ts +0 -15
- package/dist/routes/dash/settings.d.ts.map +0 -1
- package/dist/routes/feed/rss.d.ts +0 -13
- package/dist/routes/feed/rss.d.ts.map +0 -1
- package/dist/routes/feed/sitemap.d.ts +0 -13
- package/dist/routes/feed/sitemap.d.ts.map +0 -1
- package/dist/routes/pages/archive.d.ts +0 -15
- package/dist/routes/pages/archive.d.ts.map +0 -1
- package/dist/routes/pages/collection.d.ts +0 -13
- package/dist/routes/pages/collection.d.ts.map +0 -1
- package/dist/routes/pages/home.d.ts +0 -13
- package/dist/routes/pages/home.d.ts.map +0 -1
- package/dist/routes/pages/page.d.ts +0 -15
- package/dist/routes/pages/page.d.ts.map +0 -1
- package/dist/routes/pages/post.d.ts +0 -13
- package/dist/routes/pages/post.d.ts.map +0 -1
- package/dist/routes/pages/search.d.ts +0 -13
- package/dist/routes/pages/search.d.ts.map +0 -1
- package/dist/services/collection.d.ts +0 -32
- package/dist/services/collection.d.ts.map +0 -1
- package/dist/services/index.d.ts +0 -28
- package/dist/services/index.d.ts.map +0 -1
- package/dist/services/media.d.ts +0 -34
- package/dist/services/media.d.ts.map +0 -1
- package/dist/services/post.d.ts +0 -31
- package/dist/services/post.d.ts.map +0 -1
- package/dist/services/redirect.d.ts +0 -15
- package/dist/services/redirect.d.ts.map +0 -1
- package/dist/services/search.d.ts +0 -26
- package/dist/services/search.d.ts.map +0 -1
- package/dist/services/settings.d.ts +0 -18
- package/dist/services/settings.d.ts.map +0 -1
- package/dist/theme/color-themes.d.ts +0 -30
- package/dist/theme/color-themes.d.ts.map +0 -1
- package/dist/theme/components/ActionButtons.d.ts +0 -43
- package/dist/theme/components/ActionButtons.d.ts.map +0 -1
- package/dist/theme/components/CrudPageHeader.d.ts +0 -23
- package/dist/theme/components/CrudPageHeader.d.ts.map +0 -1
- package/dist/theme/components/DangerZone.d.ts +0 -36
- package/dist/theme/components/DangerZone.d.ts.map +0 -1
- package/dist/theme/components/EmptyState.d.ts +0 -27
- package/dist/theme/components/EmptyState.d.ts.map +0 -1
- package/dist/theme/components/ListItemRow.d.ts +0 -15
- package/dist/theme/components/ListItemRow.d.ts.map +0 -1
- package/dist/theme/components/MediaGallery.d.ts +0 -13
- package/dist/theme/components/MediaGallery.d.ts.map +0 -1
- package/dist/theme/components/PageForm.d.ts +0 -14
- package/dist/theme/components/PageForm.d.ts.map +0 -1
- package/dist/theme/components/Pagination.d.ts +0 -46
- package/dist/theme/components/Pagination.d.ts.map +0 -1
- package/dist/theme/components/PostForm.d.ts +0 -16
- package/dist/theme/components/PostForm.d.ts.map +0 -1
- package/dist/theme/components/PostList.d.ts +0 -10
- package/dist/theme/components/PostList.d.ts.map +0 -1
- package/dist/theme/components/ThreadView.d.ts +0 -15
- package/dist/theme/components/ThreadView.d.ts.map +0 -1
- package/dist/theme/components/TypeBadge.d.ts +0 -12
- package/dist/theme/components/TypeBadge.d.ts.map +0 -1
- package/dist/theme/components/VisibilityBadge.d.ts +0 -12
- package/dist/theme/components/VisibilityBadge.d.ts.map +0 -1
- package/dist/theme/components/index.d.ts +0 -14
- package/dist/theme/components/index.d.ts.map +0 -1
- package/dist/theme/index.d.ts +0 -21
- package/dist/theme/index.d.ts.map +0 -1
- package/dist/theme/layouts/BaseLayout.d.ts +0 -23
- package/dist/theme/layouts/BaseLayout.d.ts.map +0 -1
- package/dist/theme/layouts/DashLayout.d.ts +0 -17
- package/dist/theme/layouts/DashLayout.d.ts.map +0 -1
- package/dist/theme/layouts/index.d.ts +0 -3
- package/dist/theme/layouts/index.d.ts.map +0 -1
- package/dist/types.d.ts +0 -237
- package/dist/types.d.ts.map +0 -1
|
@@ -1,47 +1,25 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
|
|
2
|
-
import { getSiteName } from "../../lib/config.js";
|
|
3
2
|
/**
|
|
4
3
|
* Custom Page Route
|
|
5
4
|
*
|
|
6
5
|
* Catch-all route for custom pages accessible via their path field
|
|
7
6
|
*/ import { Hono } from "hono";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { BaseLayout, SiteLayout } from "../../theme/layouts/index.js";
|
|
8
|
+
import { getNavigationData } from "../../lib/navigation.js";
|
|
10
9
|
export const pageRoutes = new Hono();
|
|
11
10
|
function PageContent({ page }) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class: "container py-8 max-w-2xl",
|
|
11
|
+
return /*#__PURE__*/ _jsxs("article", {
|
|
12
|
+
class: "h-entry",
|
|
15
13
|
children: [
|
|
16
|
-
/*#__PURE__*/
|
|
17
|
-
class: "
|
|
18
|
-
children:
|
|
19
|
-
page.title && /*#__PURE__*/ _jsx("h1", {
|
|
20
|
-
class: "p-name text-3xl font-semibold mb-6",
|
|
21
|
-
children: page.title
|
|
22
|
-
}),
|
|
23
|
-
/*#__PURE__*/ _jsx("div", {
|
|
24
|
-
class: "e-content prose",
|
|
25
|
-
dangerouslySetInnerHTML: {
|
|
26
|
-
__html: page.contentHtml || ""
|
|
27
|
-
}
|
|
28
|
-
})
|
|
29
|
-
]
|
|
14
|
+
page.title && /*#__PURE__*/ _jsx("h1", {
|
|
15
|
+
class: "p-name text-3xl font-semibold mb-6",
|
|
16
|
+
children: page.title
|
|
30
17
|
}),
|
|
31
|
-
/*#__PURE__*/ _jsx("
|
|
32
|
-
class: "
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
children: [
|
|
37
|
-
"←",
|
|
38
|
-
" ",
|
|
39
|
-
$__i18n._({
|
|
40
|
-
id: "x4RuFo",
|
|
41
|
-
message: "Back to home"
|
|
42
|
-
})
|
|
43
|
-
]
|
|
44
|
-
})
|
|
18
|
+
/*#__PURE__*/ _jsx("div", {
|
|
19
|
+
class: "e-content prose",
|
|
20
|
+
dangerouslySetInnerHTML: {
|
|
21
|
+
__html: page.contentHtml || ""
|
|
22
|
+
}
|
|
45
23
|
})
|
|
46
24
|
]
|
|
47
25
|
});
|
|
@@ -59,13 +37,16 @@ pageRoutes.get("/:path", async (c)=>{
|
|
|
59
37
|
if (page.visibility === "draft") {
|
|
60
38
|
return c.notFound();
|
|
61
39
|
}
|
|
62
|
-
const
|
|
40
|
+
const navData = await getNavigationData(c);
|
|
63
41
|
return c.html(/*#__PURE__*/ _jsx(BaseLayout, {
|
|
64
|
-
title: `${page.title} - ${siteName}`,
|
|
42
|
+
title: `${page.title} - ${navData.siteName}`,
|
|
65
43
|
description: page.content?.slice(0, 160),
|
|
66
44
|
c: c,
|
|
67
|
-
children: /*#__PURE__*/ _jsx(
|
|
68
|
-
|
|
45
|
+
children: /*#__PURE__*/ _jsx(SiteLayout, {
|
|
46
|
+
...navData,
|
|
47
|
+
children: /*#__PURE__*/ _jsx(PageContent, {
|
|
48
|
+
page: page
|
|
49
|
+
})
|
|
69
50
|
})
|
|
70
51
|
}));
|
|
71
52
|
});
|
|
@@ -1,66 +1,50 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
|
|
2
|
-
import { getSiteName } from "../../lib/config.js";
|
|
3
2
|
/**
|
|
4
3
|
* Single Post Page Route
|
|
5
4
|
*/ import { Hono } from "hono";
|
|
6
5
|
import { useLingui as $_useLingui } from "@jant/core/i18n";
|
|
7
|
-
import { BaseLayout } from "../../theme/layouts/index.js";
|
|
6
|
+
import { BaseLayout, SiteLayout } from "../../theme/layouts/index.js";
|
|
8
7
|
import { MediaGallery } from "../../theme/components/index.js";
|
|
9
8
|
import * as sqid from "../../lib/sqid.js";
|
|
10
9
|
import * as time from "../../lib/time.js";
|
|
11
10
|
import { getMediaUrl, getImageUrl } from "../../lib/image.js";
|
|
11
|
+
import { getNavigationData } from "../../lib/navigation.js";
|
|
12
12
|
export const postRoutes = new Hono();
|
|
13
13
|
function PostContent({ post, mediaAttachments }) {
|
|
14
14
|
const { i18n: $__i18n, _: $__ } = $_useLingui();
|
|
15
|
-
return /*#__PURE__*/ _jsxs("
|
|
16
|
-
class: "
|
|
15
|
+
return /*#__PURE__*/ _jsxs("article", {
|
|
16
|
+
class: "h-entry",
|
|
17
17
|
children: [
|
|
18
|
-
/*#__PURE__*/
|
|
19
|
-
class: "
|
|
18
|
+
post.title && /*#__PURE__*/ _jsx("h1", {
|
|
19
|
+
class: "p-name text-2xl font-semibold mb-4",
|
|
20
|
+
children: post.title
|
|
21
|
+
}),
|
|
22
|
+
/*#__PURE__*/ _jsx("div", {
|
|
23
|
+
class: "e-content prose",
|
|
24
|
+
dangerouslySetInnerHTML: {
|
|
25
|
+
__html: post.contentHtml || ""
|
|
26
|
+
}
|
|
27
|
+
}),
|
|
28
|
+
mediaAttachments.length > 0 && /*#__PURE__*/ _jsx(MediaGallery, {
|
|
29
|
+
attachments: mediaAttachments
|
|
30
|
+
}),
|
|
31
|
+
/*#__PURE__*/ _jsxs("footer", {
|
|
32
|
+
class: "mt-6 pt-4 border-t text-sm text-muted-foreground",
|
|
20
33
|
children: [
|
|
21
|
-
|
|
22
|
-
class: "
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/*#__PURE__*/ _jsx("div", {
|
|
26
|
-
class: "e-content prose",
|
|
27
|
-
dangerouslySetInnerHTML: {
|
|
28
|
-
__html: post.contentHtml || ""
|
|
29
|
-
}
|
|
34
|
+
/*#__PURE__*/ _jsx("time", {
|
|
35
|
+
class: "dt-published",
|
|
36
|
+
datetime: time.toISOString(post.publishedAt),
|
|
37
|
+
children: time.formatDate(post.publishedAt)
|
|
30
38
|
}),
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class: "dt-published",
|
|
39
|
-
datetime: time.toISOString(post.publishedAt),
|
|
40
|
-
children: time.formatDate(post.publishedAt)
|
|
41
|
-
}),
|
|
42
|
-
/*#__PURE__*/ _jsx("a", {
|
|
43
|
-
href: `/p/${sqid.encode(post.id)}`,
|
|
44
|
-
class: "u-url ml-4",
|
|
45
|
-
children: $__i18n._({
|
|
46
|
-
id: "D9Oea+",
|
|
47
|
-
message: "Permalink"
|
|
48
|
-
})
|
|
49
|
-
})
|
|
50
|
-
]
|
|
39
|
+
/*#__PURE__*/ _jsx("a", {
|
|
40
|
+
href: `/p/${sqid.encode(post.id)}`,
|
|
41
|
+
class: "u-url ml-4",
|
|
42
|
+
children: $__i18n._({
|
|
43
|
+
id: "D9Oea+",
|
|
44
|
+
message: "Permalink"
|
|
45
|
+
})
|
|
51
46
|
})
|
|
52
47
|
]
|
|
53
|
-
}),
|
|
54
|
-
/*#__PURE__*/ _jsx("nav", {
|
|
55
|
-
class: "mt-8",
|
|
56
|
-
children: /*#__PURE__*/ _jsx("a", {
|
|
57
|
-
href: "/",
|
|
58
|
-
class: "text-sm hover:underline",
|
|
59
|
-
children: $__i18n._({
|
|
60
|
-
id: "biOepV",
|
|
61
|
-
message: "← Back to home"
|
|
62
|
-
})
|
|
63
|
-
})
|
|
64
48
|
})
|
|
65
49
|
]
|
|
66
50
|
});
|
|
@@ -103,15 +87,18 @@ postRoutes.get("/:id", async (c)=>{
|
|
|
103
87
|
position: m.position,
|
|
104
88
|
mimeType: m.mimeType
|
|
105
89
|
}));
|
|
106
|
-
const
|
|
107
|
-
const title = post.title || siteName;
|
|
90
|
+
const navData = await getNavigationData(c);
|
|
91
|
+
const title = post.title || navData.siteName;
|
|
108
92
|
return c.html(/*#__PURE__*/ _jsx(BaseLayout, {
|
|
109
93
|
title: title,
|
|
110
94
|
description: post.content?.slice(0, 160),
|
|
111
95
|
c: c,
|
|
112
|
-
children: /*#__PURE__*/ _jsx(
|
|
113
|
-
|
|
114
|
-
|
|
96
|
+
children: /*#__PURE__*/ _jsx(SiteLayout, {
|
|
97
|
+
...navData,
|
|
98
|
+
children: /*#__PURE__*/ _jsx(PostContent, {
|
|
99
|
+
post: post,
|
|
100
|
+
mediaAttachments: mediaAttachments
|
|
101
|
+
})
|
|
115
102
|
})
|
|
116
103
|
}));
|
|
117
104
|
});
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
|
|
2
|
-
import { getSiteName } from "../../lib/config.js";
|
|
3
2
|
/**
|
|
4
3
|
* Search Page Route
|
|
5
4
|
*/ import { Hono } from "hono";
|
|
6
5
|
import { useLingui as $_useLingui } from "@jant/core/i18n";
|
|
7
|
-
import { BaseLayout } from "../../theme/layouts/index.js";
|
|
6
|
+
import { BaseLayout, SiteLayout } from "../../theme/layouts/index.js";
|
|
8
7
|
import { PagePagination } from "../../theme/components/index.js";
|
|
9
8
|
import * as sqid from "../../lib/sqid.js";
|
|
10
9
|
import * as time from "../../lib/time.js";
|
|
10
|
+
import { getNavigationData } from "../../lib/navigation.js";
|
|
11
11
|
const PAGE_SIZE = 10;
|
|
12
12
|
export const searchRoutes = new Hono();
|
|
13
13
|
function SearchContent({ query, results, error, hasMore, page }) {
|
|
@@ -17,7 +17,6 @@ function SearchContent({ query, results, error, hasMore, page }) {
|
|
|
17
17
|
message: "Search"
|
|
18
18
|
});
|
|
19
19
|
return /*#__PURE__*/ _jsxs("div", {
|
|
20
|
-
class: "container py-8 max-w-2xl",
|
|
21
20
|
children: [
|
|
22
21
|
/*#__PURE__*/ _jsx("h1", {
|
|
23
22
|
class: "text-2xl font-semibold mb-6",
|
|
@@ -118,21 +117,6 @@ function SearchContent({ query, results, error, hasMore, page }) {
|
|
|
118
117
|
]
|
|
119
118
|
})
|
|
120
119
|
]
|
|
121
|
-
}),
|
|
122
|
-
/*#__PURE__*/ _jsx("nav", {
|
|
123
|
-
class: "mt-8 pt-6 border-t",
|
|
124
|
-
children: /*#__PURE__*/ _jsxs("a", {
|
|
125
|
-
href: "/",
|
|
126
|
-
class: "text-sm hover:underline",
|
|
127
|
-
children: [
|
|
128
|
-
"←",
|
|
129
|
-
" ",
|
|
130
|
-
$__i18n._({
|
|
131
|
-
id: "x4RuFo",
|
|
132
|
-
message: "Back to home"
|
|
133
|
-
})
|
|
134
|
-
]
|
|
135
|
-
})
|
|
136
120
|
})
|
|
137
121
|
]
|
|
138
122
|
});
|
|
@@ -141,7 +125,7 @@ searchRoutes.get("/", async (c)=>{
|
|
|
141
125
|
const query = c.req.query("q") || "";
|
|
142
126
|
const pageParam = c.req.query("page");
|
|
143
127
|
const page = pageParam ? Math.max(1, parseInt(pageParam, 10) || 1) : 1;
|
|
144
|
-
const
|
|
128
|
+
const navData = await getNavigationData(c);
|
|
145
129
|
// Only search if there's a query
|
|
146
130
|
let results = [];
|
|
147
131
|
let error = null;
|
|
@@ -168,14 +152,17 @@ searchRoutes.get("/", async (c)=>{
|
|
|
168
152
|
}
|
|
169
153
|
}
|
|
170
154
|
return c.html(/*#__PURE__*/ _jsx(BaseLayout, {
|
|
171
|
-
title: query ? `Search: ${query} - ${siteName}` : `Search - ${siteName}`,
|
|
155
|
+
title: query ? `Search: ${query} - ${navData.siteName}` : `Search - ${navData.siteName}`,
|
|
172
156
|
c: c,
|
|
173
|
-
children: /*#__PURE__*/ _jsx(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
157
|
+
children: /*#__PURE__*/ _jsx(SiteLayout, {
|
|
158
|
+
...navData,
|
|
159
|
+
children: /*#__PURE__*/ _jsx(SearchContent, {
|
|
160
|
+
query: query,
|
|
161
|
+
results: results,
|
|
162
|
+
error: error,
|
|
163
|
+
hasMore: hasMore,
|
|
164
|
+
page: page
|
|
165
|
+
})
|
|
179
166
|
})
|
|
180
167
|
}));
|
|
181
168
|
});
|
package/dist/services/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import { createRedirectService } from "./redirect.js";
|
|
|
8
8
|
import { createMediaService } from "./media.js";
|
|
9
9
|
import { createCollectionService } from "./collection.js";
|
|
10
10
|
import { createSearchService } from "./search.js";
|
|
11
|
+
import { createNavigationLinkService } from "./navigation.js";
|
|
11
12
|
export function createServices(db, d1) {
|
|
12
13
|
return {
|
|
13
14
|
settings: createSettingsService(db),
|
|
@@ -15,6 +16,7 @@ export function createServices(db, d1) {
|
|
|
15
16
|
redirects: createRedirectService(db),
|
|
16
17
|
media: createMediaService(db),
|
|
17
18
|
collections: createCollectionService(db),
|
|
18
|
-
search: createSearchService(d1)
|
|
19
|
+
search: createSearchService(d1),
|
|
20
|
+
navigationLinks: createNavigationLinkService(db)
|
|
19
21
|
};
|
|
20
22
|
}
|
package/dist/services/media.js
CHANGED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Navigation Link Service
|
|
3
|
+
*
|
|
4
|
+
* Manages navigation links displayed on public pages
|
|
5
|
+
*/ import { eq, asc, sql } from "drizzle-orm";
|
|
6
|
+
import { navigationLinks } from "../db/schema.js";
|
|
7
|
+
import { now } from "../lib/time.js";
|
|
8
|
+
export function createNavigationLinkService(db) {
|
|
9
|
+
function toNavigationLink(row) {
|
|
10
|
+
return {
|
|
11
|
+
id: row.id,
|
|
12
|
+
label: row.label,
|
|
13
|
+
url: row.url,
|
|
14
|
+
position: row.position,
|
|
15
|
+
createdAt: row.createdAt,
|
|
16
|
+
updatedAt: row.updatedAt
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
async list () {
|
|
21
|
+
const rows = await db.select().from(navigationLinks).orderBy(asc(navigationLinks.position));
|
|
22
|
+
return rows.map(toNavigationLink);
|
|
23
|
+
},
|
|
24
|
+
async getById (id) {
|
|
25
|
+
const result = await db.select().from(navigationLinks).where(eq(navigationLinks.id, id)).limit(1);
|
|
26
|
+
return result[0] ? toNavigationLink(result[0]) : null;
|
|
27
|
+
},
|
|
28
|
+
async create (data) {
|
|
29
|
+
const timestamp = now();
|
|
30
|
+
let position = data.position;
|
|
31
|
+
if (position === undefined) {
|
|
32
|
+
const maxResult = await db.select({
|
|
33
|
+
maxPos: sql`COALESCE(MAX(position), -1)`
|
|
34
|
+
}).from(navigationLinks);
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- aggregate always returns one row
|
|
36
|
+
position = maxResult[0].maxPos + 1;
|
|
37
|
+
}
|
|
38
|
+
const result = await db.insert(navigationLinks).values({
|
|
39
|
+
label: data.label,
|
|
40
|
+
url: data.url,
|
|
41
|
+
position,
|
|
42
|
+
createdAt: timestamp,
|
|
43
|
+
updatedAt: timestamp
|
|
44
|
+
}).returning();
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- DB insert with .returning() always returns inserted row
|
|
46
|
+
return toNavigationLink(result[0]);
|
|
47
|
+
},
|
|
48
|
+
async update (id, data) {
|
|
49
|
+
const existing = await db.select().from(navigationLinks).where(eq(navigationLinks.id, id)).limit(1);
|
|
50
|
+
if (!existing[0]) return null;
|
|
51
|
+
const timestamp = now();
|
|
52
|
+
const result = await db.update(navigationLinks).set({
|
|
53
|
+
...data.label !== undefined && {
|
|
54
|
+
label: data.label
|
|
55
|
+
},
|
|
56
|
+
...data.url !== undefined && {
|
|
57
|
+
url: data.url
|
|
58
|
+
},
|
|
59
|
+
...data.position !== undefined && {
|
|
60
|
+
position: data.position
|
|
61
|
+
},
|
|
62
|
+
updatedAt: timestamp
|
|
63
|
+
}).where(eq(navigationLinks.id, id)).returning();
|
|
64
|
+
return result[0] ? toNavigationLink(result[0]) : null;
|
|
65
|
+
},
|
|
66
|
+
async delete (id) {
|
|
67
|
+
const result = await db.delete(navigationLinks).where(eq(navigationLinks.id, id)).returning();
|
|
68
|
+
return result.length > 0;
|
|
69
|
+
},
|
|
70
|
+
async reorder (ids) {
|
|
71
|
+
const timestamp = now();
|
|
72
|
+
for(let i = 0; i < ids.length; i++){
|
|
73
|
+
await db.update(navigationLinks).set({
|
|
74
|
+
position: i,
|
|
75
|
+
updatedAt: timestamp
|
|
76
|
+
})// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- loop index guarantees element exists
|
|
77
|
+
.where(eq(navigationLinks.id, ids[i]));
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
async ensureDefaults () {
|
|
81
|
+
const existing = await db.select().from(navigationLinks).limit(1);
|
|
82
|
+
if (existing.length > 0) {
|
|
83
|
+
const rows = await db.select().from(navigationLinks).orderBy(asc(navigationLinks.position));
|
|
84
|
+
return rows.map(toNavigationLink);
|
|
85
|
+
}
|
|
86
|
+
const timestamp = now();
|
|
87
|
+
const defaults = [
|
|
88
|
+
{
|
|
89
|
+
label: "Home",
|
|
90
|
+
url: "/",
|
|
91
|
+
position: 0
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
label: "Archive",
|
|
95
|
+
url: "/archive",
|
|
96
|
+
position: 1
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
label: "RSS",
|
|
100
|
+
url: "/feed",
|
|
101
|
+
position: 2
|
|
102
|
+
}
|
|
103
|
+
];
|
|
104
|
+
for (const link of defaults){
|
|
105
|
+
await db.insert(navigationLinks).values({
|
|
106
|
+
...link,
|
|
107
|
+
createdAt: timestamp,
|
|
108
|
+
updatedAt: timestamp
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const rows = await db.select().from(navigationLinks).orderBy(asc(navigationLinks.position));
|
|
112
|
+
return rows.map(toNavigationLink);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
package/dist/services/post.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Post Service
|
|
3
3
|
*
|
|
4
4
|
* CRUD operations for posts with Thread support
|
|
5
|
-
*/ import { eq, and, isNull, desc, or, inArray, sql } from "drizzle-orm";
|
|
5
|
+
*/ import { eq, and, isNull, desc, or, inArray, notInArray, sql } from "drizzle-orm";
|
|
6
6
|
import { posts } from "../db/schema.js";
|
|
7
7
|
import { now } from "../lib/time.js";
|
|
8
8
|
import { extractDomain } from "../lib/url.js";
|
|
@@ -52,6 +52,10 @@ export function createPostService(db) {
|
|
|
52
52
|
if (filters.type) {
|
|
53
53
|
conditions.push(eq(posts.type, filters.type));
|
|
54
54
|
}
|
|
55
|
+
// Exclude types filter
|
|
56
|
+
if (filters.excludeTypes && filters.excludeTypes.length > 0) {
|
|
57
|
+
conditions.push(notInArray(posts.type, filters.excludeTypes));
|
|
58
|
+
}
|
|
55
59
|
// Thread filter
|
|
56
60
|
if (filters.threadId) {
|
|
57
61
|
conditions.push(eq(posts.threadId, filters.threadId));
|
|
@@ -186,6 +190,27 @@ export function createPostService(db) {
|
|
|
186
190
|
}
|
|
187
191
|
}
|
|
188
192
|
return counts;
|
|
193
|
+
},
|
|
194
|
+
async getThreadPreviews (rootIds, previewCount = 3) {
|
|
195
|
+
if (rootIds.length === 0) return new Map();
|
|
196
|
+
const rows = await db.select().from(posts).where(and(inArray(posts.threadId, rootIds), isNull(posts.deletedAt))).orderBy(posts.threadId, posts.createdAt);
|
|
197
|
+
// Partition by threadId, take first previewCount per thread
|
|
198
|
+
const result = new Map();
|
|
199
|
+
for (const row of rows){
|
|
200
|
+
const post = toPost(row);
|
|
201
|
+
if (post.threadId === null) continue;
|
|
202
|
+
const list = result.get(post.threadId);
|
|
203
|
+
if (list) {
|
|
204
|
+
if (list.length < previewCount) {
|
|
205
|
+
list.push(post);
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
result.set(post.threadId, [
|
|
209
|
+
post
|
|
210
|
+
]);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return result;
|
|
189
214
|
}
|
|
190
215
|
};
|
|
191
216
|
}
|
|
@@ -37,6 +37,11 @@ export const PostList = ({ posts })=>{
|
|
|
37
37
|
viewLabel: $__i18n._({
|
|
38
38
|
id: "jpctdh",
|
|
39
39
|
message: "View"
|
|
40
|
+
}),
|
|
41
|
+
deleteAction: `/dash/posts/${sqid.encode(post.id)}/delete`,
|
|
42
|
+
deleteConfirm: $__i18n._({
|
|
43
|
+
id: "KmGXnO",
|
|
44
|
+
message: "Are you sure you want to delete this post? This cannot be undone."
|
|
40
45
|
})
|
|
41
46
|
}),
|
|
42
47
|
children: [
|
|
@@ -11,3 +11,5 @@ export { PostList } from "./PostList.js";
|
|
|
11
11
|
export { ThreadView } from "./ThreadView.js";
|
|
12
12
|
export { TypeBadge } from "./TypeBadge.js";
|
|
13
13
|
export { VisibilityBadge } from "./VisibilityBadge.js";
|
|
14
|
+
// Timeline components
|
|
15
|
+
export { NoteCard, ArticleCard, LinkCard, QuoteCard, ImageCard, ThreadPreview, TimelineItem, TimelineFeed } from "./timeline/index.js";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Article Card Component
|
|
3
|
+
*
|
|
4
|
+
* Prominent title + excerpt for type="article" posts.
|
|
5
|
+
*/ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
|
|
6
|
+
import * as sqid from "../../../lib/sqid.js";
|
|
7
|
+
import * as time from "../../../lib/time.js";
|
|
8
|
+
export const ArticleCard = ({ post, compact })=>{
|
|
9
|
+
const permalink = `/p/${sqid.encode(post.id)}`;
|
|
10
|
+
const excerpt = post.content ? post.content.length > 160 ? post.content.slice(0, 160) + "..." : post.content : null;
|
|
11
|
+
return /*#__PURE__*/ _jsxs("article", {
|
|
12
|
+
class: `h-entry timeline-card${compact ? " timeline-card-compact" : ""}`,
|
|
13
|
+
children: [
|
|
14
|
+
post.title && /*#__PURE__*/ _jsx("h2", {
|
|
15
|
+
class: `p-name font-semibold ${compact ? "text-sm" : "text-lg"} mb-1`,
|
|
16
|
+
children: /*#__PURE__*/ _jsx("a", {
|
|
17
|
+
href: permalink,
|
|
18
|
+
class: "u-url hover:underline",
|
|
19
|
+
children: post.title
|
|
20
|
+
})
|
|
21
|
+
}),
|
|
22
|
+
!compact && excerpt && /*#__PURE__*/ _jsx("p", {
|
|
23
|
+
class: "e-content text-sm text-muted-foreground line-clamp-3",
|
|
24
|
+
children: excerpt
|
|
25
|
+
}),
|
|
26
|
+
/*#__PURE__*/ _jsxs("footer", {
|
|
27
|
+
class: "mt-2 text-xs text-muted-foreground",
|
|
28
|
+
children: [
|
|
29
|
+
/*#__PURE__*/ _jsx("a", {
|
|
30
|
+
href: permalink,
|
|
31
|
+
class: "u-url hover:underline",
|
|
32
|
+
children: /*#__PURE__*/ _jsx("time", {
|
|
33
|
+
class: "dt-published",
|
|
34
|
+
datetime: time.toISOString(post.publishedAt),
|
|
35
|
+
children: time.formatDate(post.publishedAt)
|
|
36
|
+
})
|
|
37
|
+
}),
|
|
38
|
+
!compact && /*#__PURE__*/ _jsx("span", {
|
|
39
|
+
class: "ml-2",
|
|
40
|
+
children: /*#__PURE__*/ _jsx("a", {
|
|
41
|
+
href: permalink,
|
|
42
|
+
class: "hover:underline",
|
|
43
|
+
children: "Read more →"
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
]
|
|
47
|
+
})
|
|
48
|
+
]
|
|
49
|
+
});
|
|
50
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image Card Component
|
|
3
|
+
*
|
|
4
|
+
* Image-first layout for type="image" posts.
|
|
5
|
+
*/ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
|
|
6
|
+
import { MediaGallery } from "../MediaGallery.js";
|
|
7
|
+
import * as sqid from "../../../lib/sqid.js";
|
|
8
|
+
import * as time from "../../../lib/time.js";
|
|
9
|
+
export const ImageCard = ({ post, compact })=>{
|
|
10
|
+
const permalink = `/p/${sqid.encode(post.id)}`;
|
|
11
|
+
if (compact) {
|
|
12
|
+
return /*#__PURE__*/ _jsxs("article", {
|
|
13
|
+
class: "h-entry timeline-card timeline-card-compact",
|
|
14
|
+
children: [
|
|
15
|
+
post.title && /*#__PURE__*/ _jsx("h2", {
|
|
16
|
+
class: "p-name text-sm font-medium mb-1",
|
|
17
|
+
children: /*#__PURE__*/ _jsx("a", {
|
|
18
|
+
href: permalink,
|
|
19
|
+
class: "u-url hover:underline",
|
|
20
|
+
children: post.title
|
|
21
|
+
})
|
|
22
|
+
}),
|
|
23
|
+
post.contentHtml && /*#__PURE__*/ _jsx("div", {
|
|
24
|
+
class: "e-content prose prose-sm text-muted-foreground",
|
|
25
|
+
dangerouslySetInnerHTML: {
|
|
26
|
+
__html: post.contentHtml
|
|
27
|
+
}
|
|
28
|
+
}),
|
|
29
|
+
/*#__PURE__*/ _jsx("footer", {
|
|
30
|
+
class: "mt-1 text-xs text-muted-foreground",
|
|
31
|
+
children: /*#__PURE__*/ _jsx("a", {
|
|
32
|
+
href: permalink,
|
|
33
|
+
class: "u-url hover:underline",
|
|
34
|
+
children: /*#__PURE__*/ _jsx("time", {
|
|
35
|
+
class: "dt-published",
|
|
36
|
+
datetime: time.toISOString(post.publishedAt),
|
|
37
|
+
children: time.formatDate(post.publishedAt)
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
]
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return /*#__PURE__*/ _jsxs("article", {
|
|
45
|
+
class: "h-entry timeline-card timeline-card-image",
|
|
46
|
+
children: [
|
|
47
|
+
post.mediaAttachments.length > 0 && /*#__PURE__*/ _jsx("div", {
|
|
48
|
+
class: "timeline-card-image-gallery",
|
|
49
|
+
children: /*#__PURE__*/ _jsx(MediaGallery, {
|
|
50
|
+
attachments: post.mediaAttachments
|
|
51
|
+
})
|
|
52
|
+
}),
|
|
53
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
54
|
+
class: "p-4",
|
|
55
|
+
children: [
|
|
56
|
+
post.title && /*#__PURE__*/ _jsx("h2", {
|
|
57
|
+
class: "p-name font-medium mb-1",
|
|
58
|
+
children: /*#__PURE__*/ _jsx("a", {
|
|
59
|
+
href: permalink,
|
|
60
|
+
class: "u-url hover:underline",
|
|
61
|
+
children: post.title
|
|
62
|
+
})
|
|
63
|
+
}),
|
|
64
|
+
post.contentHtml && /*#__PURE__*/ _jsx("div", {
|
|
65
|
+
class: "e-content prose prose-sm",
|
|
66
|
+
dangerouslySetInnerHTML: {
|
|
67
|
+
__html: post.contentHtml
|
|
68
|
+
}
|
|
69
|
+
}),
|
|
70
|
+
/*#__PURE__*/ _jsx("footer", {
|
|
71
|
+
class: "mt-2 text-xs text-muted-foreground",
|
|
72
|
+
children: /*#__PURE__*/ _jsx("a", {
|
|
73
|
+
href: permalink,
|
|
74
|
+
class: "u-url hover:underline",
|
|
75
|
+
children: /*#__PURE__*/ _jsx("time", {
|
|
76
|
+
class: "dt-published",
|
|
77
|
+
datetime: time.toISOString(post.publishedAt),
|
|
78
|
+
children: time.formatDate(post.publishedAt)
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
]
|
|
83
|
+
})
|
|
84
|
+
]
|
|
85
|
+
});
|
|
86
|
+
};
|