@jant/core 0.3.25 → 0.3.26
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 +67 -562
- package/dist/client.js +1 -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/avatar-upload.js +134 -0
- package/dist/lib/config.js +39 -0
- package/dist/lib/constants.js +10 -10
- package/dist/lib/favicon.js +102 -0
- package/dist/lib/image.js +13 -17
- package/dist/lib/media-helpers.js +2 -2
- package/dist/lib/navigation.js +23 -3
- package/dist/lib/render.js +10 -1
- package/dist/lib/schemas.js +31 -0
- package/dist/lib/timezones.js +388 -0
- package/dist/lib/view.js +1 -1
- package/dist/routes/api/posts.js +1 -1
- package/dist/routes/api/upload.js +3 -3
- package/dist/routes/auth/reset.js +221 -0
- package/dist/routes/auth/setup.js +194 -0
- package/dist/routes/auth/signin.js +176 -0
- package/dist/routes/dash/collections.js +23 -415
- package/dist/routes/dash/media.js +12 -392
- package/dist/routes/dash/pages.js +7 -330
- package/dist/routes/dash/redirects.js +18 -12
- package/dist/routes/dash/settings.js +198 -577
- package/dist/routes/feed/rss.js +2 -1
- package/dist/routes/feed/sitemap.js +4 -2
- package/dist/routes/pages/featured.js +5 -1
- package/dist/routes/pages/home.js +26 -1
- package/dist/routes/pages/latest.js +45 -0
- package/dist/services/post.js +30 -50
- package/dist/types/bindings.js +3 -0
- package/dist/types/config.js +147 -0
- package/dist/types/constants.js +27 -0
- package/dist/types/entities.js +3 -0
- package/dist/types/operations.js +3 -0
- package/dist/types/props.js +3 -0
- package/dist/types/views.js +5 -0
- package/dist/types.js +8 -111
- package/dist/ui/color-themes.js +33 -33
- package/dist/ui/compose/ComposeDialog.js +36 -21
- package/dist/ui/dash/PageForm.js +21 -15
- package/dist/ui/dash/PostForm.js +22 -16
- package/dist/ui/dash/collections/CollectionForm.js +152 -0
- package/dist/ui/dash/collections/CollectionsListContent.js +68 -0
- package/dist/ui/dash/collections/ViewCollectionContent.js +96 -0
- package/dist/ui/dash/media/MediaListContent.js +166 -0
- package/dist/ui/dash/media/ViewMediaContent.js +212 -0
- package/dist/ui/dash/pages/LinkFormContent.js +130 -0
- package/dist/ui/dash/pages/UnifiedPagesContent.js +193 -0
- package/dist/ui/dash/settings/AccountContent.js +209 -0
- package/dist/ui/dash/settings/AppearanceContent.js +259 -0
- package/dist/ui/dash/settings/GeneralContent.js +536 -0
- package/dist/ui/dash/settings/SettingsNav.js +41 -0
- package/dist/ui/font-themes.js +36 -0
- package/dist/ui/layouts/BaseLayout.js +24 -2
- package/dist/ui/layouts/SiteLayout.js +47 -19
- package/package.json +1 -1
- package/src/app.tsx +93 -553
- package/src/client.ts +1 -0
- package/src/i18n/locales/en.po +240 -175
- package/src/i18n/locales/en.ts +1 -1
- package/src/i18n/locales/zh-Hans.po +240 -175
- package/src/i18n/locales/zh-Hans.ts +1 -1
- package/src/i18n/locales/zh-Hant.po +240 -175
- package/src/i18n/locales/zh-Hant.ts +1 -1
- package/src/lib/__tests__/config.test.ts +192 -0
- package/src/lib/__tests__/favicon.test.ts +151 -0
- package/src/lib/__tests__/image.test.ts +2 -6
- package/src/lib/__tests__/timezones.test.ts +61 -0
- package/src/lib/__tests__/view.test.ts +2 -2
- package/src/lib/avatar-upload.ts +165 -0
- package/src/lib/config.ts +47 -0
- package/src/lib/constants.ts +19 -11
- package/src/lib/favicon.ts +115 -0
- package/src/lib/image.ts +13 -21
- package/src/lib/media-helpers.ts +2 -2
- package/src/lib/navigation.ts +33 -2
- package/src/lib/render.tsx +15 -1
- package/src/lib/schemas.ts +39 -0
- package/src/lib/timezones.ts +325 -0
- package/src/lib/view.ts +1 -1
- package/src/routes/api/posts.ts +1 -1
- package/src/routes/api/upload.ts +2 -3
- package/src/routes/auth/reset.tsx +239 -0
- package/src/routes/auth/setup.tsx +189 -0
- package/src/routes/auth/signin.tsx +163 -0
- package/src/routes/dash/__tests__/settings-avatar.test.ts +89 -0
- package/src/routes/dash/collections.tsx +17 -366
- package/src/routes/dash/media.tsx +12 -414
- package/src/routes/dash/pages.tsx +8 -348
- package/src/routes/dash/redirects.tsx +20 -14
- package/src/routes/dash/settings.tsx +243 -534
- package/src/routes/feed/__tests__/rss.test.ts +141 -0
- package/src/routes/feed/rss.ts +3 -1
- package/src/routes/feed/sitemap.ts +4 -2
- package/src/routes/pages/featured.tsx +7 -1
- package/src/routes/pages/home.tsx +25 -2
- package/src/routes/pages/latest.tsx +59 -0
- package/src/services/post.ts +34 -66
- package/src/styles/components.css +0 -65
- package/src/styles/tokens.css +1 -1
- package/src/styles/ui.css +24 -40
- package/src/types/bindings.ts +30 -0
- package/src/types/config.ts +183 -0
- package/src/types/constants.ts +26 -0
- package/src/types/entities.ts +109 -0
- package/src/types/operations.ts +88 -0
- package/src/types/props.ts +115 -0
- package/src/types/views.ts +172 -0
- package/src/types.ts +8 -644
- package/src/ui/__tests__/font-themes.test.ts +34 -0
- package/src/ui/color-themes.ts +34 -34
- package/src/ui/compose/ComposeDialog.tsx +40 -21
- package/src/ui/dash/PageForm.tsx +25 -19
- package/src/ui/dash/PostForm.tsx +26 -20
- package/src/ui/dash/collections/CollectionForm.tsx +153 -0
- package/src/ui/dash/collections/CollectionsListContent.tsx +85 -0
- package/src/ui/dash/collections/ViewCollectionContent.tsx +92 -0
- package/src/ui/dash/media/MediaListContent.tsx +201 -0
- package/src/ui/dash/media/ViewMediaContent.tsx +208 -0
- package/src/ui/dash/pages/LinkFormContent.tsx +119 -0
- package/src/ui/dash/pages/UnifiedPagesContent.tsx +203 -0
- package/src/ui/dash/settings/AccountContent.tsx +176 -0
- package/src/ui/dash/settings/AppearanceContent.tsx +254 -0
- package/src/ui/dash/settings/GeneralContent.tsx +533 -0
- package/src/ui/dash/settings/SettingsNav.tsx +56 -0
- package/src/ui/font-themes.ts +54 -0
- package/src/ui/layouts/BaseLayout.tsx +17 -0
- package/src/ui/layouts/SiteLayout.tsx +45 -31
package/dist/routes/feed/rss.js
CHANGED
|
@@ -14,10 +14,11 @@ export const rssRoutes = new Hono();
|
|
|
14
14
|
const siteDescription = all["SITE_DESCRIPTION"] ?? "";
|
|
15
15
|
const siteUrl = c.env.SITE_URL;
|
|
16
16
|
const siteLanguage = await getSiteLanguage(c);
|
|
17
|
+
const feedLimit = parseInt(c.env.RSS_FEED_LIMIT ?? "50", 10) || 50;
|
|
17
18
|
const posts = await c.var.services.posts.list({
|
|
18
19
|
status: "published",
|
|
19
20
|
excludeReplies: true,
|
|
20
|
-
limit:
|
|
21
|
+
limit: feedLimit
|
|
21
22
|
});
|
|
22
23
|
// Batch load media for enclosures
|
|
23
24
|
const postIds = posts.map((p)=>p.id);
|
|
@@ -32,10 +32,12 @@ sitemapRoutes.get("/sitemap.xml", async (c)=>{
|
|
|
32
32
|
});
|
|
33
33
|
});
|
|
34
34
|
// robots.txt
|
|
35
|
-
sitemapRoutes.get("/robots.txt", (c)=>{
|
|
35
|
+
sitemapRoutes.get("/robots.txt", async (c)=>{
|
|
36
36
|
const siteUrl = c.env.SITE_URL;
|
|
37
|
+
const noindex = await c.var.services.settings.get("NOINDEX") === "true";
|
|
38
|
+
const directive = noindex ? "Disallow: /" : "Allow: /";
|
|
37
39
|
const robots = `User-agent: *
|
|
38
|
-
|
|
40
|
+
${directive}
|
|
39
41
|
|
|
40
42
|
Sitemap: ${siteUrl}/sitemap.xml
|
|
41
43
|
`;
|
|
@@ -10,12 +10,16 @@ import { createMediaContext, toPostViewsFromPosts } from "../../lib/view.js";
|
|
|
10
10
|
import { FeaturedPage } from "../../ui/pages/FeaturedPage.js";
|
|
11
11
|
export const featuredRoutes = new Hono();
|
|
12
12
|
featuredRoutes.get("/", async (c)=>{
|
|
13
|
+
const navData = await getNavigationData(c);
|
|
14
|
+
// When homepage already shows featured, redirect to avoid duplicate content
|
|
15
|
+
if (navData.homeDefaultView === "featured") {
|
|
16
|
+
return c.redirect("/", 302);
|
|
17
|
+
}
|
|
13
18
|
const posts = await c.var.services.posts.list({
|
|
14
19
|
featured: true,
|
|
15
20
|
status: "published",
|
|
16
21
|
excludeReplies: true
|
|
17
22
|
});
|
|
18
|
-
const navData = await getNavigationData(c);
|
|
19
23
|
const mediaCtx = createMediaContext(c);
|
|
20
24
|
const postViews = toPostViewsFromPosts(posts, mediaCtx);
|
|
21
25
|
// Convert to timeline items (simple — no thread previews)
|
|
@@ -4,20 +4,45 @@ import { jsx as _jsx } from "hono/jsx/jsx-runtime";
|
|
|
4
4
|
*
|
|
5
5
|
* Timeline feed with per-type card components and thread previews.
|
|
6
6
|
* Uses page-based pagination.
|
|
7
|
+
*
|
|
8
|
+
* When HOME_DEFAULT_VIEW is "featured", the homepage shows featured posts
|
|
9
|
+
* instead of latest. The /latest route always shows latest posts explicitly.
|
|
7
10
|
*/ import { Hono } from "hono";
|
|
8
11
|
import { getNavigationData } from "../../lib/navigation.js";
|
|
9
12
|
import { renderPublicPage } from "../../lib/render.js";
|
|
10
13
|
import { assembleTimeline } from "../../lib/timeline.js";
|
|
11
14
|
import { createMediaContext, toPostViewsFromPosts } from "../../lib/view.js";
|
|
12
15
|
import { HomePage } from "../../ui/pages/HomePage.js";
|
|
16
|
+
import { FeaturedPage } from "../../ui/pages/FeaturedPage.js";
|
|
13
17
|
export const homeRoutes = new Hono();
|
|
14
18
|
homeRoutes.get("/", async (c)=>{
|
|
19
|
+
const navData = await getNavigationData(c);
|
|
20
|
+
if (navData.homeDefaultView === "featured") {
|
|
21
|
+
// Show featured posts on homepage
|
|
22
|
+
const posts = await c.var.services.posts.list({
|
|
23
|
+
featured: true,
|
|
24
|
+
status: "published",
|
|
25
|
+
excludeReplies: true
|
|
26
|
+
});
|
|
27
|
+
const mediaCtx = createMediaContext(c);
|
|
28
|
+
const postViews = toPostViewsFromPosts(posts, mediaCtx);
|
|
29
|
+
const items = postViews.map((post)=>({
|
|
30
|
+
post
|
|
31
|
+
}));
|
|
32
|
+
return renderPublicPage(c, {
|
|
33
|
+
title: navData.siteName,
|
|
34
|
+
navData,
|
|
35
|
+
content: /*#__PURE__*/ _jsx(FeaturedPage, {
|
|
36
|
+
items: items
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
// Default: show latest posts
|
|
15
41
|
const pageParam = c.req.query("page");
|
|
16
42
|
const page = pageParam ? Math.max(1, parseInt(pageParam, 10) || 1) : 1;
|
|
17
43
|
const { items, currentPage, totalPages } = await assembleTimeline(c, {
|
|
18
44
|
page
|
|
19
45
|
});
|
|
20
|
-
const navData = await getNavigationData(c);
|
|
21
46
|
// Fetch pinned posts
|
|
22
47
|
const pinnedPosts = await c.var.services.posts.list({
|
|
23
48
|
pinned: true,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx } from "hono/jsx/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Latest Page Route
|
|
4
|
+
*
|
|
5
|
+
* Explicit /latest URL that always shows the latest posts timeline.
|
|
6
|
+
* When HOME_DEFAULT_VIEW is "latest" (default), this redirects to /
|
|
7
|
+
* to avoid duplicate content. When it's "featured", this serves as
|
|
8
|
+
* the explicit latest view.
|
|
9
|
+
*/ import { Hono } from "hono";
|
|
10
|
+
import { getNavigationData } from "../../lib/navigation.js";
|
|
11
|
+
import { renderPublicPage } from "../../lib/render.js";
|
|
12
|
+
import { assembleTimeline } from "../../lib/timeline.js";
|
|
13
|
+
import { createMediaContext, toPostViewsFromPosts } from "../../lib/view.js";
|
|
14
|
+
import { HomePage } from "../../ui/pages/HomePage.js";
|
|
15
|
+
export const latestRoutes = new Hono();
|
|
16
|
+
latestRoutes.get("/", async (c)=>{
|
|
17
|
+
const navData = await getNavigationData(c);
|
|
18
|
+
// When homepage already shows latest, redirect to avoid duplicate content
|
|
19
|
+
if (navData.homeDefaultView !== "featured") {
|
|
20
|
+
return c.redirect("/", 302);
|
|
21
|
+
}
|
|
22
|
+
const pageParam = c.req.query("page");
|
|
23
|
+
const page = pageParam ? Math.max(1, parseInt(pageParam, 10) || 1) : 1;
|
|
24
|
+
const { items, currentPage, totalPages } = await assembleTimeline(c, {
|
|
25
|
+
page
|
|
26
|
+
});
|
|
27
|
+
// Fetch pinned posts
|
|
28
|
+
const pinnedPosts = await c.var.services.posts.list({
|
|
29
|
+
pinned: true,
|
|
30
|
+
status: "published",
|
|
31
|
+
excludeReplies: true
|
|
32
|
+
});
|
|
33
|
+
const mediaCtx = createMediaContext(c);
|
|
34
|
+
const pinnedItems = toPostViewsFromPosts(pinnedPosts, mediaCtx);
|
|
35
|
+
return renderPublicPage(c, {
|
|
36
|
+
title: `Latest - ${navData.siteName}`,
|
|
37
|
+
navData,
|
|
38
|
+
content: /*#__PURE__*/ _jsx(HomePage, {
|
|
39
|
+
items: items,
|
|
40
|
+
pinnedItems: pinnedItems,
|
|
41
|
+
currentPage: currentPage,
|
|
42
|
+
totalPages: totalPages
|
|
43
|
+
})
|
|
44
|
+
});
|
|
45
|
+
});
|
package/dist/services/post.js
CHANGED
|
@@ -9,6 +9,34 @@ import { posts } from "../db/schema.js";
|
|
|
9
9
|
import { now } from "../lib/time.js";
|
|
10
10
|
import { render as renderMarkdown } from "../lib/markdown.js";
|
|
11
11
|
export function createPostService(db) {
|
|
12
|
+
/** Build WHERE conditions from filters (shared by list and count) */ function buildFilterConditions(filters) {
|
|
13
|
+
const conditions = [];
|
|
14
|
+
if (filters.status) {
|
|
15
|
+
conditions.push(eq(posts.status, filters.status));
|
|
16
|
+
}
|
|
17
|
+
if (filters.featured !== undefined) {
|
|
18
|
+
conditions.push(eq(posts.featured, filters.featured ? 1 : 0));
|
|
19
|
+
}
|
|
20
|
+
if (filters.pinned !== undefined) {
|
|
21
|
+
conditions.push(eq(posts.pinned, filters.pinned ? 1 : 0));
|
|
22
|
+
}
|
|
23
|
+
if (filters.format) {
|
|
24
|
+
conditions.push(eq(posts.format, filters.format));
|
|
25
|
+
}
|
|
26
|
+
if (filters.collectionId !== undefined) {
|
|
27
|
+
conditions.push(eq(posts.collectionId, filters.collectionId));
|
|
28
|
+
}
|
|
29
|
+
if (filters.threadId) {
|
|
30
|
+
conditions.push(eq(posts.threadId, filters.threadId));
|
|
31
|
+
}
|
|
32
|
+
if (filters.excludeReplies) {
|
|
33
|
+
conditions.push(isNull(posts.threadId));
|
|
34
|
+
}
|
|
35
|
+
if (!filters.includeDeleted) {
|
|
36
|
+
conditions.push(isNull(posts.deletedAt));
|
|
37
|
+
}
|
|
38
|
+
return conditions;
|
|
39
|
+
}
|
|
12
40
|
function toPost(row) {
|
|
13
41
|
return {
|
|
14
42
|
id: row.id,
|
|
@@ -42,31 +70,7 @@ export function createPostService(db) {
|
|
|
42
70
|
return result[0] ? toPost(result[0]) : null;
|
|
43
71
|
},
|
|
44
72
|
async list (filters = {}) {
|
|
45
|
-
const conditions =
|
|
46
|
-
if (filters.status) {
|
|
47
|
-
conditions.push(eq(posts.status, filters.status));
|
|
48
|
-
}
|
|
49
|
-
if (filters.featured !== undefined) {
|
|
50
|
-
conditions.push(eq(posts.featured, filters.featured ? 1 : 0));
|
|
51
|
-
}
|
|
52
|
-
if (filters.pinned !== undefined) {
|
|
53
|
-
conditions.push(eq(posts.pinned, filters.pinned ? 1 : 0));
|
|
54
|
-
}
|
|
55
|
-
if (filters.format) {
|
|
56
|
-
conditions.push(eq(posts.format, filters.format));
|
|
57
|
-
}
|
|
58
|
-
if (filters.collectionId !== undefined) {
|
|
59
|
-
conditions.push(eq(posts.collectionId, filters.collectionId));
|
|
60
|
-
}
|
|
61
|
-
if (filters.threadId) {
|
|
62
|
-
conditions.push(eq(posts.threadId, filters.threadId));
|
|
63
|
-
}
|
|
64
|
-
if (filters.excludeReplies) {
|
|
65
|
-
conditions.push(isNull(posts.threadId));
|
|
66
|
-
}
|
|
67
|
-
if (!filters.includeDeleted) {
|
|
68
|
-
conditions.push(isNull(posts.deletedAt));
|
|
69
|
-
}
|
|
73
|
+
const conditions = buildFilterConditions(filters);
|
|
70
74
|
if (filters.cursor) {
|
|
71
75
|
conditions.push(sql`${posts.id} < ${filters.cursor}`);
|
|
72
76
|
}
|
|
@@ -78,31 +82,7 @@ export function createPostService(db) {
|
|
|
78
82
|
return rows.map(toPost);
|
|
79
83
|
},
|
|
80
84
|
async count (filters = {}) {
|
|
81
|
-
const conditions =
|
|
82
|
-
if (filters.status) {
|
|
83
|
-
conditions.push(eq(posts.status, filters.status));
|
|
84
|
-
}
|
|
85
|
-
if (filters.featured !== undefined) {
|
|
86
|
-
conditions.push(eq(posts.featured, filters.featured ? 1 : 0));
|
|
87
|
-
}
|
|
88
|
-
if (filters.pinned !== undefined) {
|
|
89
|
-
conditions.push(eq(posts.pinned, filters.pinned ? 1 : 0));
|
|
90
|
-
}
|
|
91
|
-
if (filters.format) {
|
|
92
|
-
conditions.push(eq(posts.format, filters.format));
|
|
93
|
-
}
|
|
94
|
-
if (filters.collectionId !== undefined) {
|
|
95
|
-
conditions.push(eq(posts.collectionId, filters.collectionId));
|
|
96
|
-
}
|
|
97
|
-
if (filters.threadId) {
|
|
98
|
-
conditions.push(eq(posts.threadId, filters.threadId));
|
|
99
|
-
}
|
|
100
|
-
if (filters.excludeReplies) {
|
|
101
|
-
conditions.push(isNull(posts.threadId));
|
|
102
|
-
}
|
|
103
|
-
if (!filters.includeDeleted) {
|
|
104
|
-
conditions.push(isNull(posts.deletedAt));
|
|
105
|
-
}
|
|
85
|
+
const conditions = buildFilterConditions(filters);
|
|
106
86
|
const result = await db.select({
|
|
107
87
|
count: sql`count(*)`.as("count")
|
|
108
88
|
}).from(posts).where(conditions.length > 0 ? and(...conditions) : undefined);
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration System
|
|
3
|
+
*
|
|
4
|
+
* Single Source of Truth for all configuration fields.
|
|
5
|
+
*/ /**
|
|
6
|
+
* Configuration Registry - Single Source of Truth
|
|
7
|
+
*
|
|
8
|
+
* All available configuration fields with their metadata.
|
|
9
|
+
* Add new fields here, and they'll automatically work everywhere.
|
|
10
|
+
*
|
|
11
|
+
* Priority logic:
|
|
12
|
+
* - envOnly: false -> User-configurable (DB > ENV > Default)
|
|
13
|
+
* - envOnly: true -> Environment-only (ENV > Default)
|
|
14
|
+
*/ export const CONFIG_FIELDS = {
|
|
15
|
+
// User-configurable (can be modified in dashboard)
|
|
16
|
+
SITE_NAME: {
|
|
17
|
+
defaultValue: "Jant",
|
|
18
|
+
envOnly: false
|
|
19
|
+
},
|
|
20
|
+
SITE_DESCRIPTION: {
|
|
21
|
+
defaultValue: "A microblog powered by Jant",
|
|
22
|
+
envOnly: false
|
|
23
|
+
},
|
|
24
|
+
SITE_LANGUAGE: {
|
|
25
|
+
defaultValue: "en",
|
|
26
|
+
envOnly: false
|
|
27
|
+
},
|
|
28
|
+
HOME_DEFAULT_VIEW: {
|
|
29
|
+
defaultValue: "latest",
|
|
30
|
+
envOnly: false
|
|
31
|
+
},
|
|
32
|
+
// Environment-only (deployment/infrastructure config)
|
|
33
|
+
SITE_URL: {
|
|
34
|
+
defaultValue: "",
|
|
35
|
+
envOnly: true
|
|
36
|
+
},
|
|
37
|
+
AUTH_SECRET: {
|
|
38
|
+
defaultValue: "",
|
|
39
|
+
envOnly: true
|
|
40
|
+
},
|
|
41
|
+
R2_PUBLIC_URL: {
|
|
42
|
+
defaultValue: "",
|
|
43
|
+
envOnly: true
|
|
44
|
+
},
|
|
45
|
+
IMAGE_TRANSFORM_URL: {
|
|
46
|
+
defaultValue: "",
|
|
47
|
+
envOnly: true
|
|
48
|
+
},
|
|
49
|
+
DEMO_EMAIL: {
|
|
50
|
+
defaultValue: "",
|
|
51
|
+
envOnly: true
|
|
52
|
+
},
|
|
53
|
+
DEMO_PASSWORD: {
|
|
54
|
+
defaultValue: "",
|
|
55
|
+
envOnly: true
|
|
56
|
+
},
|
|
57
|
+
PAGE_SIZE: {
|
|
58
|
+
defaultValue: "20",
|
|
59
|
+
envOnly: true
|
|
60
|
+
},
|
|
61
|
+
STORAGE_DRIVER: {
|
|
62
|
+
defaultValue: "r2",
|
|
63
|
+
envOnly: true
|
|
64
|
+
},
|
|
65
|
+
S3_ENDPOINT: {
|
|
66
|
+
defaultValue: "",
|
|
67
|
+
envOnly: true
|
|
68
|
+
},
|
|
69
|
+
S3_BUCKET: {
|
|
70
|
+
defaultValue: "",
|
|
71
|
+
envOnly: true
|
|
72
|
+
},
|
|
73
|
+
S3_ACCESS_KEY_ID: {
|
|
74
|
+
defaultValue: "",
|
|
75
|
+
envOnly: true
|
|
76
|
+
},
|
|
77
|
+
S3_SECRET_ACCESS_KEY: {
|
|
78
|
+
defaultValue: "",
|
|
79
|
+
envOnly: true
|
|
80
|
+
},
|
|
81
|
+
S3_REGION: {
|
|
82
|
+
defaultValue: "auto",
|
|
83
|
+
envOnly: true
|
|
84
|
+
},
|
|
85
|
+
S3_PUBLIC_URL: {
|
|
86
|
+
defaultValue: "",
|
|
87
|
+
envOnly: true
|
|
88
|
+
},
|
|
89
|
+
// Internal settings (DB-only, not configurable via env or dashboard)
|
|
90
|
+
THEME: {
|
|
91
|
+
defaultValue: "",
|
|
92
|
+
envOnly: false,
|
|
93
|
+
internal: true
|
|
94
|
+
},
|
|
95
|
+
CUSTOM_CSS: {
|
|
96
|
+
defaultValue: "",
|
|
97
|
+
envOnly: false,
|
|
98
|
+
internal: true
|
|
99
|
+
},
|
|
100
|
+
SITE_AVATAR: {
|
|
101
|
+
defaultValue: "",
|
|
102
|
+
envOnly: false,
|
|
103
|
+
internal: true
|
|
104
|
+
},
|
|
105
|
+
SHOW_HEADER_AVATAR: {
|
|
106
|
+
defaultValue: "",
|
|
107
|
+
envOnly: false,
|
|
108
|
+
internal: true
|
|
109
|
+
},
|
|
110
|
+
SITE_FAVICON_ICO: {
|
|
111
|
+
defaultValue: "",
|
|
112
|
+
envOnly: false,
|
|
113
|
+
internal: true
|
|
114
|
+
},
|
|
115
|
+
SITE_FAVICON_APPLE_TOUCH: {
|
|
116
|
+
defaultValue: "",
|
|
117
|
+
envOnly: false,
|
|
118
|
+
internal: true
|
|
119
|
+
},
|
|
120
|
+
FONT_THEME: {
|
|
121
|
+
defaultValue: "",
|
|
122
|
+
envOnly: false,
|
|
123
|
+
internal: true
|
|
124
|
+
},
|
|
125
|
+
TIME_ZONE: {
|
|
126
|
+
defaultValue: "UTC",
|
|
127
|
+
envOnly: false
|
|
128
|
+
},
|
|
129
|
+
SITE_FOOTER: {
|
|
130
|
+
defaultValue: "",
|
|
131
|
+
envOnly: false
|
|
132
|
+
},
|
|
133
|
+
NOINDEX: {
|
|
134
|
+
defaultValue: "",
|
|
135
|
+
envOnly: false
|
|
136
|
+
},
|
|
137
|
+
ONBOARDING_STATUS: {
|
|
138
|
+
defaultValue: "pending",
|
|
139
|
+
envOnly: false,
|
|
140
|
+
internal: true
|
|
141
|
+
},
|
|
142
|
+
PASSWORD_RESET_TOKEN: {
|
|
143
|
+
defaultValue: "",
|
|
144
|
+
envOnly: false,
|
|
145
|
+
internal: true
|
|
146
|
+
}
|
|
147
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Type Constants
|
|
3
|
+
*/ export const FORMATS = [
|
|
4
|
+
"note",
|
|
5
|
+
"link",
|
|
6
|
+
"quote"
|
|
7
|
+
];
|
|
8
|
+
export const STATUSES = [
|
|
9
|
+
"draft",
|
|
10
|
+
"published"
|
|
11
|
+
];
|
|
12
|
+
export const SORT_ORDERS = [
|
|
13
|
+
"newest",
|
|
14
|
+
"oldest",
|
|
15
|
+
"rating_desc",
|
|
16
|
+
"rating_asc"
|
|
17
|
+
];
|
|
18
|
+
export const NAV_ITEM_TYPES = [
|
|
19
|
+
"page",
|
|
20
|
+
"link"
|
|
21
|
+
];
|
|
22
|
+
export const MAX_MEDIA_ATTACHMENTS = 20;
|
|
23
|
+
export const MAX_PINNED_POSTS = 3;
|
|
24
|
+
export const STORAGE_DRIVERS = [
|
|
25
|
+
"r2",
|
|
26
|
+
"s3"
|
|
27
|
+
];
|
package/dist/types.js
CHANGED
|
@@ -1,114 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Jant Type Definitions (v2)
|
|
3
|
-
*/ // =============================================================================
|
|
4
|
-
// Content Types
|
|
5
|
-
// =============================================================================
|
|
6
|
-
export const FORMATS = [
|
|
7
|
-
"note",
|
|
8
|
-
"link",
|
|
9
|
-
"quote"
|
|
10
|
-
];
|
|
11
|
-
export const STATUSES = [
|
|
12
|
-
"draft",
|
|
13
|
-
"published"
|
|
14
|
-
];
|
|
15
|
-
export const SORT_ORDERS = [
|
|
16
|
-
"newest",
|
|
17
|
-
"oldest",
|
|
18
|
-
"rating_desc",
|
|
19
|
-
"rating_asc"
|
|
20
|
-
];
|
|
21
|
-
export const NAV_ITEM_TYPES = [
|
|
22
|
-
"page",
|
|
23
|
-
"link"
|
|
24
|
-
];
|
|
25
|
-
export const MAX_MEDIA_ATTACHMENTS = 20;
|
|
26
|
-
export const MAX_PINNED_POSTS = 3;
|
|
27
|
-
export const STORAGE_DRIVERS = [
|
|
28
|
-
"r2",
|
|
29
|
-
"s3"
|
|
30
|
-
];
|
|
31
|
-
// =============================================================================
|
|
32
|
-
// Configuration System
|
|
33
|
-
// =============================================================================
|
|
34
|
-
/**
|
|
35
|
-
* Configuration Registry - Single Source of Truth
|
|
36
|
-
*
|
|
37
|
-
* All available configuration fields with their metadata.
|
|
38
|
-
* Add new fields here, and they'll automatically work everywhere.
|
|
39
3
|
*
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
*
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
},
|
|
49
|
-
SITE_DESCRIPTION: {
|
|
50
|
-
defaultValue: "A microblog powered by Jant",
|
|
51
|
-
envOnly: false
|
|
52
|
-
},
|
|
53
|
-
SITE_LANGUAGE: {
|
|
54
|
-
defaultValue: "en",
|
|
55
|
-
envOnly: false
|
|
56
|
-
},
|
|
57
|
-
// Environment-only (deployment/infrastructure config)
|
|
58
|
-
SITE_URL: {
|
|
59
|
-
defaultValue: "",
|
|
60
|
-
envOnly: true
|
|
61
|
-
},
|
|
62
|
-
AUTH_SECRET: {
|
|
63
|
-
defaultValue: "",
|
|
64
|
-
envOnly: true
|
|
65
|
-
},
|
|
66
|
-
R2_PUBLIC_URL: {
|
|
67
|
-
defaultValue: "",
|
|
68
|
-
envOnly: true
|
|
69
|
-
},
|
|
70
|
-
IMAGE_TRANSFORM_URL: {
|
|
71
|
-
defaultValue: "",
|
|
72
|
-
envOnly: true
|
|
73
|
-
},
|
|
74
|
-
DEMO_EMAIL: {
|
|
75
|
-
defaultValue: "",
|
|
76
|
-
envOnly: true
|
|
77
|
-
},
|
|
78
|
-
DEMO_PASSWORD: {
|
|
79
|
-
defaultValue: "",
|
|
80
|
-
envOnly: true
|
|
81
|
-
},
|
|
82
|
-
PAGE_SIZE: {
|
|
83
|
-
defaultValue: "20",
|
|
84
|
-
envOnly: true
|
|
85
|
-
},
|
|
86
|
-
STORAGE_DRIVER: {
|
|
87
|
-
defaultValue: "r2",
|
|
88
|
-
envOnly: true
|
|
89
|
-
},
|
|
90
|
-
S3_ENDPOINT: {
|
|
91
|
-
defaultValue: "",
|
|
92
|
-
envOnly: true
|
|
93
|
-
},
|
|
94
|
-
S3_BUCKET: {
|
|
95
|
-
defaultValue: "",
|
|
96
|
-
envOnly: true
|
|
97
|
-
},
|
|
98
|
-
S3_ACCESS_KEY_ID: {
|
|
99
|
-
defaultValue: "",
|
|
100
|
-
envOnly: true
|
|
101
|
-
},
|
|
102
|
-
S3_SECRET_ACCESS_KEY: {
|
|
103
|
-
defaultValue: "",
|
|
104
|
-
envOnly: true
|
|
105
|
-
},
|
|
106
|
-
S3_REGION: {
|
|
107
|
-
defaultValue: "auto",
|
|
108
|
-
envOnly: true
|
|
109
|
-
},
|
|
110
|
-
S3_PUBLIC_URL: {
|
|
111
|
-
defaultValue: "",
|
|
112
|
-
envOnly: true
|
|
113
|
-
}
|
|
114
|
-
};
|
|
4
|
+
* Barrel re-export from focused submodules.
|
|
5
|
+
*/ export * from "./types/constants.js";
|
|
6
|
+
export * from "./types/bindings.js";
|
|
7
|
+
export * from "./types/config.js";
|
|
8
|
+
export * from "./types/entities.js";
|
|
9
|
+
export * from "./types/operations.js";
|
|
10
|
+
export * from "./types/views.js";
|
|
11
|
+
export * from "./types/props.js";
|
package/dist/ui/color-themes.js
CHANGED
|
@@ -71,9 +71,39 @@
|
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
export const BUILTIN_COLOR_THEMES = [
|
|
74
|
+
defineTheme({
|
|
75
|
+
id: "halloween",
|
|
76
|
+
name: "Halloween",
|
|
77
|
+
preview: {
|
|
78
|
+
lightBg: "#f9f2e3",
|
|
79
|
+
lightText: "#352200",
|
|
80
|
+
lightLink: "#b84400",
|
|
81
|
+
darkBg: "#1e1000",
|
|
82
|
+
darkText: "#dfc390",
|
|
83
|
+
darkLink: "#ff8c00"
|
|
84
|
+
},
|
|
85
|
+
light: {
|
|
86
|
+
bg: "oklch(0.97 0.015 75)",
|
|
87
|
+
fg: "oklch(0.25 0.04 55)",
|
|
88
|
+
primary: "oklch(0.47 0.17 50)",
|
|
89
|
+
primaryFg: "oklch(0.98 0.01 75)",
|
|
90
|
+
muted: "oklch(0.93 0.02 75)",
|
|
91
|
+
mutedFg: "oklch(0.5 0.025 55)",
|
|
92
|
+
border: "oklch(0.88 0.025 75)"
|
|
93
|
+
},
|
|
94
|
+
dark: {
|
|
95
|
+
bg: "oklch(0.16 0.03 50)",
|
|
96
|
+
fg: "oklch(0.85 0.025 75)",
|
|
97
|
+
primary: "oklch(0.72 0.19 55)",
|
|
98
|
+
primaryFg: "oklch(0.14 0.03 50)",
|
|
99
|
+
muted: "oklch(0.22 0.025 50)",
|
|
100
|
+
mutedFg: "oklch(0.62 0.02 75)",
|
|
101
|
+
border: "oklch(0.28 0.025 50)"
|
|
102
|
+
}
|
|
103
|
+
}),
|
|
74
104
|
{
|
|
75
105
|
id: "default",
|
|
76
|
-
name: "
|
|
106
|
+
name: "Panda",
|
|
77
107
|
light: {},
|
|
78
108
|
dark: {},
|
|
79
109
|
preview: {
|
|
@@ -175,36 +205,6 @@ export const BUILTIN_COLOR_THEMES = [
|
|
|
175
205
|
border: "oklch(0.3 0 0)"
|
|
176
206
|
}
|
|
177
207
|
}),
|
|
178
|
-
defineTheme({
|
|
179
|
-
id: "halloween",
|
|
180
|
-
name: "Halloween",
|
|
181
|
-
preview: {
|
|
182
|
-
lightBg: "#f9f2e3",
|
|
183
|
-
lightText: "#352200",
|
|
184
|
-
lightLink: "#cc5500",
|
|
185
|
-
darkBg: "#1e1000",
|
|
186
|
-
darkText: "#dfc390",
|
|
187
|
-
darkLink: "#ff8c00"
|
|
188
|
-
},
|
|
189
|
-
light: {
|
|
190
|
-
bg: "oklch(0.97 0.015 75)",
|
|
191
|
-
fg: "oklch(0.25 0.04 55)",
|
|
192
|
-
primary: "oklch(0.6 0.2 50)",
|
|
193
|
-
primaryFg: "oklch(0.98 0.01 75)",
|
|
194
|
-
muted: "oklch(0.93 0.02 75)",
|
|
195
|
-
mutedFg: "oklch(0.5 0.025 55)",
|
|
196
|
-
border: "oklch(0.88 0.025 75)"
|
|
197
|
-
},
|
|
198
|
-
dark: {
|
|
199
|
-
bg: "oklch(0.16 0.03 50)",
|
|
200
|
-
fg: "oklch(0.85 0.025 75)",
|
|
201
|
-
primary: "oklch(0.72 0.19 55)",
|
|
202
|
-
primaryFg: "oklch(0.14 0.03 50)",
|
|
203
|
-
muted: "oklch(0.22 0.025 50)",
|
|
204
|
-
mutedFg: "oklch(0.62 0.02 75)",
|
|
205
|
-
border: "oklch(0.28 0.025 50)"
|
|
206
|
-
}
|
|
207
|
-
}),
|
|
208
208
|
defineTheme({
|
|
209
209
|
id: "notepad",
|
|
210
210
|
name: "Notepad",
|
|
@@ -241,7 +241,7 @@ export const BUILTIN_COLOR_THEMES = [
|
|
|
241
241
|
preview: {
|
|
242
242
|
lightBg: "#f7eef5",
|
|
243
243
|
lightText: "#2e1e2c",
|
|
244
|
-
lightLink: "#
|
|
244
|
+
lightLink: "#7a30a8",
|
|
245
245
|
darkBg: "#1d1428",
|
|
246
246
|
darkText: "#d4c2d0",
|
|
247
247
|
darkLink: "#c080fc"
|
|
@@ -249,7 +249,7 @@ export const BUILTIN_COLOR_THEMES = [
|
|
|
249
249
|
light: {
|
|
250
250
|
bg: "oklch(0.97 0.012 325)",
|
|
251
251
|
fg: "oklch(0.25 0.02 310)",
|
|
252
|
-
primary: "oklch(0.
|
|
252
|
+
primary: "oklch(0.45 0.2 300)",
|
|
253
253
|
primaryFg: "oklch(0.98 0.008 325)",
|
|
254
254
|
muted: "oklch(0.93 0.016 325)",
|
|
255
255
|
mutedFg: "oklch(0.52 0.015 310)",
|