@jant/core 0.0.1
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/bin/jant.js +188 -0
- package/drizzle.config.ts +10 -0
- package/lingui.config.ts +16 -0
- package/package.json +116 -0
- package/src/app.tsx +377 -0
- package/src/assets/datastar.min.js +8 -0
- package/src/auth.ts +38 -0
- package/src/client.ts +6 -0
- package/src/db/index.ts +14 -0
- package/src/db/migrations/0000_solid_moon_knight.sql +118 -0
- package/src/db/migrations/0001_add_search_fts.sql +40 -0
- package/src/db/migrations/0002_collection_path.sql +2 -0
- package/src/db/migrations/0003_collection_path_nullable.sql +21 -0
- package/src/db/migrations/0004_media_uuid.sql +35 -0
- package/src/db/migrations/meta/0000_snapshot.json +784 -0
- package/src/db/migrations/meta/_journal.json +41 -0
- package/src/db/schema.ts +159 -0
- package/src/i18n/EXAMPLES.md +235 -0
- package/src/i18n/README.md +296 -0
- package/src/i18n/Trans.tsx +31 -0
- package/src/i18n/context.tsx +101 -0
- package/src/i18n/detect.ts +100 -0
- package/src/i18n/i18n.ts +62 -0
- package/src/i18n/index.ts +65 -0
- package/src/i18n/locales/en.po +875 -0
- package/src/i18n/locales/en.ts +1 -0
- package/src/i18n/locales/zh-Hans.po +875 -0
- package/src/i18n/locales/zh-Hans.ts +1 -0
- package/src/i18n/locales/zh-Hant.po +875 -0
- package/src/i18n/locales/zh-Hant.ts +1 -0
- package/src/i18n/locales.ts +14 -0
- package/src/i18n/middleware.ts +59 -0
- package/src/index.ts +42 -0
- package/src/lib/assets.ts +47 -0
- package/src/lib/constants.ts +67 -0
- package/src/lib/image.ts +107 -0
- package/src/lib/index.ts +9 -0
- package/src/lib/markdown.ts +93 -0
- package/src/lib/schemas.ts +92 -0
- package/src/lib/sqid.ts +79 -0
- package/src/lib/sse.ts +152 -0
- package/src/lib/time.ts +117 -0
- package/src/lib/url.ts +107 -0
- package/src/middleware/auth.ts +59 -0
- package/src/routes/api/posts.ts +127 -0
- package/src/routes/api/search.ts +53 -0
- package/src/routes/api/upload.ts +240 -0
- package/src/routes/dash/collections.tsx +341 -0
- package/src/routes/dash/index.tsx +89 -0
- package/src/routes/dash/media.tsx +551 -0
- package/src/routes/dash/pages.tsx +245 -0
- package/src/routes/dash/posts.tsx +202 -0
- package/src/routes/dash/redirects.tsx +155 -0
- package/src/routes/dash/settings.tsx +93 -0
- package/src/routes/feed/rss.ts +119 -0
- package/src/routes/feed/sitemap.ts +75 -0
- package/src/routes/pages/archive.tsx +223 -0
- package/src/routes/pages/collection.tsx +79 -0
- package/src/routes/pages/home.tsx +93 -0
- package/src/routes/pages/page.tsx +64 -0
- package/src/routes/pages/post.tsx +81 -0
- package/src/routes/pages/search.tsx +162 -0
- package/src/services/collection.ts +180 -0
- package/src/services/index.ts +40 -0
- package/src/services/media.ts +97 -0
- package/src/services/post.ts +279 -0
- package/src/services/redirect.ts +74 -0
- package/src/services/search.ts +117 -0
- package/src/services/settings.ts +76 -0
- package/src/theme/components/ActionButtons.tsx +98 -0
- package/src/theme/components/CrudPageHeader.tsx +48 -0
- package/src/theme/components/DangerZone.tsx +77 -0
- package/src/theme/components/EmptyState.tsx +56 -0
- package/src/theme/components/ListItemRow.tsx +24 -0
- package/src/theme/components/PageForm.tsx +114 -0
- package/src/theme/components/Pagination.tsx +196 -0
- package/src/theme/components/PostForm.tsx +122 -0
- package/src/theme/components/PostList.tsx +68 -0
- package/src/theme/components/ThreadView.tsx +118 -0
- package/src/theme/components/TypeBadge.tsx +28 -0
- package/src/theme/components/VisibilityBadge.tsx +33 -0
- package/src/theme/components/index.ts +12 -0
- package/src/theme/index.ts +24 -0
- package/src/theme/layouts/BaseLayout.tsx +49 -0
- package/src/theme/layouts/DashLayout.tsx +108 -0
- package/src/theme/layouts/index.ts +2 -0
- package/src/theme/styles/main.css +52 -0
- package/src/types.ts +222 -0
- package/static/assets/datastar.min.js +7 -0
- package/static/assets/image-processor.js +234 -0
- package/tsconfig.json +16 -0
- package/vite.config.ts +82 -0
- package/wrangler.toml +21 -0
package/bin/jant.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Jant CLI
|
|
5
|
+
*
|
|
6
|
+
* Commands:
|
|
7
|
+
* swizzle <component> [--wrap|--eject] - Override a theme component
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
11
|
+
import { resolve, dirname } from "path";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = dirname(__filename);
|
|
16
|
+
|
|
17
|
+
// Available components that can be swizzled
|
|
18
|
+
const SWIZZLABLE_COMPONENTS = {
|
|
19
|
+
PostCard: {
|
|
20
|
+
file: "PostCard.tsx",
|
|
21
|
+
props: "PostCardProps",
|
|
22
|
+
},
|
|
23
|
+
PostList: {
|
|
24
|
+
file: "PostList.tsx",
|
|
25
|
+
props: "PostListProps",
|
|
26
|
+
},
|
|
27
|
+
Pagination: {
|
|
28
|
+
file: "Pagination.tsx",
|
|
29
|
+
props: "PaginationProps",
|
|
30
|
+
},
|
|
31
|
+
EmptyState: {
|
|
32
|
+
file: "EmptyState.tsx",
|
|
33
|
+
props: "EmptyStateProps",
|
|
34
|
+
},
|
|
35
|
+
BaseLayout: {
|
|
36
|
+
file: "BaseLayout.tsx",
|
|
37
|
+
props: "BaseLayoutProps",
|
|
38
|
+
isLayout: true,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function showHelp() {
|
|
43
|
+
console.log(`
|
|
44
|
+
Jant CLI
|
|
45
|
+
|
|
46
|
+
Usage:
|
|
47
|
+
jant swizzle <component> [options]
|
|
48
|
+
|
|
49
|
+
Commands:
|
|
50
|
+
swizzle <component> Override a theme component
|
|
51
|
+
|
|
52
|
+
Options:
|
|
53
|
+
--wrap Create a wrapper around the original component (default)
|
|
54
|
+
--eject Copy the full component source for complete customization
|
|
55
|
+
--list List available components
|
|
56
|
+
|
|
57
|
+
Examples:
|
|
58
|
+
jant swizzle PostCard # Wrap PostCard component
|
|
59
|
+
jant swizzle PostCard --eject # Copy PostCard source
|
|
60
|
+
jant swizzle --list # List all swizzlable components
|
|
61
|
+
`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function listComponents() {
|
|
65
|
+
console.log("\nAvailable components to swizzle:\n");
|
|
66
|
+
for (const [name, info] of Object.entries(SWIZZLABLE_COMPONENTS)) {
|
|
67
|
+
const type = info.isLayout ? "[Layout]" : "[Component]";
|
|
68
|
+
console.log(` ${name.padEnd(15)} ${type}`);
|
|
69
|
+
}
|
|
70
|
+
console.log("\nUsage: jant swizzle <component> [--wrap|--eject]\n");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function generateWrapperCode(componentName, info) {
|
|
74
|
+
const importPath = info.isLayout
|
|
75
|
+
? "@jant/core/theme/layouts"
|
|
76
|
+
: "@jant/core/theme/components";
|
|
77
|
+
|
|
78
|
+
return `/**
|
|
79
|
+
* Custom ${componentName} component
|
|
80
|
+
*
|
|
81
|
+
* This is a wrapper around the original ${componentName}.
|
|
82
|
+
* You can customize the rendering while keeping the original functionality.
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
import type { ${info.props} } from "@jant/core";
|
|
86
|
+
import { ${componentName} as Original${componentName} } from "${importPath}";
|
|
87
|
+
|
|
88
|
+
export function ${componentName}(props: ${info.props}) {
|
|
89
|
+
// Add your customizations here
|
|
90
|
+
return (
|
|
91
|
+
<div class="custom-${componentName.toLowerCase()}-wrapper">
|
|
92
|
+
<Original${componentName} {...props} />
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function swizzle(componentName, mode) {
|
|
100
|
+
const info = SWIZZLABLE_COMPONENTS[componentName];
|
|
101
|
+
if (!info) {
|
|
102
|
+
console.error(`Error: Unknown component "${componentName}"`);
|
|
103
|
+
console.log("\nAvailable components:");
|
|
104
|
+
listComponents();
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const targetDir = info.isLayout
|
|
109
|
+
? resolve(process.cwd(), "src/theme/layouts")
|
|
110
|
+
: resolve(process.cwd(), "src/theme/components");
|
|
111
|
+
|
|
112
|
+
const targetFile = resolve(targetDir, info.file);
|
|
113
|
+
|
|
114
|
+
// Check if file already exists
|
|
115
|
+
if (existsSync(targetFile)) {
|
|
116
|
+
console.error(`Error: ${targetFile} already exists`);
|
|
117
|
+
console.log("Remove it first if you want to re-swizzle.");
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Create directory if needed
|
|
122
|
+
mkdirSync(targetDir, { recursive: true });
|
|
123
|
+
|
|
124
|
+
if (mode === "eject") {
|
|
125
|
+
// For eject mode, we'd need to copy the actual source
|
|
126
|
+
// For now, show a message about where to find it
|
|
127
|
+
console.log(`
|
|
128
|
+
To eject ${componentName}, copy the source from:
|
|
129
|
+
node_modules/@jant/core/src/theme/${info.isLayout ? "layouts" : "components"}/${info.file}
|
|
130
|
+
|
|
131
|
+
Then modify it as needed.
|
|
132
|
+
`);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Generate wrapper code
|
|
137
|
+
const code = generateWrapperCode(componentName, info);
|
|
138
|
+
writeFileSync(targetFile, code, "utf-8");
|
|
139
|
+
|
|
140
|
+
console.log(`
|
|
141
|
+
✓ Created ${targetFile}
|
|
142
|
+
|
|
143
|
+
Next steps:
|
|
144
|
+
1. Customize the component in the generated file
|
|
145
|
+
2. Import it in your src/index.ts:
|
|
146
|
+
|
|
147
|
+
import { ${componentName} } from "./theme/${info.isLayout ? "layouts" : "components"}/${componentName}";
|
|
148
|
+
|
|
149
|
+
export default createApp({
|
|
150
|
+
theme: {
|
|
151
|
+
components: {
|
|
152
|
+
${componentName},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Parse arguments
|
|
160
|
+
const args = process.argv.slice(2);
|
|
161
|
+
|
|
162
|
+
if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
163
|
+
showHelp();
|
|
164
|
+
process.exit(0);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const command = args[0];
|
|
168
|
+
|
|
169
|
+
if (command === "swizzle") {
|
|
170
|
+
if (args.includes("--list")) {
|
|
171
|
+
listComponents();
|
|
172
|
+
process.exit(0);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const componentName = args[1];
|
|
176
|
+
if (!componentName) {
|
|
177
|
+
console.error("Error: Component name required");
|
|
178
|
+
console.log("Usage: jant swizzle <component> [--wrap|--eject]");
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const mode = args.includes("--eject") ? "eject" : "wrap";
|
|
183
|
+
swizzle(componentName, mode);
|
|
184
|
+
} else {
|
|
185
|
+
console.error(`Unknown command: ${command}`);
|
|
186
|
+
showHelp();
|
|
187
|
+
process.exit(1);
|
|
188
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { defineConfig } from "drizzle-kit";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
schema: "./src/db/schema.ts",
|
|
5
|
+
out: "./src/db/migrations",
|
|
6
|
+
dialect: "sqlite",
|
|
7
|
+
dbCredentials: {
|
|
8
|
+
url: ".wrangler/state/v3/d1/miniflare-D1DatabaseObject/local.sqlite",
|
|
9
|
+
},
|
|
10
|
+
});
|
package/lingui.config.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { LinguiConfig } from "@lingui/conf";
|
|
2
|
+
|
|
3
|
+
const config: LinguiConfig = {
|
|
4
|
+
locales: ["en", "zh-Hans", "zh-Hant"],
|
|
5
|
+
sourceLocale: "en",
|
|
6
|
+
catalogs: [
|
|
7
|
+
{
|
|
8
|
+
path: "<rootDir>/src/i18n/locales/{locale}",
|
|
9
|
+
include: ["<rootDir>/src/**/*.{ts,tsx}"],
|
|
10
|
+
},
|
|
11
|
+
],
|
|
12
|
+
format: "po",
|
|
13
|
+
compileNamespace: "ts",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default config;
|
package/package.json
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jant/core",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A modern, open-source microblogging platform built on Cloudflare Workers",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"jant": "./bin/jant.js"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./src/index.ts",
|
|
11
|
+
"./theme": "./src/theme/index.ts",
|
|
12
|
+
"./theme/*": "./src/theme/*",
|
|
13
|
+
"./src/*": "./src/*",
|
|
14
|
+
"./static/*": "./static/*"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"bin",
|
|
18
|
+
"src",
|
|
19
|
+
"static",
|
|
20
|
+
"migrations",
|
|
21
|
+
"drizzle.config.ts",
|
|
22
|
+
"lingui.config.ts",
|
|
23
|
+
"postcss.config.js",
|
|
24
|
+
"tailwind.config.ts",
|
|
25
|
+
"tsconfig.json",
|
|
26
|
+
"vite.config.ts",
|
|
27
|
+
"wrangler.toml"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"dev": "pnpm db:migrate:local && vite dev",
|
|
31
|
+
"dev:debug": "pnpm db:migrate:local && vite dev --port 19019",
|
|
32
|
+
"build": "vite build",
|
|
33
|
+
"deploy": "pnpm build && wrangler deploy",
|
|
34
|
+
"preview": "vite preview",
|
|
35
|
+
"typecheck": "tsc --noEmit",
|
|
36
|
+
"lint": "eslint src/",
|
|
37
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
|
|
38
|
+
"format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
|
|
39
|
+
"db:generate": "drizzle-kit generate",
|
|
40
|
+
"db:migrate:local": "wrangler d1 migrations apply DB --local",
|
|
41
|
+
"db:migrate:remote": "wrangler d1 migrations apply DB --remote",
|
|
42
|
+
"i18n:extract": "lingui extract",
|
|
43
|
+
"i18n:compile": "lingui compile --typescript",
|
|
44
|
+
"i18n:build": "pnpm i18n:extract && pnpm i18n:compile",
|
|
45
|
+
"prepare": "husky"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@lingui/core": "^5.9.0",
|
|
49
|
+
"better-auth": "^1.4.18",
|
|
50
|
+
"drizzle-orm": "^0.45.1",
|
|
51
|
+
"hono": "^4.11.7",
|
|
52
|
+
"marked": "^17.0.1",
|
|
53
|
+
"sqids": "^0.3.0",
|
|
54
|
+
"uuidv7": "^1.1.0",
|
|
55
|
+
"zod": "^4.3.6"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@babel/cli": "^7.28.6",
|
|
59
|
+
"@babel/core": "^7.29.0",
|
|
60
|
+
"@babel/preset-typescript": "^7.28.5",
|
|
61
|
+
"@cloudflare/vite-plugin": "^1.22.1",
|
|
62
|
+
"@cloudflare/workers-types": "^4.20260131.0",
|
|
63
|
+
"@eslint/js": "^9.39.2",
|
|
64
|
+
"@lingui/babel-plugin-lingui-macro": "^5.9.0",
|
|
65
|
+
"@lingui/cli": "^5.9.0",
|
|
66
|
+
"@lingui/format-json": "^5.9.0",
|
|
67
|
+
"@lingui/format-po": "^5.9.0",
|
|
68
|
+
"@lingui/swc-plugin": "^5.10.1",
|
|
69
|
+
"@swc/core": "^1.15.11",
|
|
70
|
+
"@tailwindcss/cli": "^4.1.18",
|
|
71
|
+
"@tailwindcss/postcss": "^4.1.18",
|
|
72
|
+
"@types/node": "^25.1.0",
|
|
73
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
74
|
+
"@typescript-eslint/parser": "^8.54.0",
|
|
75
|
+
"autoprefixer": "^10.4.24",
|
|
76
|
+
"basecoat-css": "^0.3.10",
|
|
77
|
+
"drizzle-kit": "^0.31.8",
|
|
78
|
+
"esbuild-plugin-lingui-macro": "^1.0.1",
|
|
79
|
+
"eslint": "^9.39.2",
|
|
80
|
+
"eslint-plugin-react": "^7.37.5",
|
|
81
|
+
"glob": "^13.0.0",
|
|
82
|
+
"husky": "^9.1.7",
|
|
83
|
+
"lint-staged": "^16.2.7",
|
|
84
|
+
"postcss": "^8.5.6",
|
|
85
|
+
"prettier": "^3.8.1",
|
|
86
|
+
"tailwindcss": "^4.1.18",
|
|
87
|
+
"tsx": "^4.21.0",
|
|
88
|
+
"typescript": "^5.9.3",
|
|
89
|
+
"unplugin-swc": "^1.5.9",
|
|
90
|
+
"vite": "^7.3.1",
|
|
91
|
+
"wrangler": "^4.61.1"
|
|
92
|
+
},
|
|
93
|
+
"repository": {
|
|
94
|
+
"type": "git",
|
|
95
|
+
"url": "https://github.com/jant-me/jant.git",
|
|
96
|
+
"directory": "packages/core"
|
|
97
|
+
},
|
|
98
|
+
"keywords": [
|
|
99
|
+
"jant",
|
|
100
|
+
"microblog",
|
|
101
|
+
"cloudflare",
|
|
102
|
+
"workers",
|
|
103
|
+
"hono",
|
|
104
|
+
"d1",
|
|
105
|
+
"r2"
|
|
106
|
+
],
|
|
107
|
+
"author": "Jant Contributors",
|
|
108
|
+
"license": "MIT",
|
|
109
|
+
"bugs": {
|
|
110
|
+
"url": "https://github.com/jant-me/jant/issues"
|
|
111
|
+
},
|
|
112
|
+
"homepage": "https://jant.me",
|
|
113
|
+
"engines": {
|
|
114
|
+
"node": ">=24.0.0"
|
|
115
|
+
}
|
|
116
|
+
}
|