create-noxion 0.1.1 → 0.2.0
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.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +159 -5
- package/dist/index.js.map +1 -1
- package/dist/scaffold.d.ts +9 -1
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +20 -3
- package/dist/scaffold.js.map +1 -1
- package/dist/templates/docs/.env +8 -0
- package/dist/templates/docs/.env.example +9 -0
- package/dist/templates/docs/app/[slug]/page.tsx +49 -0
- package/dist/templates/docs/app/api/notion-webhook/route.ts +12 -0
- package/dist/templates/docs/app/api/revalidate/route.ts +12 -0
- package/dist/templates/docs/app/globals.css +31 -0
- package/dist/templates/docs/app/layout.tsx +35 -0
- package/dist/templates/docs/app/not-found.tsx +38 -0
- package/dist/templates/docs/app/page.tsx +45 -0
- package/dist/templates/docs/app/providers.tsx +45 -0
- package/dist/templates/docs/app/robots.ts +7 -0
- package/dist/templates/docs/app/sitemap.ts +9 -0
- package/dist/templates/docs/app/theme-script.tsx +16 -0
- package/dist/templates/docs/lib/config.ts +24 -0
- package/dist/templates/docs/lib/notion.ts +48 -0
- package/dist/templates/docs/next.config.ts +26 -0
- package/dist/templates/docs/noxion.config.ts +23 -0
- package/dist/templates/docs/package.json +25 -0
- package/dist/templates/docs/tsconfig.json +19 -0
- package/dist/templates/full/.env +10 -0
- package/dist/templates/full/.env.example +11 -0
- package/dist/templates/full/app/[slug]/page.tsx +55 -0
- package/dist/templates/full/app/api/notion-webhook/route.ts +12 -0
- package/dist/templates/full/app/api/revalidate/route.ts +12 -0
- package/dist/templates/full/app/globals.css +31 -0
- package/dist/templates/full/app/home-content.tsx +58 -0
- package/dist/templates/full/app/layout.tsx +35 -0
- package/dist/templates/full/app/not-found.tsx +38 -0
- package/dist/templates/full/app/page.tsx +50 -0
- package/dist/templates/full/app/providers.tsx +45 -0
- package/dist/templates/full/app/robots.ts +7 -0
- package/dist/templates/full/app/sitemap.ts +9 -0
- package/dist/templates/full/app/tag/[tag]/page.tsx +66 -0
- package/dist/templates/full/app/theme-script.tsx +16 -0
- package/dist/templates/full/lib/config.ts +24 -0
- package/dist/templates/full/lib/notion.ts +66 -0
- package/dist/templates/full/next.config.ts +26 -0
- package/dist/templates/full/noxion.config.ts +40 -0
- package/dist/templates/full/package.json +25 -0
- package/dist/templates/full/tsconfig.json +19 -0
- package/dist/templates/nextjs/.env.example +1 -0
- package/dist/templates/nextjs/app/api/notion-webhook/route.ts +12 -0
- package/dist/templates/nextjs/app/page.tsx +3 -3
- package/dist/templates/nextjs/app/tag/[tag]/page.tsx +4 -4
- package/dist/templates/nextjs/lib/config.ts +1 -0
- package/dist/templates/nextjs/lib/notion.ts +5 -5
- package/dist/templates/plugin/noxion-plugin.json +10 -0
- package/dist/templates/plugin/package.json +41 -0
- package/dist/templates/plugin/src/__tests__/plugin.test.ts +39 -0
- package/dist/templates/plugin/src/index.ts +20 -0
- package/dist/templates/plugin/tsconfig.json +20 -0
- package/dist/templates/portfolio/.env +8 -0
- package/dist/templates/portfolio/.env.example +9 -0
- package/dist/templates/portfolio/app/[slug]/page.tsx +48 -0
- package/dist/templates/portfolio/app/api/notion-webhook/route.ts +12 -0
- package/dist/templates/portfolio/app/api/revalidate/route.ts +12 -0
- package/dist/templates/portfolio/app/globals.css +31 -0
- package/dist/templates/portfolio/app/layout.tsx +35 -0
- package/dist/templates/portfolio/app/not-found.tsx +38 -0
- package/dist/templates/portfolio/app/page.tsx +70 -0
- package/dist/templates/portfolio/app/providers.tsx +45 -0
- package/dist/templates/portfolio/app/robots.ts +7 -0
- package/dist/templates/portfolio/app/sitemap.ts +9 -0
- package/dist/templates/portfolio/app/theme-script.tsx +16 -0
- package/dist/templates/portfolio/lib/config.ts +24 -0
- package/dist/templates/portfolio/lib/notion.ts +48 -0
- package/dist/templates/portfolio/next.config.ts +26 -0
- package/dist/templates/portfolio/noxion.config.ts +23 -0
- package/dist/templates/portfolio/package.json +25 -0
- package/dist/templates/portfolio/tsconfig.json +19 -0
- package/dist/templates/theme/package.json +42 -0
- package/dist/templates/theme/src/index.ts +40 -0
- package/dist/templates/theme/styles/theme.css +23 -0
- package/dist/templates/theme/tsconfig.json +20 -0
- package/package.json +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { loadConfig } from "@noxion/core";
|
|
2
|
+
import type { NoxionConfig } from "@noxion/core";
|
|
3
|
+
import noxionConfigInput from "../noxion.config";
|
|
4
|
+
|
|
5
|
+
function createConfig(): NoxionConfig {
|
|
6
|
+
try {
|
|
7
|
+
return loadConfig(noxionConfigInput);
|
|
8
|
+
} catch {
|
|
9
|
+
return {
|
|
10
|
+
name: noxionConfigInput.name ?? "{{SITE_NAME}}",
|
|
11
|
+
domain: noxionConfigInput.domain ?? "{{DOMAIN}}",
|
|
12
|
+
author: noxionConfigInput.author ?? "{{AUTHOR}}",
|
|
13
|
+
description: noxionConfigInput.description ?? "{{SITE_DESCRIPTION}}",
|
|
14
|
+
language: noxionConfigInput.language ?? "en",
|
|
15
|
+
defaultTheme: noxionConfigInput.defaultTheme ?? "system",
|
|
16
|
+
defaultPageType: "blog",
|
|
17
|
+
revalidate: noxionConfigInput.revalidate ?? 3600,
|
|
18
|
+
plugins: noxionConfigInput.plugins,
|
|
19
|
+
collections: noxionConfigInput.collections,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const siteConfig = createConfig();
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createNotionClient, fetchCollection, fetchPage, downloadImages, mapImages } from "@noxion/core";
|
|
2
|
+
import type { NoxionPage, BlogPage, ExtendedRecordMap } from "@noxion/core";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { siteConfig } from "./config";
|
|
5
|
+
|
|
6
|
+
const notion = createNotionClient({
|
|
7
|
+
authToken: process.env.NOTION_TOKEN || undefined,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export async function getAllPages(): Promise<NoxionPage[]> {
|
|
11
|
+
const collections = siteConfig.collections ?? [];
|
|
12
|
+
if (collections.length === 0) return [];
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const results = await Promise.all(
|
|
16
|
+
collections.map((col) => fetchCollection(notion, col))
|
|
17
|
+
);
|
|
18
|
+
return results.flat();
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error("Failed to fetch pages:", error);
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function getPagesByType(pageType: string): Promise<NoxionPage[]> {
|
|
26
|
+
const pages = await getAllPages();
|
|
27
|
+
return pages.filter((p) => p.pageType === pageType);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function getPageBySlug(slug: string): Promise<NoxionPage | undefined> {
|
|
31
|
+
const pages = await getAllPages();
|
|
32
|
+
return pages.find((p) => p.slug === slug);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function getPageRecordMap(pageId: string): Promise<ExtendedRecordMap> {
|
|
36
|
+
const recordMap = await fetchPage(notion, pageId);
|
|
37
|
+
|
|
38
|
+
if (process.env.NODE_ENV === "production") {
|
|
39
|
+
try {
|
|
40
|
+
const outputDir = join(process.cwd(), "public");
|
|
41
|
+
const urlMap = await downloadImages(recordMap, outputDir, { concurrency: 5 });
|
|
42
|
+
const localUrlMap: Record<string, string> = {};
|
|
43
|
+
for (const [originalUrl, localPath] of Object.entries(urlMap)) {
|
|
44
|
+
localUrlMap[originalUrl] = `/images/${localPath.split("/images/").pop()}`;
|
|
45
|
+
}
|
|
46
|
+
return mapImages(recordMap, localUrlMap);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error("Image download failed, using original URLs:", error);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return recordMap;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function getAllTags(posts: NoxionPage[]): string[] {
|
|
56
|
+
const tagSet = new Set<string>();
|
|
57
|
+
for (const post of posts) {
|
|
58
|
+
const tags = post.metadata.tags;
|
|
59
|
+
if (Array.isArray(tags)) {
|
|
60
|
+
for (const tag of tags) {
|
|
61
|
+
tagSet.add(tag as string);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return [...tagSet].sort();
|
|
66
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { NextConfig } from "next";
|
|
2
|
+
|
|
3
|
+
const nextConfig: NextConfig = {
|
|
4
|
+
output: "standalone",
|
|
5
|
+
transpilePackages: [
|
|
6
|
+
"@noxion/core",
|
|
7
|
+
"@noxion/renderer",
|
|
8
|
+
"@noxion/adapter-nextjs",
|
|
9
|
+
"@noxion/notion-renderer",
|
|
10
|
+
"notion-client",
|
|
11
|
+
"notion-types",
|
|
12
|
+
"notion-utils",
|
|
13
|
+
],
|
|
14
|
+
images: {
|
|
15
|
+
remotePatterns: [
|
|
16
|
+
{ protocol: "https", hostname: "www.notion.so" },
|
|
17
|
+
{ protocol: "https", hostname: "notion.so" },
|
|
18
|
+
{ protocol: "https", hostname: "images.unsplash.com" },
|
|
19
|
+
{ protocol: "https", hostname: "s3.us-west-2.amazonaws.com" },
|
|
20
|
+
{ protocol: "https", hostname: "prod-files-secure.s3.us-west-2.amazonaws.com" },
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
staticPageGenerationTimeout: 300,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default nextConfig;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { defineConfig, createRSSPlugin } from "@noxion/core";
|
|
2
|
+
|
|
3
|
+
const config = defineConfig({
|
|
4
|
+
name: process.env.SITE_NAME ?? "{{SITE_NAME}}",
|
|
5
|
+
domain: process.env.SITE_DOMAIN ?? "{{DOMAIN}}",
|
|
6
|
+
author: process.env.SITE_AUTHOR ?? "{{AUTHOR}}",
|
|
7
|
+
description: process.env.SITE_DESCRIPTION ?? "{{SITE_DESCRIPTION}}",
|
|
8
|
+
language: "en",
|
|
9
|
+
defaultTheme: "system",
|
|
10
|
+
defaultPageType: "blog",
|
|
11
|
+
revalidate: 3600,
|
|
12
|
+
revalidateSecret: process.env.REVALIDATE_SECRET,
|
|
13
|
+
collections: [
|
|
14
|
+
{
|
|
15
|
+
name: "blog",
|
|
16
|
+
databaseId: process.env.NOTION_PAGE_ID!,
|
|
17
|
+
pageType: "blog",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: "docs",
|
|
21
|
+
databaseId: process.env.DOCS_NOTION_ID || process.env.NOTION_PAGE_ID!,
|
|
22
|
+
pageType: "docs",
|
|
23
|
+
pathPrefix: "/docs",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "portfolio",
|
|
27
|
+
databaseId: process.env.PORTFOLIO_NOTION_ID || process.env.NOTION_PAGE_ID!,
|
|
28
|
+
pageType: "portfolio",
|
|
29
|
+
pathPrefix: "/projects",
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
plugins: [
|
|
33
|
+
createRSSPlugin({
|
|
34
|
+
feedPath: "/feed.xml",
|
|
35
|
+
limit: 20,
|
|
36
|
+
}),
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export default config;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"start": "next start"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@noxion/core": "^0.0.2",
|
|
12
|
+
"@noxion/renderer": "^0.0.2",
|
|
13
|
+
"@noxion/adapter-nextjs": "^0.0.2",
|
|
14
|
+
"next": "^16.1.6",
|
|
15
|
+
"react": "^19.1.0",
|
|
16
|
+
"react-dom": "^19.1.0",
|
|
17
|
+
"notion-client": "^7.8.2"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^22.0.0",
|
|
21
|
+
"@types/react": "^19.2.14",
|
|
22
|
+
"@types/react-dom": "^19.2.3",
|
|
23
|
+
"typescript": "^5.7.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"plugins": [{ "name": "next" }],
|
|
15
|
+
"outDir": "./dist"
|
|
16
|
+
},
|
|
17
|
+
"include": ["**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
18
|
+
"exclude": ["node_modules", ".next", "out", "dist"]
|
|
19
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { revalidatePath } from "next/cache";
|
|
2
|
+
import { createNotionWebhookHandler } from "@noxion/adapter-nextjs";
|
|
3
|
+
import { siteConfig } from "../../../lib/config";
|
|
4
|
+
|
|
5
|
+
const handler = createNotionWebhookHandler({
|
|
6
|
+
config: siteConfig,
|
|
7
|
+
revalidatePath,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export async function POST(request: Request) {
|
|
11
|
+
return handler(request);
|
|
12
|
+
}
|
|
@@ -10,10 +10,10 @@ export default async function HomePage() {
|
|
|
10
10
|
const postCards = posts.map((post) => ({
|
|
11
11
|
title: post.title,
|
|
12
12
|
slug: post.slug,
|
|
13
|
-
date: post.date,
|
|
14
|
-
tags: post.tags,
|
|
13
|
+
date: post.metadata.date,
|
|
14
|
+
tags: post.metadata.tags,
|
|
15
15
|
coverImage: post.coverImage,
|
|
16
|
-
category: post.category,
|
|
16
|
+
category: post.metadata.category,
|
|
17
17
|
}));
|
|
18
18
|
|
|
19
19
|
return <HomeContent posts={postCards} allTags={allTags} />;
|
|
@@ -35,14 +35,14 @@ export default async function TagPage({
|
|
|
35
35
|
const allTags = getAllTags(posts);
|
|
36
36
|
|
|
37
37
|
const filteredPosts = posts
|
|
38
|
-
.filter((p) => p.tags.includes(decodedTag))
|
|
38
|
+
.filter((p) => p.metadata.tags.includes(decodedTag))
|
|
39
39
|
.map((post) => ({
|
|
40
40
|
title: post.title,
|
|
41
41
|
slug: post.slug,
|
|
42
|
-
date: post.date,
|
|
43
|
-
tags: post.tags,
|
|
42
|
+
date: post.metadata.date,
|
|
43
|
+
tags: post.metadata.tags,
|
|
44
44
|
coverImage: post.coverImage,
|
|
45
|
-
category: post.category,
|
|
45
|
+
category: post.metadata.category,
|
|
46
46
|
}));
|
|
47
47
|
|
|
48
48
|
return (
|
|
@@ -14,6 +14,7 @@ function createConfig(): NoxionConfig {
|
|
|
14
14
|
description: noxionConfigInput.description ?? "{{SITE_DESCRIPTION}}",
|
|
15
15
|
language: noxionConfigInput.language ?? "en",
|
|
16
16
|
defaultTheme: noxionConfigInput.defaultTheme ?? "system",
|
|
17
|
+
defaultPageType: "blog",
|
|
17
18
|
revalidate: noxionConfigInput.revalidate ?? 3600,
|
|
18
19
|
plugins: noxionConfigInput.plugins,
|
|
19
20
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createNotionClient, fetchBlogPosts, fetchPage, fetchPostBySlug, downloadImages, mapImages } from "@noxion/core";
|
|
2
|
-
import type {
|
|
2
|
+
import type { BlogPage, ExtendedRecordMap } from "@noxion/core";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { siteConfig } from "./config";
|
|
5
5
|
|
|
@@ -7,7 +7,7 @@ const notion = createNotionClient({
|
|
|
7
7
|
authToken: process.env.NOTION_TOKEN || undefined,
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
-
export async function getAllPosts(): Promise<
|
|
10
|
+
export async function getAllPosts(): Promise<BlogPage[]> {
|
|
11
11
|
if (!siteConfig.rootNotionPageId) return [];
|
|
12
12
|
try {
|
|
13
13
|
return await fetchBlogPosts(notion, siteConfig.rootNotionPageId);
|
|
@@ -17,7 +17,7 @@ export async function getAllPosts(): Promise<BlogPost[]> {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export async function getPostBySlug(slug: string): Promise<
|
|
20
|
+
export async function getPostBySlug(slug: string): Promise<BlogPage | undefined> {
|
|
21
21
|
if (!siteConfig.rootNotionPageId) return undefined;
|
|
22
22
|
try {
|
|
23
23
|
return await fetchPostBySlug(notion, siteConfig.rootNotionPageId, slug);
|
|
@@ -47,10 +47,10 @@ export async function getPageRecordMap(pageId: string): Promise<ExtendedRecordMa
|
|
|
47
47
|
return recordMap;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
export function getAllTags(posts:
|
|
50
|
+
export function getAllTags(posts: BlogPage[]): string[] {
|
|
51
51
|
const tagSet = new Set<string>();
|
|
52
52
|
for (const post of posts) {
|
|
53
|
-
for (const tag of post.tags) {
|
|
53
|
+
for (const tag of post.metadata.tags) {
|
|
54
54
|
tagSet.add(tag);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "noxion-plugin-{{PLUGIN_NAME}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "{{PLUGIN_DESCRIPTION}}",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"noxion-plugin.json",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"test": "bun test",
|
|
25
|
+
"prepublishOnly": "bun run build"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"notion",
|
|
29
|
+
"noxion",
|
|
30
|
+
"noxion-plugin"
|
|
31
|
+
],
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@noxion/core": ">=0.2.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@noxion/core": "^0.2.0",
|
|
37
|
+
"@noxion/plugin-utils": "^0.1.0",
|
|
38
|
+
"@types/bun": "^1.2.0",
|
|
39
|
+
"typescript": "^5.7.0"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
createMockBlogPages,
|
|
4
|
+
createTestPlugin,
|
|
5
|
+
resetMockCounter,
|
|
6
|
+
} from "@noxion/plugin-utils";
|
|
7
|
+
import { createPlugin } from "../index";
|
|
8
|
+
|
|
9
|
+
describe("noxion-plugin-{{PLUGIN_NAME}}", () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
resetMockCounter();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("has the correct name", () => {
|
|
15
|
+
const plugin = createPlugin({});
|
|
16
|
+
expect(plugin.name).toBe("noxion-plugin-{{PLUGIN_NAME}}");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("passes posts through when enabled", () => {
|
|
20
|
+
const plugin = createPlugin({ enabled: true });
|
|
21
|
+
const posts = createMockBlogPages(3);
|
|
22
|
+
const result = plugin.transformPosts!({ posts });
|
|
23
|
+
expect(result).toHaveLength(3);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("passes posts through when disabled", () => {
|
|
27
|
+
const plugin = createPlugin({ enabled: false });
|
|
28
|
+
const posts = createMockBlogPages(3);
|
|
29
|
+
const result = plugin.transformPosts!({ posts });
|
|
30
|
+
expect(result).toHaveLength(3);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("works as a test plugin", () => {
|
|
34
|
+
const plugin = createTestPlugin({
|
|
35
|
+
name: "noxion-plugin-{{PLUGIN_NAME}}",
|
|
36
|
+
});
|
|
37
|
+
expect(plugin.name).toBe("noxion-plugin-{{PLUGIN_NAME}}");
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { NoxionPlugin, PluginFactory } from "@noxion/core";
|
|
2
|
+
|
|
3
|
+
export interface PluginOptions {
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const createPlugin: PluginFactory<PluginOptions> = (options = {}) => {
|
|
8
|
+
const plugin: NoxionPlugin = {
|
|
9
|
+
name: "noxion-plugin-{{PLUGIN_NAME}}",
|
|
10
|
+
|
|
11
|
+
transformPosts({ posts }) {
|
|
12
|
+
if (options.enabled === false) return posts;
|
|
13
|
+
return posts;
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
return plugin;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default createPlugin;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"declarationMap": true,
|
|
8
|
+
"sourceMap": true,
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"rootDir": "./src",
|
|
11
|
+
"strict": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"types": ["bun-types"]
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*.ts"],
|
|
19
|
+
"exclude": ["node_modules", "dist", "src/**/*.test.ts", "src/**/__tests__/**"]
|
|
20
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { notFound } from "next/navigation";
|
|
2
|
+
import type { Metadata } from "next";
|
|
3
|
+
import { NotionPage } from "@noxion/renderer";
|
|
4
|
+
import { generateNoxionMetadata } from "@noxion/adapter-nextjs";
|
|
5
|
+
import { getProjectBySlug, getPageRecordMap, getAllProjects } from "../../lib/notion";
|
|
6
|
+
import { siteConfig } from "../../lib/config";
|
|
7
|
+
|
|
8
|
+
export const revalidate = 3600;
|
|
9
|
+
|
|
10
|
+
export async function generateStaticParams() {
|
|
11
|
+
const projects = await getAllProjects();
|
|
12
|
+
return projects.map((p) => ({ slug: p.slug }));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function generateMetadata({
|
|
16
|
+
params,
|
|
17
|
+
}: {
|
|
18
|
+
params: Promise<{ slug: string }>;
|
|
19
|
+
}): Promise<Metadata> {
|
|
20
|
+
const { slug } = await params;
|
|
21
|
+
const project = await getProjectBySlug(slug);
|
|
22
|
+
if (!project) return { title: "Not Found" };
|
|
23
|
+
return generateNoxionMetadata(project, siteConfig);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default async function ProjectPage({
|
|
27
|
+
params,
|
|
28
|
+
}: {
|
|
29
|
+
params: Promise<{ slug: string }>;
|
|
30
|
+
}) {
|
|
31
|
+
const { slug } = await params;
|
|
32
|
+
const project = await getProjectBySlug(slug);
|
|
33
|
+
if (!project) notFound();
|
|
34
|
+
|
|
35
|
+
const recordMap = await getPageRecordMap(project.id);
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<article>
|
|
39
|
+
<NotionPage
|
|
40
|
+
recordMap={recordMap}
|
|
41
|
+
rootPageId={project.id}
|
|
42
|
+
fullPage
|
|
43
|
+
previewImages
|
|
44
|
+
mapPageUrl={(pageId: string) => `/${pageId}`}
|
|
45
|
+
/>
|
|
46
|
+
</article>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { revalidatePath } from "next/cache";
|
|
2
|
+
import { createNotionWebhookHandler } from "@noxion/adapter-nextjs";
|
|
3
|
+
import { siteConfig } from "../../../lib/config";
|
|
4
|
+
|
|
5
|
+
const handler = createNotionWebhookHandler({
|
|
6
|
+
config: siteConfig,
|
|
7
|
+
revalidatePath,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export async function POST(request: Request) {
|
|
11
|
+
return handler(request);
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { revalidatePath } from "next/cache";
|
|
2
|
+
import { createRevalidateHandler } from "@noxion/adapter-nextjs";
|
|
3
|
+
import { siteConfig } from "../../../lib/config";
|
|
4
|
+
|
|
5
|
+
const handler = createRevalidateHandler({
|
|
6
|
+
config: siteConfig,
|
|
7
|
+
revalidatePath,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export async function POST(request: Request) {
|
|
11
|
+
return handler(request as never);
|
|
12
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
@import "@noxion/notion-renderer/styles";
|
|
2
|
+
|
|
3
|
+
*,
|
|
4
|
+
*::before,
|
|
5
|
+
*::after {
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
margin: 0;
|
|
8
|
+
padding: 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
html {
|
|
12
|
+
font-family: var(--noxion-font-sans, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
|
|
13
|
+
-webkit-font-smoothing: antialiased;
|
|
14
|
+
-moz-osx-font-smoothing: grayscale;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
body {
|
|
18
|
+
background-color: var(--noxion-background, #fff);
|
|
19
|
+
color: var(--noxion-foreground, #0a0a0a);
|
|
20
|
+
min-height: 100vh;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
[data-theme="dark"] body {
|
|
24
|
+
background-color: var(--noxion-background, #0a0a0a);
|
|
25
|
+
color: var(--noxion-foreground, #fafafa);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
a {
|
|
29
|
+
color: inherit;
|
|
30
|
+
text-decoration: none;
|
|
31
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { generateNoxionListMetadata, generateWebSiteLD } from "@noxion/adapter-nextjs";
|
|
3
|
+
import { siteConfig } from "../lib/config";
|
|
4
|
+
import { ThemeScript } from "./theme-script";
|
|
5
|
+
import { Providers } from "./providers";
|
|
6
|
+
import "./globals.css";
|
|
7
|
+
|
|
8
|
+
export function generateMetadata(): Metadata {
|
|
9
|
+
return generateNoxionListMetadata(siteConfig);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function RootLayout({
|
|
13
|
+
children,
|
|
14
|
+
}: {
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
}) {
|
|
17
|
+
const jsonLd = generateWebSiteLD(siteConfig);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<html lang={siteConfig.language} suppressHydrationWarning>
|
|
21
|
+
<head>
|
|
22
|
+
<ThemeScript />
|
|
23
|
+
<script
|
|
24
|
+
type="application/ld+json"
|
|
25
|
+
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
|
26
|
+
/>
|
|
27
|
+
</head>
|
|
28
|
+
<body>
|
|
29
|
+
<Providers siteName={siteConfig.name} author={siteConfig.author}>
|
|
30
|
+
{children}
|
|
31
|
+
</Providers>
|
|
32
|
+
</body>
|
|
33
|
+
</html>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
|
|
3
|
+
export default function NotFound() {
|
|
4
|
+
return (
|
|
5
|
+
<div
|
|
6
|
+
style={{
|
|
7
|
+
display: "flex",
|
|
8
|
+
flexDirection: "column",
|
|
9
|
+
alignItems: "center",
|
|
10
|
+
justifyContent: "center",
|
|
11
|
+
minHeight: "50vh",
|
|
12
|
+
textAlign: "center",
|
|
13
|
+
gap: "1rem",
|
|
14
|
+
}}
|
|
15
|
+
>
|
|
16
|
+
<h1 style={{ fontSize: "4rem", fontWeight: 700, color: "var(--noxion-mutedForeground, #737373)" }}>
|
|
17
|
+
404
|
|
18
|
+
</h1>
|
|
19
|
+
<p style={{ fontSize: "1.125rem", color: "var(--noxion-mutedForeground, #737373)" }}>
|
|
20
|
+
This page could not be found.
|
|
21
|
+
</p>
|
|
22
|
+
<Link
|
|
23
|
+
href="/"
|
|
24
|
+
style={{
|
|
25
|
+
marginTop: "1rem",
|
|
26
|
+
padding: "0.5rem 1.5rem",
|
|
27
|
+
borderRadius: "var(--noxion-border-radius, 0.5rem)",
|
|
28
|
+
backgroundColor: "var(--noxion-primary, #2563eb)",
|
|
29
|
+
color: "var(--noxion-primaryForeground, #fff)",
|
|
30
|
+
fontSize: "0.875rem",
|
|
31
|
+
fontWeight: 500,
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
Go Home
|
|
35
|
+
</Link>
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|