chalknotes 0.0.32 ā 0.0.34
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/cli.js +71 -201
- package/package.json +1 -1
- package/src/lib/getPostBySlug.js +17 -0
package/bin/cli.js
CHANGED
|
@@ -9,15 +9,15 @@ console.log("š Initializing ChalkNotes...");
|
|
|
9
9
|
|
|
10
10
|
// Check environment variables
|
|
11
11
|
if (!process.env.NOTION_TOKEN) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
console.error("ā NOTION_TOKEN is not set in .env file");
|
|
13
|
+
console.log("š” Please create a .env file with your NOTION_TOKEN");
|
|
14
|
+
process.exit(1);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
if (!process.env.NOTION_DATABASE_ID) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
console.error("ā NOTION_DATABASE_ID is not set in .env file");
|
|
19
|
+
console.log("š” Please create a .env file with your NOTION_DATABASE_ID");
|
|
20
|
+
process.exit(1);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
console.log("ā
Environment variables are set");
|
|
@@ -26,19 +26,19 @@ const configPath = path.join(process.cwd(), 'blog.config.js');
|
|
|
26
26
|
|
|
27
27
|
// Check if blog.config.js exists
|
|
28
28
|
if (!fs.existsSync(configPath)) {
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
console.log("\nā blog.config.js not found");
|
|
30
|
+
console.log("This file is required to configure your blog settings.");
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
const rl = readline.createInterface({
|
|
33
|
+
input: process.stdin,
|
|
34
|
+
output: process.stdout
|
|
35
|
+
});
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
rl.question("Would you like to create a default blog.config.js? (y/n): ", (answer) => {
|
|
38
|
+
if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
|
|
39
|
+
console.log("š Creating blog.config.js with default configuration...");
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
const configTemplate = `module.exports = {
|
|
42
42
|
notionToken: process.env.NOTION_TOKEN,
|
|
43
43
|
notionDatabaseId: process.env.NOTION_DATABASE_ID,
|
|
44
44
|
routeBasePath: '/blog',
|
|
@@ -46,24 +46,24 @@ if (!fs.existsSync(configPath)) {
|
|
|
46
46
|
plugins: [],
|
|
47
47
|
};`.trim();
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
fs.writeFileSync(configPath, configTemplate);
|
|
50
|
+
console.log("ā
Created blog.config.js with default configuration");
|
|
51
|
+
console.log("\nš” Now you can re-run 'npx chalknotes' to scaffold your blog pages!");
|
|
52
|
+
} else {
|
|
53
|
+
console.log("ā Please create a blog.config.js file and try again.");
|
|
54
|
+
}
|
|
55
|
+
rl.close();
|
|
56
|
+
});
|
|
57
|
+
return;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
// Load configuration
|
|
61
61
|
let config;
|
|
62
62
|
try {
|
|
63
|
-
|
|
63
|
+
config = require(configPath);
|
|
64
64
|
} catch (error) {
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
console.error("ā Error loading blog.config.js:", error.message);
|
|
66
|
+
process.exit(1);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
// Set defaults for missing config values
|
|
@@ -85,56 +85,11 @@ const appRouter = path.join(process.cwd(), '/app')
|
|
|
85
85
|
|
|
86
86
|
// Generate templates based on theme
|
|
87
87
|
function getTemplates(theme, routeBasePath) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (theme === 'dark') {
|
|
91
|
-
return {
|
|
92
|
-
pageRouter: `
|
|
93
|
-
import { getStaticPropsForPost, getStaticPathsForPosts } from 'chalknotes';
|
|
94
|
-
import NotionRenderer from './NotionRenderer';
|
|
95
|
-
|
|
96
|
-
export const getStaticProps = getStaticPropsForPost;
|
|
97
|
-
export const getStaticPaths = getStaticPathsForPosts;
|
|
98
|
-
|
|
99
|
-
export default function BlogPost({ post }) {
|
|
100
|
-
return (
|
|
101
|
-
<div className="min-h-screen bg-gray-900">
|
|
102
|
-
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
|
103
|
-
<article className="bg-gray-800 rounded-lg shadow-lg border border-gray-700 p-8">
|
|
104
|
-
<h1 className="text-4xl font-bold text-white mb-6 leading-tight">
|
|
105
|
-
{post.title}
|
|
106
|
-
</h1>
|
|
107
|
-
<NotionRenderer blocks={post.blocks} />
|
|
108
|
-
</article>
|
|
109
|
-
</main>
|
|
110
|
-
</div>
|
|
111
|
-
);
|
|
112
|
-
}`.trim(),
|
|
113
|
-
appRouter: `
|
|
114
|
-
import { getPostBySlug } from 'chalknotes';
|
|
115
|
-
import NotionRenderer from './NotionRenderer';
|
|
116
|
-
|
|
117
|
-
export default async function BlogPost({ params }) {
|
|
118
|
-
const post = await getPostBySlug(params.slug);
|
|
88
|
+
const routePath = routeBasePath.replace(/^\//, ''); // Remove leading slash
|
|
119
89
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
<article className="bg-gray-800 rounded-lg shadow-lg border border-gray-700 p-8">
|
|
124
|
-
<h1 className="text-4xl font-bold text-white mb-6 leading-tight">
|
|
125
|
-
{post.title}
|
|
126
|
-
</h1>
|
|
127
|
-
<NotionRenderer blocks={post.blocks} />
|
|
128
|
-
</article>
|
|
129
|
-
</main>
|
|
130
|
-
</div>
|
|
131
|
-
);
|
|
132
|
-
}`.trim()
|
|
133
|
-
};
|
|
134
|
-
} else {
|
|
135
|
-
// Default theme (light mode)
|
|
136
|
-
return {
|
|
137
|
-
pageRouter: `
|
|
90
|
+
// Both themes now use responsive dark mode
|
|
91
|
+
return {
|
|
92
|
+
pageRouter: `
|
|
138
93
|
import { getStaticPropsForPost, getStaticPathsForPosts } from 'chalknotes';
|
|
139
94
|
import NotionRenderer from './NotionRenderer';
|
|
140
95
|
|
|
@@ -143,10 +98,10 @@ export const getStaticPaths = getStaticPathsForPosts;
|
|
|
143
98
|
|
|
144
99
|
export default function BlogPost({ post }) {
|
|
145
100
|
return (
|
|
146
|
-
<div className="min-h-screen bg-gray-50">
|
|
101
|
+
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
|
|
147
102
|
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
|
148
|
-
<article className="bg-white rounded-lg shadow-sm border border-gray-200 p-8">
|
|
149
|
-
<h1 className="text-4xl font-bold text-gray-900 mb-6 leading-tight">
|
|
103
|
+
<article className="bg-white dark:bg-gray-800 rounded-lg shadow-sm dark:shadow-lg border border-gray-200 dark:border-gray-700 p-8">
|
|
104
|
+
<h1 className="text-4xl font-bold text-gray-900 dark:text-white mb-6 leading-tight">
|
|
150
105
|
{post.title}
|
|
151
106
|
</h1>
|
|
152
107
|
<NotionRenderer blocks={post.blocks} />
|
|
@@ -155,7 +110,7 @@ export default function BlogPost({ post }) {
|
|
|
155
110
|
</div>
|
|
156
111
|
);
|
|
157
112
|
}`.trim(),
|
|
158
|
-
|
|
113
|
+
appRouter: `
|
|
159
114
|
import { getPostBySlug } from 'chalknotes';
|
|
160
115
|
import NotionRenderer from './NotionRenderer';
|
|
161
116
|
|
|
@@ -163,10 +118,10 @@ export default async function BlogPost({ params }) {
|
|
|
163
118
|
const post = await getPostBySlug(params.slug);
|
|
164
119
|
|
|
165
120
|
return (
|
|
166
|
-
<div className="min-h-screen bg-gray-50">
|
|
121
|
+
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
|
|
167
122
|
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
|
168
|
-
<article className="bg-white rounded-lg shadow-sm border border-gray-200 p-8">
|
|
169
|
-
<h1 className="text-4xl font-bold text-gray-900 mb-6 leading-tight">
|
|
123
|
+
<article className="bg-white dark:bg-gray-800 rounded-lg shadow-sm dark:shadow-lg border border-gray-200 dark:border-gray-700 p-8">
|
|
124
|
+
<h1 className="text-4xl font-bold text-gray-900 dark:text-white mb-6 leading-tight">
|
|
170
125
|
{post.title}
|
|
171
126
|
</h1>
|
|
172
127
|
<NotionRenderer blocks={post.blocks} />
|
|
@@ -175,28 +130,18 @@ export default async function BlogPost({ params }) {
|
|
|
175
130
|
</div>
|
|
176
131
|
);
|
|
177
132
|
}`.trim()
|
|
178
|
-
|
|
179
|
-
}
|
|
133
|
+
};
|
|
180
134
|
}
|
|
181
135
|
|
|
182
|
-
//
|
|
183
|
-
|
|
184
|
-
console.log("ā
Page router found");
|
|
185
|
-
const routePath = config.routeBasePath.replace(/^\//, ''); // Remove leading slash
|
|
186
|
-
const slugDir = path.join(pageRouter, routePath, "[slug].js")
|
|
187
|
-
const dirPath = path.dirname(slugDir);
|
|
188
|
-
|
|
189
|
-
const templates = getTemplates(config.theme, config.routeBasePath);
|
|
190
|
-
|
|
191
|
-
// Create NotionRenderer component in the same directory as the blog page
|
|
192
|
-
const notionRendererContent = `import React from "react";
|
|
136
|
+
// NotionRenderer component template
|
|
137
|
+
const notionRendererTemplate = `import React from "react";
|
|
193
138
|
import Image from "next/image";
|
|
194
139
|
|
|
195
140
|
export default function NotionRenderer({ blocks }) {
|
|
196
141
|
if (!blocks || blocks.length === 0) return null;
|
|
197
142
|
|
|
198
143
|
return (
|
|
199
|
-
<div className="
|
|
144
|
+
<div className="max-w-none">
|
|
200
145
|
{blocks.map((block, i) => {
|
|
201
146
|
switch (block.type) {
|
|
202
147
|
case "heading_1":
|
|
@@ -300,119 +245,44 @@ export default function NotionRenderer({ blocks }) {
|
|
|
300
245
|
</div>
|
|
301
246
|
);
|
|
302
247
|
}`;
|
|
303
|
-
|
|
304
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
305
|
-
fs.writeFileSync(path.join(dirPath, 'NotionRenderer.jsx'), notionRendererContent);
|
|
306
|
-
console.log(`ā
Created ${routePath}/NotionRenderer.jsx`);
|
|
307
|
-
|
|
308
|
-
fs.writeFileSync(slugDir, templates.pageRouter);
|
|
309
|
-
console.log(`ā
Created pages/${routePath}/[slug].js`);
|
|
310
|
-
|
|
311
|
-
} else if (fs.existsSync(appRouter)) {
|
|
312
|
-
console.log("ā
App router found");
|
|
313
|
-
const routePath = config.routeBasePath.replace(/^\//, ''); // Remove leading slash
|
|
314
|
-
const slugDir = path.join(appRouter, routePath, "[slug]", "page.jsx")
|
|
315
|
-
const dirPath = path.dirname(slugDir);
|
|
316
|
-
|
|
317
|
-
const templates = getTemplates(config.theme, config.routeBasePath);
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
// Create NotionRenderer component in the same directory as the blog page
|
|
321
|
-
const notionRendererContent = `import React from "react";
|
|
322
|
-
import Image from "next/image";
|
|
323
248
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
switch (block.type) {
|
|
331
|
-
case "heading_1":
|
|
332
|
-
return <h1 key={i}>{block.text}</h1>;
|
|
333
|
-
|
|
334
|
-
case "heading_2":
|
|
335
|
-
return <h2 key={i}>{block.text}</h2>;
|
|
336
|
-
|
|
337
|
-
case "heading_3":
|
|
338
|
-
return <h3 key={i}>{block.text}</h3>;
|
|
249
|
+
// Create blog page templates
|
|
250
|
+
if (fs.existsSync(pageRouter)) {
|
|
251
|
+
console.log("ā
Page router found");
|
|
252
|
+
const routePath = config.routeBasePath.replace(/^\//, ''); // Remove leading slash
|
|
253
|
+
const slugDir = path.join(pageRouter, routePath, "[slug].js")
|
|
254
|
+
const dirPath = path.dirname(slugDir);
|
|
339
255
|
|
|
340
|
-
|
|
341
|
-
return <p key={i}>{block.text}</p>;
|
|
256
|
+
const templates = getTemplates(config.theme, config.routeBasePath);
|
|
342
257
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
</ul>
|
|
348
|
-
);
|
|
258
|
+
// Create NotionRenderer component in the same directory as the blog page
|
|
259
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
260
|
+
fs.writeFileSync(path.join(dirPath, 'NotionRenderer.jsx'), notionRendererTemplate);
|
|
261
|
+
console.log(`ā
Created ${routePath}/NotionRenderer.jsx`);
|
|
349
262
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
<ol key={i} className="list-decimal ml-6">
|
|
353
|
-
<li>{block.text}</li>
|
|
354
|
-
</ol>
|
|
355
|
-
);
|
|
263
|
+
fs.writeFileSync(slugDir, templates.pageRouter);
|
|
264
|
+
console.log(`ā
Created pages/${routePath}/[slug].js`);
|
|
356
265
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
);
|
|
266
|
+
} else if (fs.existsSync(appRouter)) {
|
|
267
|
+
console.log("ā
App router found");
|
|
268
|
+
const routePath = config.routeBasePath.replace(/^\//, ''); // Remove leading slash
|
|
269
|
+
const slugDir = path.join(appRouter, routePath, "[slug]", "page.jsx")
|
|
270
|
+
const dirPath = path.dirname(slugDir);
|
|
363
271
|
|
|
364
|
-
|
|
365
|
-
return (
|
|
366
|
-
<pre key={i} className="bg-slate-900 text-slate-100 p-4 rounded-xl overflow-x-auto text-sm">
|
|
367
|
-
<code className={\`language-\${block.language}\`}>{block.code}</code>
|
|
368
|
-
</pre>
|
|
369
|
-
);
|
|
272
|
+
const templates = getTemplates(config.theme, config.routeBasePath);
|
|
370
273
|
|
|
371
|
-
|
|
372
|
-
|
|
274
|
+
// Create NotionRenderer component in the same directory as the blog page
|
|
275
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
276
|
+
fs.writeFileSync(path.join(dirPath, 'NotionRenderer.jsx'), notionRendererTemplate);
|
|
277
|
+
console.log(`ā
Created ${routePath}/[slug]/NotionRenderer.jsx`);
|
|
373
278
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
<figure key={i} className="max-w-[400px] mx-auto my-6 px-4">
|
|
377
|
-
<Image
|
|
378
|
-
src={block.imageUrl}
|
|
379
|
-
alt={block.alt || "Image"}
|
|
380
|
-
width={400}
|
|
381
|
-
height={300}
|
|
382
|
-
className="rounded-xl object-contain"
|
|
383
|
-
unoptimized={true}
|
|
384
|
-
/>
|
|
385
|
-
{block.caption && (
|
|
386
|
-
<figcaption className="text-sm text-center text-slate-500 mt-2 italic">
|
|
387
|
-
{block.caption}
|
|
388
|
-
</figcaption>
|
|
389
|
-
)}
|
|
390
|
-
</figure>
|
|
391
|
-
);
|
|
279
|
+
fs.writeFileSync(slugDir, templates.appRouter);
|
|
280
|
+
console.log(`ā
Created app/${routePath}/[slug]/page.jsx`);
|
|
392
281
|
|
|
393
|
-
default:
|
|
394
|
-
return (
|
|
395
|
-
<p key={i} className="text-sm text-red-500 italic">
|
|
396
|
-
ā ļø Unsupported block: {block.type}
|
|
397
|
-
</p>
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
})}
|
|
401
|
-
</div>
|
|
402
|
-
);
|
|
403
|
-
}`;
|
|
404
|
-
|
|
405
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
406
|
-
fs.writeFileSync(path.join(dirPath, 'NotionRenderer.jsx'), notionRendererContent);
|
|
407
|
-
console.log(`ā
Created ${routePath}/[slug]/NotionRenderer.jsx`);
|
|
408
|
-
|
|
409
|
-
fs.writeFileSync(slugDir, templates.appRouter);
|
|
410
|
-
console.log(`ā
Created app/${routePath}/[slug]/page.jsx`);
|
|
411
|
-
|
|
412
282
|
} else {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
283
|
+
console.log("ā Neither pages/ nor app/ directory found");
|
|
284
|
+
console.log("š” Please make sure you're running this in a Next.js project");
|
|
285
|
+
process.exit(1);
|
|
416
286
|
}
|
|
417
287
|
|
|
418
288
|
console.log("\nš Blog page scaffolded successfully!");
|
package/package.json
CHANGED
package/src/lib/getPostBySlug.js
CHANGED
|
@@ -105,6 +105,23 @@ function convertBlockToStructuredJSON(block) {
|
|
|
105
105
|
case "divider":
|
|
106
106
|
return { ...base };
|
|
107
107
|
|
|
108
|
+
case "callout":
|
|
109
|
+
return { ...base };
|
|
110
|
+
|
|
111
|
+
case "toggle":
|
|
112
|
+
return { ...base };
|
|
113
|
+
|
|
114
|
+
case "table_of_contents":
|
|
115
|
+
return { ...base };
|
|
116
|
+
case "bookmark":
|
|
117
|
+
return { ...base };
|
|
118
|
+
|
|
119
|
+
case "equation":
|
|
120
|
+
return { ...base };
|
|
121
|
+
|
|
122
|
+
case "table":
|
|
123
|
+
return { ...base };
|
|
124
|
+
|
|
108
125
|
default:
|
|
109
126
|
return {
|
|
110
127
|
...base,
|