create-jant 0.3.27 → 0.3.29

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/index.js CHANGED
@@ -9,8 +9,8 @@ import path from "path";
9
9
  import { fileURLToPath } from "url";
10
10
  var __filename = fileURLToPath(import.meta.url);
11
11
  var __dirname = path.dirname(__filename);
12
- var CORE_VERSION = "0.3.27";
13
- var TEMPLATE_DIR = fs.existsSync(path.resolve(__dirname, "../template")) ? path.resolve(__dirname, "../template") : path.resolve(__dirname, "../../../templates/jant-site");
12
+ var CORE_VERSION = "0.3.29";
13
+ var TEMPLATE_DIR = fs.existsSync(path.resolve(__dirname, "../template")) ? path.resolve(__dirname, "../template") : path.resolve(__dirname, "../../../sites/demo");
14
14
  function isValidProjectName(name) {
15
15
  return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(name);
16
16
  }
@@ -40,9 +40,6 @@ function detectPackageManager() {
40
40
  function formatRunCmd(pm, script) {
41
41
  return pm === "npm" ? `npm run ${script}` : `${pm} ${script}`;
42
42
  }
43
- function formatAddCmd(pm, pkg) {
44
- return pm === "npm" ? `npm install ${pkg}` : `${pm} add ${pkg}`;
45
- }
46
43
  function runCommand(cmd, cwd) {
47
44
  try {
48
45
  execSync(cmd, { stdio: "ignore", cwd });
@@ -51,58 +48,56 @@ function runCommand(cmd, cwd) {
51
48
  return false;
52
49
  }
53
50
  }
54
- function processMarkers(content, vars) {
55
- content = content.replace(
56
- /\s*(?:\/\/|#)\s*@create-jant:\s*@remove-start[\s\S]*?(?:\/\/|#)\s*@create-jant:\s*@remove-end\n?/g,
57
- ""
58
- );
59
- content = content.replace(
60
- /^.*(?:\/\/|#)\s*@create-jant:\s*@remove\s*\n?/gm,
61
- ""
62
- );
63
- content = content.replace(
64
- /^(.+=\s*)"[^"]*"\s*(?:\/\/|#)\s*@create-jant:\s*"([^"]*)"/gm,
65
- (_, prefix, template) => {
66
- const value = template.replace(
51
+ function processAnnotations(content, vars) {
52
+ const lines = content.split("\n");
53
+ const result = [];
54
+ let removing = false;
55
+ for (const line of lines) {
56
+ if (line.trim() === "# @create-jant: @remove-start") {
57
+ removing = true;
58
+ continue;
59
+ }
60
+ if (line.trim() === "# @create-jant: @remove-end") {
61
+ removing = false;
62
+ continue;
63
+ }
64
+ if (removing) continue;
65
+ if (line.includes("# @create-jant: @remove")) {
66
+ continue;
67
+ }
68
+ const replaceMatch = line.match(/^(.+?)\s*#\s*@create-jant:\s*"(.*)"$/);
69
+ if (replaceMatch) {
70
+ const prefix = replaceMatch[1];
71
+ const newValue = replaceMatch[2];
72
+ const interpolated = newValue.replace(
67
73
  /\$\{(\w+)\}/g,
68
- (__, key) => vars[key] ?? ""
74
+ (_, key) => vars[key] ?? ""
69
75
  );
70
- return `${prefix}"${value}"`;
76
+ const valueMatch = prefix.match(/^(\s*\S+\s*=\s*)"[^"]*"(.*)$/);
77
+ if (valueMatch) {
78
+ result.push(`${valueMatch[1]}"${interpolated}"${valueMatch[2]}`);
79
+ } else {
80
+ result.push(prefix);
81
+ }
82
+ continue;
71
83
  }
72
- );
73
- return content;
84
+ result.push(line);
85
+ }
86
+ return result.join("\n");
74
87
  }
75
88
  async function copyTemplate(config) {
76
89
  const { projectName, targetDir, packageManager } = config;
77
90
  await fs.copy(TEMPLATE_DIR, targetDir, {
78
91
  filter: (src) => {
79
92
  const basename = path.basename(src);
80
- if (basename.startsWith(".DS_Store")) return false;
81
93
  if (basename === "node_modules") return false;
82
94
  if (basename === ".wrangler") return false;
83
- if (basename === ".swc") return false;
84
95
  if (basename === ".dev.vars") return false;
85
- if (basename === "pnpm-lock.yaml") return false;
86
- if (basename === "yarn.lock") return false;
87
- if (basename === "package-lock.json") return false;
88
- if (basename === "bun.lockb") return false;
89
- if (basename === "pnpm-workspace.yaml") return false;
90
- if (basename === "dist") return false;
91
- if (basename === "wrangler.demo.toml") return false;
92
- if (basename === "reset-demo.sql") return false;
93
- if (basename === "seed-demo.sql") return false;
94
- if (basename === "reset-local.sql") return false;
95
- if (basename === "seed-local.sql") return false;
96
- if (basename === "export-demo.mjs") return false;
97
- if (basename === "export-seed.mjs") return false;
98
96
  return true;
99
97
  }
100
98
  });
101
- const secretsExampleFile = ".dev.vars.example";
102
- const secretsFile = ".dev.vars";
103
99
  const renames = [
104
100
  ["_gitignore", ".gitignore"],
105
- ["_env.example", secretsExampleFile],
106
101
  ["_github", ".github"]
107
102
  ];
108
103
  for (const [from, to] of renames) {
@@ -119,17 +114,14 @@ async function copyTemplate(config) {
119
114
  if (pkg.dependencies?.["@jant/core"] === "workspace:*") {
120
115
  pkg.dependencies["@jant/core"] = `^${CORE_VERSION}`;
121
116
  }
122
- delete pkg.scripts["dev:debug"];
123
- if (packageManager !== "pnpm") {
117
+ if (packageManager !== "pnpm" && pkg.scripts) {
124
118
  delete pkg.packageManager;
125
- if (pkg.scripts) {
126
- for (const [key, value] of Object.entries(pkg.scripts)) {
127
- if (typeof value === "string") {
128
- pkg.scripts[key] = value.replace(
129
- /pnpm run (\S+)/g,
130
- (_, script) => formatRunCmd(packageManager, script)
131
- );
132
- }
119
+ for (const [key, value] of Object.entries(pkg.scripts)) {
120
+ if (typeof value === "string") {
121
+ pkg.scripts[key] = value.replace(
122
+ /pnpm run (\S+)/g,
123
+ (_, script) => formatRunCmd(packageManager, script)
124
+ );
133
125
  }
134
126
  }
135
127
  }
@@ -138,7 +130,10 @@ async function copyTemplate(config) {
138
130
  const wranglerPath = path.join(targetDir, "wrangler.toml");
139
131
  if (await fs.pathExists(wranglerPath)) {
140
132
  let content = await fs.readFile(wranglerPath, "utf-8");
141
- content = processMarkers(content, { name: projectName });
133
+ content = processAnnotations(content, { name: projectName });
134
+ if (config.s3) {
135
+ content = content.replace(/\n\[\[r2_buckets\]\][^[]*/s, "\n");
136
+ }
142
137
  await fs.writeFile(wranglerPath, content, "utf-8");
143
138
  }
144
139
  const authSecret = generateAuthSecret();
@@ -147,19 +142,6 @@ async function copyTemplate(config) {
147
142
  AUTH_SECRET=${authSecret}
148
143
  `;
149
144
  if (config.s3) {
150
- if (await fs.pathExists(wranglerPath)) {
151
- let wContent = await fs.readFile(wranglerPath, "utf-8");
152
- wContent = wContent.replace(
153
- /^# STORAGE_DRIVER = "s3"/m,
154
- 'STORAGE_DRIVER = "s3"'
155
- );
156
- wContent = wContent.replace(/^# S3_ENDPOINT = /m, "S3_ENDPOINT = ");
157
- wContent = wContent.replace(/^# S3_BUCKET = /m, "S3_BUCKET = ");
158
- wContent = wContent.replace(/^# S3_REGION = /m, "S3_REGION = ");
159
- wContent = wContent.replace(/^# S3_PUBLIC_URL = /m, "S3_PUBLIC_URL = ");
160
- wContent = wContent.replace(/\n\[\[r2_buckets\]\][^[]*/s, "\n");
161
- await fs.writeFile(wranglerPath, wContent, "utf-8");
162
- }
163
145
  devVarsContent += `
164
146
  # S3-compatible storage credentials
165
147
  S3_ACCESS_KEY_ID=
@@ -167,37 +149,10 @@ S3_SECRET_ACCESS_KEY=
167
149
  `;
168
150
  }
169
151
  await fs.writeFile(
170
- path.join(targetDir, secretsFile),
152
+ path.join(targetDir, ".dev.vars"),
171
153
  devVarsContent,
172
154
  "utf-8"
173
155
  );
174
- const viteConfigPath = path.join(targetDir, "vite.config.ts");
175
- if (await fs.pathExists(viteConfigPath)) {
176
- let content = await fs.readFile(viteConfigPath, "utf-8");
177
- content = processMarkers(content, {});
178
- await fs.writeFile(viteConfigPath, content, "utf-8");
179
- }
180
- const readmePath = path.join(targetDir, "README.md");
181
- if (packageManager !== "npm" && await fs.pathExists(readmePath)) {
182
- let readme = await fs.readFile(readmePath, "utf-8");
183
- readme = readme.replace(
184
- /npm install (\S+)/g,
185
- (_, pkg) => formatAddCmd(packageManager, pkg)
186
- );
187
- readme = readme.replace(/npm install/g, `${packageManager} install`);
188
- readme = readme.replace(
189
- /npm run (\S+)/g,
190
- (_, script) => formatRunCmd(packageManager, script)
191
- );
192
- readme = readme.replace(/npm create/g, `${packageManager} create`);
193
- await fs.writeFile(readmePath, readme, "utf-8");
194
- }
195
- if (packageManager === "pnpm") {
196
- const wsSource = path.join(TEMPLATE_DIR, "pnpm-workspace.yaml");
197
- if (await fs.pathExists(wsSource)) {
198
- await fs.copy(wsSource, path.join(targetDir, "pnpm-workspace.yaml"));
199
- }
200
- }
201
156
  }
202
157
  async function main() {
203
158
  console.log();
@@ -209,12 +164,12 @@ async function main() {
209
164
  if (args[0]) {
210
165
  projectName = args[0];
211
166
  } else if (opts.yes) {
212
- projectName = "jant-site";
167
+ projectName = "my-jant-site";
213
168
  } else {
214
169
  const result = await p.text({
215
170
  message: "What is your project name?",
216
- placeholder: "jant-site",
217
- defaultValue: "jant-site",
171
+ placeholder: "my-jant-site",
172
+ defaultValue: "my-jant-site",
218
173
  validate: (value) => {
219
174
  if (!value) return "Project name is required";
220
175
  const sanitized = toValidProjectName(value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-jant",
3
- "version": "0.3.27",
3
+ "version": "0.3.29",
4
4
  "description": "Create a new Jant project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -53,8 +53,7 @@
53
53
  "build": "tsup src/index.ts --format esm --clean --outDir dist",
54
54
  "dev": "tsup src/index.ts --format esm --watch",
55
55
  "typecheck": "tsc --noEmit",
56
- "copy-template": "rm -rf template && cp -r ../../templates/jant-site template",
57
- "prepare-template": "node scripts/prepare-template.js",
56
+ "copy-template": "rm -rf template && rsync -a --exclude node_modules --exclude .wrangler --exclude .dev.vars --exclude scripts ../../sites/demo/ template/ && mv template/.gitignore template/_gitignore && mv template/.github template/_github",
58
57
  "inject-version": "node -e \"const fs=require('fs');const v=require('../core/package.json').version;const f='dist/index.js';fs.writeFileSync(f,fs.readFileSync(f,'utf8').replace('__JANT_CORE_VERSION__',v))\"",
59
58
  "test-template": "node scripts/test-template.js"
60
59
  }
@@ -1,46 +1,14 @@
1
- # Jant Site
1
+ # Jant
2
2
 
3
- A personal website/blog powered by [Jant](https://github.com/jant-me/jant).
3
+ A personal microblogging system self-hosted, single-author, and stripped of all social mechanics. Runs on Cloudflare Workers.
4
4
 
5
- ## Option A: One-Click Deploy
5
+ ## Quick Start
6
6
 
7
- Deploy to Cloudflare instantly — no local setup required:
7
+ ### One-Click Deploy
8
8
 
9
9
  [![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/jant-me/jant-starter)
10
10
 
11
- ### Deploy form fields
12
-
13
- | Field | What to do |
14
- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
15
- | **Git account** | Select your GitHub account. A new repo will be created for you. |
16
- | **D1 database** | Keep "Create new". The default name is fine. |
17
- | **Database location hint** | Pick a region close to you (optional, Cloudflare auto-selects). |
18
- | **R2 bucket** | Keep "Create new". The default name is fine. Used for media uploads. |
19
- | **AUTH_SECRET** | Used for login session encryption. Keep the pre-filled value or generate your own with `openssl rand -base64 32`. |
20
- | **SITE_URL** | Change this to your production URL (e.g. `https://my-blog.example.com`). If you don't have a custom domain yet, leave it empty — you can set it later in the Cloudflare dashboard after you know your `*.workers.dev` URL. |
21
-
22
- ### After deploy
23
-
24
- 1. Visit your site at the URL shown in the Cloudflare dashboard (e.g. `https://<project>.<account>.workers.dev`)
25
- 2. Go to `/dash` to set up your admin account
26
- 3. If you set `SITE_URL` to a custom domain, add it in: Cloudflare dashboard → Workers & Pages → your worker → Settings → Domains & Routes → Add Custom Domain
27
- 4. If you left `SITE_URL` empty, set it to your `*.workers.dev` URL: Cloudflare dashboard → Workers & Pages → your worker → Settings → Variables and Secrets
28
-
29
- ### Develop locally
30
-
31
- ```bash
32
- # Clone the repo that was created for you
33
- git clone git@github.com:<your-username>/<your-repo>.git
34
- cd <your-repo>
35
- npm install
36
- npm run dev
37
- ```
38
-
39
- Visit http://localhost:9019. Changes pushed to `main` will auto-deploy.
40
-
41
- ## Option B: Create with CLI
42
-
43
- Set up a new project locally, then deploy manually:
11
+ ### CLI
44
12
 
45
13
  ```bash
46
14
  npm create jant my-site
@@ -48,240 +16,103 @@ cd my-site
48
16
  npm run dev
49
17
  ```
50
18
 
51
- Visit http://localhost:9019. When you're ready to go live, continue with [Deploy to Cloudflare](#deploy-to-cloudflare) below.
52
-
53
- ### Deploy to Cloudflare
54
-
55
- #### 1. Prerequisites
56
-
57
- Install [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/install-and-update/) and log in:
58
-
59
- ```bash
60
- wrangler login
61
- ```
62
-
63
- #### 2. Create D1 Database
19
+ ### Manual Deploy
64
20
 
65
- Check the `database_name` in your `wrangler.toml` (defaults to `<your-project>-db`), then create it:
21
+ 1. **Create a D1 database:**
66
22
 
67
- ```bash
68
- wrangler d1 create <your-project>-db
69
- # Copy the database_id from the output!
70
- ```
71
-
72
- #### 3. Update Configuration
73
-
74
- Edit `wrangler.toml`:
75
-
76
- - Replace `database_id = "local"` with the ID from step 2
77
- - Set `SITE_URL` to your production URL (e.g. `https://example.com`)
78
-
79
- > R2 bucket is automatically created on first deploy — no manual setup needed.
80
- >
81
- > **Note:** Changing `database_id` resets your local development database (local data is stored per database ID). If you've already started local development, you'll need to go through the setup wizard again to create your admin account.
82
-
83
- #### 4. Set Production Secrets
84
-
85
- Generate a production secret and save it somewhere safe (you'll need it again for CI):
86
-
87
- ```bash
88
- # Generate a secret
89
- openssl rand -base64 32
90
-
91
- # Set it in Cloudflare
92
- wrangler secret put AUTH_SECRET
93
- # Paste the generated value when prompted
94
- ```
95
-
96
- > **Important:** This is separate from the `AUTH_SECRET` in `.dev.vars` (which is for local development only). Do not change the production secret after your site is live — it will invalidate all sessions. If you get locked out, use `npm run reset-password` to generate a password reset link.
97
-
98
- #### 5. Deploy
99
-
100
- ```bash
101
- # Apply database migrations and deploy
102
- npm run deploy
103
- ```
23
+ ```bash
24
+ npx wrangler d1 create my-site-db
25
+ ```
104
26
 
105
- Your site is now live at `https://<your-project>.<your-subdomain>.workers.dev`!
27
+ 2. **Update `wrangler.toml`** with the `database_id` from step 1 and set your `SITE_URL`.
106
28
 
107
- #### 6. Custom Domain (Optional)
29
+ 3. **Set production secrets:**
108
30
 
109
- 1. Go to [Cloudflare Dashboard](https://dash.cloudflare.com) → Workers & Pages
110
- 2. Select your worker → Settings → Domains & Routes
111
- 3. Click **Add -> Custom domain** and enter your domain
31
+ ```bash
32
+ npx wrangler secret put AUTH_SECRET
33
+ ```
112
34
 
113
- ### GitHub Actions (CI/CD)
35
+ 4. **Deploy:**
114
36
 
115
- A workflow file is included at `.github/workflows/deploy.yml`. Complete the [deployment](#deploy-to-cloudflare) first, then set up CI for automatic deployments.
116
-
117
- > Runtime secrets (`AUTH_SECRET`, S3 keys, etc.) are already stored in Cloudflare from the manual deployment step. CI only needs deployment credentials.
118
-
119
- #### 1. Push to GitHub
120
-
121
- Create a new repository on [GitHub](https://github.com/new), then commit and push your project:
122
-
123
- ```bash
124
- git add -A
125
- git commit -m "Initial setup"
126
- git remote add origin git@github.com:<your-username>/<your-repo>.git
127
- git push -u origin main
128
- ```
129
-
130
- #### 2. Create API Token
131
-
132
- 1. Go to [Cloudflare API Tokens](https://dash.cloudflare.com/profile/api-tokens)
133
- 2. Click **Create Token** → **Use template** next to **Edit Cloudflare Workers**
134
- 3. **Add D1 permission** (not in template by default):
135
- - Click **+ Add more** → **Account** → **D1** → **Edit**
136
-
137
- Your permissions should include:
138
-
139
- | Scope | Permission | Access |
140
- | ------- | ------------------ | ----------------------------- |
141
- | Account | Workers Scripts | Edit |
142
- | Account | Workers R2 Storage | Edit |
143
- | Account | **D1** | **Edit** ← Must add manually! |
144
- | Zone | Workers Routes | Edit |
145
-
146
- 4. Set **Account Resources** → **Include** → your account
147
- 5. Set **Zone Resources** → **Include** → **All zones from an account** → your account
148
- 6. **Create Token** and copy it
149
-
150
- #### 3. Add GitHub Secrets
151
-
152
- Go to your repo → **Settings** → **Secrets and variables** → **Actions**:
153
-
154
- | Secret Name | Value |
155
- | --------------- | ------------------------------------------------------------------------ |
156
- | `CF_API_TOKEN` | API token from above |
157
- | `CF_ACCOUNT_ID` | Your Cloudflare Account ID (found in dashboard URL or `wrangler whoami`) |
158
-
159
- #### 4. Enable Auto-Deploy
160
-
161
- Uncomment the push trigger in `.github/workflows/deploy.yml`:
162
-
163
- ```yaml
164
- on:
165
- push:
166
- branches:
167
- - main
168
- workflow_dispatch:
169
- ```
170
-
171
- Now every push to `main` will auto-deploy.
172
-
173
- #### Using Environments (Optional)
174
-
175
- For separate staging/production, update `.github/workflows/deploy.yml`:
176
-
177
- ```yaml
178
- jobs:
179
- deploy:
180
- uses: jant-me/jant/.github/workflows/deploy.yml@main
181
- with:
182
- environment: production # Uses [env.production] in wrangler.toml
183
- secrets:
184
- CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
185
- CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
186
- ```
37
+ ```bash
38
+ npm run deploy
39
+ ```
187
40
 
188
41
  ## Commands
189
42
 
190
- | Command | Description |
191
- | --------------------------- | ---------------------------------- |
192
- | `npm run dev` | Start development server |
193
- | `npm run build` | Build for production |
194
- | `npm run deploy` | Migrate, build, and deploy |
195
- | `npm run preview` | Preview production build |
196
- | `npm run typecheck` | Run TypeScript checks |
197
- | `npm run db:migrate:remote` | Apply database migrations (remote) |
43
+ | Command | Description |
44
+ | ---------------- | ------------------------------------------- |
45
+ | `npm run dev` | Start local dev server (applies migrations) |
46
+ | `npm run deploy` | Deploy to Cloudflare (applies migrations) |
198
47
 
199
48
  ## Environment Variables
200
49
 
201
- | Variable | Description | Location |
202
- | ------------- | ----------------------------------------- | ---------------- |
203
- | `AUTH_SECRET` | Secret key for authentication (32+ chars) | `.dev.vars` file |
204
- | `SITE_URL` | Your site's public URL | `wrangler.toml` |
50
+ Configuration is set in `wrangler.toml` and `.dev.vars`. See [Configuration](https://github.com/jant-me/jant/blob/main/docs/configuration.md) for the full reference.
205
51
 
206
- For all available variables (site name, language, R2 storage, image optimization, S3, demo mode, etc.), see the **[Configuration Guide](https://github.com/jant-me/jant/blob/main/docs/configuration.md)**.
52
+ **Required:**
207
53
 
208
- ## Customization
209
-
210
- ### Color Themes
54
+ | Variable | Where | Description |
55
+ | ------------- | --------------- | ---------------------------------- |
56
+ | `SITE_URL` | `wrangler.toml` | Your site's public URL |
57
+ | `AUTH_SECRET` | `.dev.vars` | Session encryption key (32+ chars) |
211
58
 
212
- Pick a color theme from the dashboard: **Settings > Appearance**.
59
+ **Optional (in `wrangler.toml`):**
213
60
 
214
- ### Custom CSS
61
+ | Variable | Description |
62
+ | --------------------- | ----------------------------------------- |
63
+ | `SITE_NAME` | Display name (also settable in dashboard) |
64
+ | `SITE_DESCRIPTION` | Meta description / RSS subtitle |
65
+ | `SITE_LANGUAGE` | Language code (`en`, `zh`, etc.) |
66
+ | `R2_PUBLIC_URL` | Public URL for R2 media bucket |
67
+ | `IMAGE_TRANSFORM_URL` | Cloudflare Image Transformations URL |
215
68
 
216
- Inject custom CSS from the dashboard: **Settings > Appearance > Custom CSS**. This CSS is applied with the highest priority, so you can override any built-in styles.
69
+ ## GitHub Actions CI/CD
217
70
 
218
- ### CSS Design Tokens
71
+ The included workflow (`.github/workflows/deploy.yml`) deploys on every push to `main`.
219
72
 
220
- Override design tokens in your custom CSS to change the look and feel:
73
+ **Setup:**
221
74
 
222
- ```css
223
- :root {
224
- --site-width: 720px;
225
- --card-radius: 0.5rem;
226
- --font-body: "Inter", system-ui, sans-serif;
227
- --avatar-size: 42px;
228
- }
229
- ```
75
+ 1. Add these **repository secrets** in Settings > Secrets and variables > Actions:
76
+ - `CF_API_TOKEN` — Cloudflare API token with Workers, D1, and R2 permissions
77
+ - `CF_ACCOUNT_ID` — your Cloudflare account ID
78
+ 2. Set your production `AUTH_SECRET`:
79
+ ```bash
80
+ npx wrangler secret put AUTH_SECRET
81
+ ```
82
+ 3. Push to `main` — the workflow handles migrations and deployment.
230
83
 
231
- ### Data Attributes
232
-
233
- Target specific elements with stable data attributes:
84
+ ## Customization
234
85
 
235
- ```css
236
- /* Style only note-format posts */
237
- [data-format="note"] {
238
- border-left: 3px solid var(--primary);
239
- }
86
+ ### CSS Tokens
240
87
 
241
- /* Style the home page differently */
242
- [data-page="home"] {
243
- background: var(--muted);
244
- }
88
+ Customize colors through the dashboard (Settings > Appearance) or by overriding CSS variables. See [Theming](https://github.com/jant-me/jant/blob/main/docs/theming.md).
245
89
 
246
- /* Hide compose prompt for unauthenticated visitors */
247
- body:not([data-authenticated]) .compose-prompt {
248
- display: none;
249
- }
250
- ```
90
+ ### Data Attributes
251
91
 
252
- ### Code-Level Customization
92
+ Target specific elements for styling with stable data attributes:
253
93
 
254
- Pass CSS variable overrides or custom color themes via `createApp()`:
94
+ | Attribute | Purpose |
95
+ | ---------------- | ----------------------------- |
96
+ | `data-page` | Page type identifier |
97
+ | `data-post` | Post marker |
98
+ | `data-format` | Post format (note/link/quote) |
99
+ | `data-post-body` | Post body content |
255
100
 
256
- ```typescript
257
- import { createApp } from "@jant/core";
101
+ ### Code-Level
258
102
 
259
- export default createApp({
260
- cssVariables: {
261
- "--site-width": "720px",
262
- "--card-radius": "0.5rem",
263
- },
264
- });
265
- ```
103
+ For deeper changes, fork the project and modify `@jant/core` directly.
266
104
 
267
105
  ## Updating
268
106
 
269
107
  ```bash
270
- # Update @jant/core to latest version
271
- npm install @jant/core@latest
272
-
273
- # Start dev server (auto-applies migrations locally)
274
- npm run dev
275
-
276
- # Deploy (includes remote migrations)
108
+ npm update @jant/core
277
109
  npm run deploy
278
110
  ```
279
111
 
280
- > New versions of `@jant/core` may include database migrations. Check the [release notes](https://github.com/jant-me/jant/releases) for any breaking changes.
281
- >
282
- > **Dev dependencies** (vite, wrangler, tailwindcss, etc.) may also need updating. Compare your `devDependencies` with the [latest template](https://github.com/jant-me/jant/blob/main/templates/jant-site/package.json) and update if needed.
112
+ Check the [changelog](https://github.com/jant-me/jant/releases) for breaking changes before updating.
283
113
 
284
114
  ## Documentation
285
115
 
286
- - [Jant Documentation](https://jant.me/docs)
287
- - [GitHub Repository](https://github.com/jant-me/jant)
116
+ - [Configuration](https://github.com/jant-me/jant/blob/main/docs/configuration.md)
117
+ - [Theming](https://github.com/jant-me/jant/blob/main/docs/theming.md)
118
+ - [GitHub](https://github.com/jant-me/jant)
@@ -1,25 +1,47 @@
1
- # Deploy to Cloudflare Workers
2
- # Documentation: https://jant.me/docs/deployment
1
+ # Deploy your Jant site to Cloudflare Workers.
3
2
  #
4
3
  # Prerequisites:
5
- # 1. Complete manual deployment first (see README.md Deploy to Cloudflare)
6
- # 2. Set GitHub secrets: CF_API_TOKEN and CF_ACCOUNT_ID
4
+ # 1. Create a D1 database: npx wrangler d1 create <name>
5
+ # 2. Update wrangler.toml with the database_id
6
+ # 3. Add repository secrets: CF_API_TOKEN, CF_ACCOUNT_ID
7
+ # 4. Set production secret: npx wrangler secret put AUTH_SECRET
7
8
  #
8
- # Runtime secrets (AUTH_SECRET, S3 keys, etc.) are managed via
9
- # `wrangler secret put` and persist across deployments.
9
+ # Full setup guide: https://github.com/jant-me/jant
10
10
 
11
11
  name: Deploy
12
12
 
13
13
  on:
14
- # Uncomment to auto-deploy on push after configuring secrets:
15
- # push:
16
- # branches:
17
- # - main
14
+ push:
15
+ branches:
16
+ - main
18
17
  workflow_dispatch:
19
18
 
20
19
  jobs:
21
20
  deploy:
22
- uses: jant-me/jant/.github/workflows/deploy.yml@main
23
- secrets:
24
- CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
25
- CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
21
+ name: Deploy
22
+ runs-on: ubuntu-latest
23
+
24
+ steps:
25
+ - name: Checkout
26
+ uses: actions/checkout@v4
27
+
28
+ - name: Setup Node.js
29
+ uses: actions/setup-node@v4
30
+ with:
31
+ node-version: "24"
32
+
33
+ - name: Install dependencies
34
+ run: npm ci
35
+
36
+ - name: Run migrations
37
+ run: npx wrangler d1 migrations apply DB --remote
38
+ env:
39
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
40
+ CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
41
+
42
+ - name: Deploy to Cloudflare Workers
43
+ uses: cloudflare/wrangler-action@v3
44
+ with:
45
+ apiToken: ${{ secrets.CF_API_TOKEN }}
46
+ accountId: ${{ secrets.CF_ACCOUNT_ID }}
47
+ command: deploy