@jant/core 0.3.6 → 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 +11 -21
- package/dist/client.js +1 -0
- package/dist/db/schema.js +15 -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/index.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/schemas.js +32 -2
- package/dist/lib/sse.js +7 -8
- package/dist/lib/theme-components.js +49 -0
- package/dist/routes/api/posts.js +101 -5
- package/dist/routes/api/timeline.js +115 -0
- package/dist/routes/api/upload.js +9 -5
- package/dist/routes/dash/media.js +38 -0
- package/dist/routes/dash/navigation.js +274 -0
- package/dist/routes/dash/posts.js +45 -6
- package/dist/routes/feed/rss.js +10 -1
- package/dist/routes/pages/archive.js +14 -27
- package/dist/routes/pages/collection.js +10 -19
- package/dist/routes/pages/home.js +88 -98
- package/dist/routes/pages/page.js +19 -38
- package/dist/routes/pages/post.js +61 -48
- package/dist/routes/pages/search.js +13 -26
- package/dist/services/collection.js +13 -0
- package/dist/services/index.js +3 -1
- package/dist/services/media.js +55 -2
- package/dist/services/navigation.js +115 -0
- package/dist/services/post.js +26 -1
- package/dist/theme/components/MediaGallery.js +107 -0
- package/dist/theme/components/PostForm.js +158 -2
- package/dist/theme/components/PostList.js +5 -0
- package/dist/theme/components/index.js +3 -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/dist/types.js +27 -0
- package/package.json +3 -2
- package/src/__tests__/helpers/app.ts +6 -1
- package/src/__tests__/helpers/db.ts +20 -0
- package/src/app.tsx +11 -25
- package/src/client.ts +1 -0
- package/src/db/migrations/0002_add_media_attachments.sql +3 -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 +15 -0
- package/src/i18n/locales/en.po +170 -58
- package/src/i18n/locales/en.ts +1 -1
- package/src/i18n/locales/zh-Hans.po +162 -71
- package/src/i18n/locales/zh-Hans.ts +1 -1
- package/src/i18n/locales/zh-Hant.po +162 -71
- package/src/i18n/locales/zh-Hant.ts +1 -1
- package/src/index.ts +13 -1
- package/src/lib/__tests__/schemas.test.ts +89 -1
- package/src/lib/__tests__/sse.test.ts +13 -1
- 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/schemas.ts +47 -1
- package/src/lib/sse.ts +10 -11
- package/src/lib/theme-components.ts +76 -0
- package/src/routes/api/__tests__/posts.test.ts +239 -0
- package/src/routes/api/__tests__/timeline.test.ts +242 -0
- package/src/routes/api/posts.ts +134 -5
- package/src/routes/api/timeline.tsx +145 -0
- package/src/routes/api/upload.ts +9 -5
- package/src/routes/dash/media.tsx +50 -0
- package/src/routes/dash/navigation.tsx +306 -0
- package/src/routes/dash/posts.tsx +79 -7
- package/src/routes/feed/rss.ts +14 -1
- package/src/routes/pages/archive.tsx +15 -23
- package/src/routes/pages/collection.tsx +8 -15
- package/src/routes/pages/home.tsx +121 -88
- package/src/routes/pages/page.tsx +17 -30
- package/src/routes/pages/post.tsx +64 -40
- package/src/routes/pages/search.tsx +18 -22
- package/src/services/__tests__/collection.test.ts +102 -0
- package/src/services/__tests__/media.test.ts +282 -7
- package/src/services/__tests__/navigation.test.ts +213 -0
- package/src/services/__tests__/post-timeline.test.ts +220 -0
- package/src/services/collection.ts +19 -0
- package/src/services/index.ts +7 -0
- package/src/services/media.ts +78 -2
- 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/MediaGallery.tsx +128 -0
- package/src/theme/components/PostForm.tsx +170 -2
- package/src/theme/components/PostList.tsx +7 -0
- package/src/theme/components/index.ts +13 -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 +97 -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 -1507
- 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 -113
- 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 -31
- 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 -27
- 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/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 -11
- 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 -13
- 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 -213
- package/dist/types.d.ts.map +0 -1
|
@@ -107,6 +107,14 @@ function DashLayoutContent({ siteName, currentPath, children }) {
|
|
|
107
107
|
message: "Redirects"
|
|
108
108
|
})
|
|
109
109
|
}),
|
|
110
|
+
/*#__PURE__*/ _jsx("a", {
|
|
111
|
+
href: "/dash/navigation",
|
|
112
|
+
class: navClass("/dash/navigation", /^\/dash\/navigation/),
|
|
113
|
+
children: $__i18n._({
|
|
114
|
+
id: "UxKoFf",
|
|
115
|
+
message: "Navigation"
|
|
116
|
+
})
|
|
117
|
+
}),
|
|
110
118
|
/*#__PURE__*/ _jsx("a", {
|
|
111
119
|
href: "/dash/settings",
|
|
112
120
|
class: navClass("/dash/settings", /^\/dash\/settings/),
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Site Layout
|
|
3
|
+
*
|
|
4
|
+
* Two-column layout for public pages with sidebar navigation.
|
|
5
|
+
* On mobile, uses a slide-out drawer menu.
|
|
6
|
+
*/ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
|
|
7
|
+
/**
|
|
8
|
+
* Determine if a navigation link is active based on the current path.
|
|
9
|
+
*
|
|
10
|
+
* @param linkUrl - The link's URL
|
|
11
|
+
* @param currentPath - The current page path
|
|
12
|
+
* @returns Whether the link should be shown as active
|
|
13
|
+
*/ function isLinkActive(linkUrl, currentPath) {
|
|
14
|
+
// External links are never active
|
|
15
|
+
if (linkUrl.startsWith("http://") || linkUrl.startsWith("https://")) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
// Exact match for home
|
|
19
|
+
if (linkUrl === "/") {
|
|
20
|
+
return currentPath === "/";
|
|
21
|
+
}
|
|
22
|
+
// Prefix match for other internal links
|
|
23
|
+
return currentPath === linkUrl || currentPath.startsWith(linkUrl + "/");
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Check if a URL is external
|
|
27
|
+
*/ function isExternalUrl(url) {
|
|
28
|
+
return url.startsWith("http://") || url.startsWith("https://");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Render navigation links with dot indicator for active state.
|
|
32
|
+
*/ function NavLinks({ navigationLinks, currentPath }) {
|
|
33
|
+
return /*#__PURE__*/ _jsx(_Fragment, {
|
|
34
|
+
children: navigationLinks.map((link)=>{
|
|
35
|
+
const active = isLinkActive(link.url, currentPath);
|
|
36
|
+
const external = isExternalUrl(link.url);
|
|
37
|
+
return /*#__PURE__*/ _jsxs("a", {
|
|
38
|
+
href: link.url,
|
|
39
|
+
class: `text-sm flex items-center gap-2 py-0.5 ${active ? "text-primary font-medium" : "text-muted-foreground hover:text-foreground"}`,
|
|
40
|
+
...external ? {
|
|
41
|
+
target: "_blank",
|
|
42
|
+
rel: "noopener noreferrer"
|
|
43
|
+
} : {},
|
|
44
|
+
children: [
|
|
45
|
+
/*#__PURE__*/ _jsx("span", {
|
|
46
|
+
class: `size-1.5 rounded-full shrink-0 ${active ? "bg-primary" : "bg-transparent"}`
|
|
47
|
+
}),
|
|
48
|
+
link.label,
|
|
49
|
+
external && /*#__PURE__*/ _jsx("span", {
|
|
50
|
+
class: "ml-1 text-xs opacity-50",
|
|
51
|
+
children: "↗"
|
|
52
|
+
})
|
|
53
|
+
]
|
|
54
|
+
}, link.id);
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export const SiteLayout = ({ siteName, navigationLinks, currentPath, children })=>{
|
|
59
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
60
|
+
class: "container py-8 md:flex md:gap-12",
|
|
61
|
+
"data-signals": JSON.stringify({
|
|
62
|
+
_drawerOpen: false
|
|
63
|
+
}),
|
|
64
|
+
children: [
|
|
65
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
66
|
+
class: "flex items-center justify-between mb-6 md:hidden",
|
|
67
|
+
children: [
|
|
68
|
+
/*#__PURE__*/ _jsx("a", {
|
|
69
|
+
href: "/",
|
|
70
|
+
class: "text-xl font-semibold",
|
|
71
|
+
children: siteName
|
|
72
|
+
}),
|
|
73
|
+
/*#__PURE__*/ _jsx("button", {
|
|
74
|
+
"data-on:click": "$_drawerOpen = true",
|
|
75
|
+
class: "p-2 -mr-2 text-muted-foreground hover:text-foreground",
|
|
76
|
+
"aria-label": "Open menu",
|
|
77
|
+
children: /*#__PURE__*/ _jsx("svg", {
|
|
78
|
+
class: "size-5",
|
|
79
|
+
fill: "none",
|
|
80
|
+
viewBox: "0 0 24 24",
|
|
81
|
+
"stroke-width": "1.5",
|
|
82
|
+
stroke: "currentColor",
|
|
83
|
+
children: /*#__PURE__*/ _jsx("path", {
|
|
84
|
+
"stroke-linecap": "round",
|
|
85
|
+
"stroke-linejoin": "round",
|
|
86
|
+
d: "M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
]
|
|
91
|
+
}),
|
|
92
|
+
/*#__PURE__*/ _jsx("div", {
|
|
93
|
+
class: "fixed inset-0 bg-black/50 z-40 opacity-0 pointer-events-none transition-opacity duration-300 ease-in-out md:hidden",
|
|
94
|
+
"data-class": "{'opacity-100 pointer-events-auto': $_drawerOpen, 'opacity-0 pointer-events-none': !$_drawerOpen}",
|
|
95
|
+
"data-on:click": "$_drawerOpen = false"
|
|
96
|
+
}),
|
|
97
|
+
/*#__PURE__*/ _jsxs("aside", {
|
|
98
|
+
class: "fixed inset-y-0 left-0 w-64 bg-background z-50 p-6 overflow-y-auto shadow-lg -translate-x-full transition-transform duration-300 ease-in-out md:hidden",
|
|
99
|
+
"data-class": "{'translate-x-0': $_drawerOpen, '-translate-x-full': !$_drawerOpen}",
|
|
100
|
+
children: [
|
|
101
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
102
|
+
class: "flex items-center justify-between mb-8",
|
|
103
|
+
children: [
|
|
104
|
+
/*#__PURE__*/ _jsx("a", {
|
|
105
|
+
href: "/",
|
|
106
|
+
class: "text-xl font-semibold",
|
|
107
|
+
children: siteName
|
|
108
|
+
}),
|
|
109
|
+
/*#__PURE__*/ _jsx("button", {
|
|
110
|
+
"data-on:click": "$_drawerOpen = false",
|
|
111
|
+
class: "p-2 -mr-2 text-muted-foreground hover:text-foreground",
|
|
112
|
+
"aria-label": "Close menu",
|
|
113
|
+
children: /*#__PURE__*/ _jsx("svg", {
|
|
114
|
+
class: "size-5",
|
|
115
|
+
fill: "none",
|
|
116
|
+
viewBox: "0 0 24 24",
|
|
117
|
+
"stroke-width": "1.5",
|
|
118
|
+
stroke: "currentColor",
|
|
119
|
+
children: /*#__PURE__*/ _jsx("path", {
|
|
120
|
+
"stroke-linecap": "round",
|
|
121
|
+
"stroke-linejoin": "round",
|
|
122
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
123
|
+
})
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
]
|
|
127
|
+
}),
|
|
128
|
+
/*#__PURE__*/ _jsx("nav", {
|
|
129
|
+
class: "flex flex-col gap-0.5",
|
|
130
|
+
children: /*#__PURE__*/ _jsx(NavLinks, {
|
|
131
|
+
navigationLinks: navigationLinks,
|
|
132
|
+
currentPath: currentPath
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
]
|
|
136
|
+
}),
|
|
137
|
+
/*#__PURE__*/ _jsxs("aside", {
|
|
138
|
+
class: "hidden md:block md:w-48 md:shrink-0 md:sticky md:top-8 md:self-start",
|
|
139
|
+
children: [
|
|
140
|
+
/*#__PURE__*/ _jsx("a", {
|
|
141
|
+
href: "/",
|
|
142
|
+
class: "text-xl font-semibold block mb-20",
|
|
143
|
+
children: siteName
|
|
144
|
+
}),
|
|
145
|
+
/*#__PURE__*/ _jsx("nav", {
|
|
146
|
+
class: "flex flex-col gap-0.5",
|
|
147
|
+
children: /*#__PURE__*/ _jsx(NavLinks, {
|
|
148
|
+
navigationLinks: navigationLinks,
|
|
149
|
+
currentPath: currentPath
|
|
150
|
+
})
|
|
151
|
+
})
|
|
152
|
+
]
|
|
153
|
+
}),
|
|
154
|
+
/*#__PURE__*/ _jsx("main", {
|
|
155
|
+
class: "flex-1 min-w-0",
|
|
156
|
+
children: children
|
|
157
|
+
})
|
|
158
|
+
]
|
|
159
|
+
});
|
|
160
|
+
};
|
package/dist/types.js
CHANGED
|
@@ -11,6 +11,33 @@ export const POST_TYPES = [
|
|
|
11
11
|
"image",
|
|
12
12
|
"page"
|
|
13
13
|
];
|
|
14
|
+
export const MAX_MEDIA_ATTACHMENTS = 20;
|
|
15
|
+
/**
|
|
16
|
+
* Media attachment rules per post type.
|
|
17
|
+
* Each entry is [min, max] or null (no media allowed).
|
|
18
|
+
*/ export const POST_TYPE_MEDIA_RULES = {
|
|
19
|
+
note: [
|
|
20
|
+
0,
|
|
21
|
+
20
|
|
22
|
+
],
|
|
23
|
+
article: [
|
|
24
|
+
0,
|
|
25
|
+
20
|
|
26
|
+
],
|
|
27
|
+
image: [
|
|
28
|
+
1,
|
|
29
|
+
20
|
|
30
|
+
],
|
|
31
|
+
link: [
|
|
32
|
+
0,
|
|
33
|
+
1
|
|
34
|
+
],
|
|
35
|
+
quote: [
|
|
36
|
+
0,
|
|
37
|
+
20
|
|
38
|
+
],
|
|
39
|
+
page: null
|
|
40
|
+
};
|
|
14
41
|
export const VISIBILITY_LEVELS = [
|
|
15
42
|
"featured",
|
|
16
43
|
"quiet",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jant/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"description": "A modern, open-source microblogging platform built on Cloudflare Workers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"drizzle-orm": "^0.45.1",
|
|
38
38
|
"hono": "^4.11.7",
|
|
39
39
|
"marked": "^17.0.1",
|
|
40
|
+
"sortablejs": "^1.15.6",
|
|
40
41
|
"sqids": "^0.3.0",
|
|
41
42
|
"uuidv7": "^1.1.0",
|
|
42
43
|
"vite-ssr-components": "^0.5.2",
|
|
@@ -90,7 +91,7 @@
|
|
|
90
91
|
"build": "pnpm build:lib",
|
|
91
92
|
"build:lib": "swc src -d dist --strip-leading-paths --ignore '**/__tests__/**' && pnpm build:types",
|
|
92
93
|
"build:types": "tsc -p tsconfig.build.json",
|
|
93
|
-
"typecheck": "tsc --noEmit
|
|
94
|
+
"typecheck": "tsc --noEmit",
|
|
94
95
|
"db:generate": "drizzle-kit generate",
|
|
95
96
|
"i18n:extract": "lingui extract",
|
|
96
97
|
"i18n:compile": "lingui compile --typescript",
|
|
@@ -49,8 +49,13 @@ export function createTestApp(options: TestAppOptions = {}) {
|
|
|
49
49
|
|
|
50
50
|
const app = new Hono<Env>();
|
|
51
51
|
|
|
52
|
-
// Inject services middleware
|
|
52
|
+
// Inject env bindings and services middleware
|
|
53
53
|
app.use("*", async (c, next) => {
|
|
54
|
+
// Provide mock env bindings so c.env.* works in route handlers
|
|
55
|
+
c.env = {
|
|
56
|
+
SITE_URL: "http://localhost:9019",
|
|
57
|
+
} as AppVariables["services"] extends never ? never : Bindings;
|
|
58
|
+
|
|
54
59
|
c.set("services", services as AppVariables["services"]);
|
|
55
60
|
c.set("config", {});
|
|
56
61
|
|
|
@@ -79,6 +79,26 @@ export function createTestDatabase(options?: { fts?: boolean }) {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
// Apply media attachments migration (position + blurhash)
|
|
83
|
+
const migration2 = readFileSync(
|
|
84
|
+
resolve(MIGRATIONS_DIR, "0002_add_media_attachments.sql"),
|
|
85
|
+
"utf-8",
|
|
86
|
+
);
|
|
87
|
+
for (const sql of migration2.split("--> statement-breakpoint")) {
|
|
88
|
+
const trimmed = sql.trim();
|
|
89
|
+
if (trimmed) sqlite.exec(trimmed);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Apply navigation links migration
|
|
93
|
+
const migration3 = readFileSync(
|
|
94
|
+
resolve(MIGRATIONS_DIR, "0003_add_navigation_links.sql"),
|
|
95
|
+
"utf-8",
|
|
96
|
+
);
|
|
97
|
+
for (const sql of migration3.split("--> statement-breakpoint")) {
|
|
98
|
+
const trimmed = sql.trim();
|
|
99
|
+
if (trimmed) sqlite.exec(trimmed);
|
|
100
|
+
}
|
|
101
|
+
|
|
82
102
|
const db = drizzle(sqlite, { schema });
|
|
83
103
|
|
|
84
104
|
return { db, sqlite };
|
package/src/app.tsx
CHANGED
|
@@ -29,11 +29,13 @@ import { mediaRoutes as dashMediaRoutes } from "./routes/dash/media.js";
|
|
|
29
29
|
import { settingsRoutes as dashSettingsRoutes } from "./routes/dash/settings.js";
|
|
30
30
|
import { redirectsRoutes as dashRedirectsRoutes } from "./routes/dash/redirects.js";
|
|
31
31
|
import { collectionsRoutes as dashCollectionsRoutes } from "./routes/dash/collections.js";
|
|
32
|
+
import { navigationRoutes as dashNavigationRoutes } from "./routes/dash/navigation.js";
|
|
32
33
|
|
|
33
34
|
// Routes - API
|
|
34
35
|
import { postsApiRoutes } from "./routes/api/posts.js";
|
|
35
36
|
import { uploadApiRoutes } from "./routes/api/upload.js";
|
|
36
37
|
import { searchApiRoutes } from "./routes/api/search.js";
|
|
38
|
+
import { timelineApiRoutes } from "./routes/api/timeline.js";
|
|
37
39
|
|
|
38
40
|
// Routes - Feed
|
|
39
41
|
import { rssRoutes } from "./routes/feed/rss.js";
|
|
@@ -168,6 +170,7 @@ export function createApp(config: JantConfig = {}): App {
|
|
|
168
170
|
|
|
169
171
|
// API Routes
|
|
170
172
|
app.route("/api/posts", postsApiRoutes);
|
|
173
|
+
app.route("/api/timeline", timelineApiRoutes);
|
|
171
174
|
|
|
172
175
|
// Setup page component
|
|
173
176
|
const SetupContent: FC = () => {
|
|
@@ -411,32 +414,14 @@ export function createApp(config: JantConfig = {}): App {
|
|
|
411
414
|
const { email, password } = body;
|
|
412
415
|
|
|
413
416
|
try {
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
{
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
body: JSON.stringify({ email, password }),
|
|
420
|
-
},
|
|
421
|
-
);
|
|
422
|
-
|
|
423
|
-
const response = await c.var.auth.handler(signInRequest);
|
|
424
|
-
|
|
425
|
-
if (!response.ok) {
|
|
426
|
-
return dsToast("Invalid email or password", "error");
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// Forward Set-Cookie headers from auth response
|
|
430
|
-
const cookieHeaders: Record<string, string> = {};
|
|
431
|
-
const setCookie = response.headers.get("set-cookie");
|
|
432
|
-
if (setCookie) {
|
|
433
|
-
cookieHeaders["Set-Cookie"] = setCookie;
|
|
434
|
-
}
|
|
417
|
+
const { headers } = await c.var.auth.api.signInEmail({
|
|
418
|
+
returnHeaders: true,
|
|
419
|
+
body: { email, password },
|
|
420
|
+
headers: c.req.raw.headers,
|
|
421
|
+
});
|
|
435
422
|
|
|
436
|
-
return dsRedirect("/dash", { headers
|
|
437
|
-
} catch
|
|
438
|
-
// eslint-disable-next-line no-console -- Error logging is intentional
|
|
439
|
-
console.error("Signin error:", err);
|
|
423
|
+
return dsRedirect("/dash", { headers });
|
|
424
|
+
} catch {
|
|
440
425
|
return dsToast("Invalid email or password", "error");
|
|
441
426
|
}
|
|
442
427
|
});
|
|
@@ -678,6 +663,7 @@ export function createApp(config: JantConfig = {}): App {
|
|
|
678
663
|
app.route("/dash/settings", dashSettingsRoutes);
|
|
679
664
|
app.route("/dash/redirects", dashRedirectsRoutes);
|
|
680
665
|
app.route("/dash/collections", dashCollectionsRoutes);
|
|
666
|
+
app.route("/dash/navigation", dashNavigationRoutes);
|
|
681
667
|
// API routes
|
|
682
668
|
app.route("/api/upload", uploadApiRoutes);
|
|
683
669
|
app.route("/api/search", searchApiRoutes);
|
package/src/client.ts
CHANGED