create-refrakt 0.9.1 → 0.9.3
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/bin.js +96 -42
- package/dist/bin.js.map +1 -1
- package/dist/scaffold.d.ts +2 -1
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +198 -30
- package/dist/scaffold.js.map +1 -1
- package/package.json +9 -2
- package/template/src/routes/[...slug]/+page.server.ts +4 -86
- package/template-astro/_gitignore +2 -0
- package/template-astro/astro.config.mjs +6 -0
- package/template-astro/content/_layout.md +14 -0
- package/template-astro/content/docs/getting-started.md +40 -0
- package/template-astro/content/index.md +18 -0
- package/template-astro/src/pages/[...slug].astro +88 -0
- package/template-astro/src/setup.ts +56 -0
- package/template-astro/tsconfig.json +7 -0
- package/template-eleventy/_gitignore +2 -0
- package/template-eleventy/content/_layout.md +14 -0
- package/template-eleventy/content/docs/getting-started.md +40 -0
- package/template-eleventy/content/index.md +18 -0
- package/template-eleventy/eleventy.config.js +22 -0
- package/template-eleventy/src/_data/refrakt.js +5 -0
- package/template-eleventy/src/_includes/base.njk +22 -0
- package/template-eleventy/src/pages.njk +9 -0
- package/template-next/_gitignore +2 -0
- package/template-next/app/[...slug]/page.tsx +124 -0
- package/template-next/app/layout.tsx +10 -0
- package/template-next/content/_layout.md +14 -0
- package/template-next/content/docs/getting-started.md +40 -0
- package/template-next/content/index.md +18 -0
- package/template-next/next.config.mjs +14 -0
- package/template-next/tsconfig.json +21 -0
- package/template-nuxt/_gitignore +2 -0
- package/template-nuxt/content/_layout.md +14 -0
- package/template-nuxt/content/docs/getting-started.md +40 -0
- package/template-nuxt/content/index.md +18 -0
- package/template-nuxt/nuxt.config.ts +3 -0
- package/template-nuxt/pages/[...slug].vue +107 -0
- package/template-nuxt/tsconfig.json +3 -0
|
@@ -1,98 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getSite, getTransform, getHighlightTransform } from 'virtual:refrakt/content';
|
|
2
2
|
import { serialize, serializeTree } from '@refrakt-md/svelte';
|
|
3
|
-
import { createHighlightTransform } from '@refrakt-md/highlight';
|
|
4
|
-
import type { HighlightTransform } from '@refrakt-md/highlight';
|
|
5
|
-
import { loadRunePackage, mergePackages, runes as coreRunes } from '@refrakt-md/runes';
|
|
6
|
-
import { assembleThemeConfig, createTransform } from '@refrakt-md/transform';
|
|
7
|
-
import type { Schema } from '@markdoc/markdoc';
|
|
8
3
|
import { error } from '@sveltejs/kit';
|
|
9
|
-
import { readFileSync } from 'node:fs';
|
|
10
|
-
import * as path from 'node:path';
|
|
11
4
|
import type { PageServerLoad } from './$types';
|
|
12
|
-
import type { RefraktConfig } from '@refrakt-md/types';
|
|
13
|
-
|
|
14
|
-
const config: RefraktConfig = JSON.parse(readFileSync(path.resolve('refrakt.config.json'), 'utf-8'));
|
|
15
|
-
const contentDir = path.resolve(config.contentDir);
|
|
16
|
-
|
|
17
|
-
let _themeConfig: any = null;
|
|
18
|
-
let _icons: Record<string, Record<string, string>> = {};
|
|
19
|
-
|
|
20
|
-
async function getThemeModule() {
|
|
21
|
-
const themeModule = await import(config.theme + '/transform');
|
|
22
|
-
return themeModule.themeConfig ?? themeModule.luminaConfig ?? themeModule.default;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
let _hl: HighlightTransform | null = null;
|
|
26
|
-
|
|
27
|
-
async function getHighlightTransform(): Promise<HighlightTransform> {
|
|
28
|
-
const cached = _hl;
|
|
29
|
-
if (cached) return cached;
|
|
30
|
-
const hl = await createHighlightTransform(config.highlight);
|
|
31
|
-
_hl = hl;
|
|
32
|
-
return hl;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
let _communityTags: Record<string, Schema> | undefined;
|
|
36
|
-
let _transform: ((tree: any) => any) | null = null;
|
|
37
|
-
|
|
38
|
-
async function getTransform(): Promise<(tree: any) => any> {
|
|
39
|
-
if (_transform) return _transform;
|
|
40
|
-
|
|
41
|
-
const themeConfig = await getThemeModule();
|
|
42
|
-
_icons = {
|
|
43
|
-
...themeConfig.icons,
|
|
44
|
-
global: { ...(themeConfig.icons?.global ?? {}), ...(config.icons ?? {}) },
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const packageNames = config.packages ?? [];
|
|
48
|
-
if (packageNames.length === 0) {
|
|
49
|
-
_transform = createTransform(themeConfig);
|
|
50
|
-
return _transform;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const loaded = await Promise.all(
|
|
54
|
-
packageNames.map((name: string) => loadRunePackage(name))
|
|
55
|
-
);
|
|
56
|
-
const coreRuneNames = new Set(Object.keys(coreRunes));
|
|
57
|
-
const merged = mergePackages(loaded, coreRuneNames, config.runes?.prefer);
|
|
58
|
-
|
|
59
|
-
_communityTags = Object.keys(merged.tags).length > 0 ? merged.tags : undefined;
|
|
60
|
-
|
|
61
|
-
const { config: assembledConfig } = assembleThemeConfig({
|
|
62
|
-
coreConfig: themeConfig,
|
|
63
|
-
packageRunes: merged.themeRunes,
|
|
64
|
-
packageIcons: merged.themeIcons,
|
|
65
|
-
packageBackgrounds: merged.themeBackgrounds,
|
|
66
|
-
extensions: merged.extensions as any,
|
|
67
|
-
provenance: merged.provenance,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
if (config.tints) {
|
|
71
|
-
assembledConfig.tints = { ...assembledConfig.tints, ...config.tints } as any;
|
|
72
|
-
}
|
|
73
|
-
if (config.backgrounds) {
|
|
74
|
-
assembledConfig.backgrounds = { ...assembledConfig.backgrounds, ...config.backgrounds } as any;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
_transform = createTransform(assembledConfig);
|
|
78
|
-
return _transform;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
async function getCommunityTags(): Promise<Record<string, Schema> | undefined> {
|
|
82
|
-
await getTransform();
|
|
83
|
-
return _communityTags;
|
|
84
|
-
}
|
|
85
5
|
|
|
86
6
|
export const prerender = true;
|
|
87
7
|
|
|
88
8
|
export const load: PageServerLoad = async ({ params }) => {
|
|
89
|
-
const [
|
|
9
|
+
const [site, transform, hl] = await Promise.all([
|
|
10
|
+
getSite(),
|
|
90
11
|
getTransform(),
|
|
91
|
-
getCommunityTags(),
|
|
92
12
|
getHighlightTransform(),
|
|
93
13
|
]);
|
|
94
14
|
|
|
95
|
-
const site = await loadContent(contentDir, '/', _icons, communityTags);
|
|
96
15
|
const slug = params.slug || '';
|
|
97
16
|
const url = '/' + slug;
|
|
98
17
|
|
|
@@ -124,8 +43,7 @@ export const load: PageServerLoad = async ({ params }) => {
|
|
|
124
43
|
};
|
|
125
44
|
|
|
126
45
|
export async function entries() {
|
|
127
|
-
const
|
|
128
|
-
const site = await loadContent(contentDir, '/', _icons, communityTags);
|
|
46
|
+
const site = await getSite();
|
|
129
47
|
return site.pages
|
|
130
48
|
.filter(p => !p.route.draft)
|
|
131
49
|
.map(p => ({ slug: p.route.url === '/' ? '' : p.route.url.slice(1) }));
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Getting Started
|
|
3
|
+
description: Learn how to work with your refrakt.md site
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Getting Started
|
|
7
|
+
|
|
8
|
+
This is your first documentation page. You can find this file at `content/docs/getting-started.md`.
|
|
9
|
+
|
|
10
|
+
## Project Structure
|
|
11
|
+
|
|
12
|
+
Your site has two key directories:
|
|
13
|
+
|
|
14
|
+
- `content/` — Markdown files that make up your pages
|
|
15
|
+
- `build/` — Generated HTML output (created by `npm run build`)
|
|
16
|
+
|
|
17
|
+
## Writing Content
|
|
18
|
+
|
|
19
|
+
Every Markdown file in `content/` becomes a page. Add frontmatter at the top for metadata:
|
|
20
|
+
|
|
21
|
+
```markdown
|
|
22
|
+
---
|
|
23
|
+
title: Page Title
|
|
24
|
+
description: A brief description
|
|
25
|
+
---
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Using Runes
|
|
29
|
+
|
|
30
|
+
Runes are Markdoc tags that give your Markdown semantic meaning:
|
|
31
|
+
|
|
32
|
+
{% hint type="note" %}
|
|
33
|
+
This callout is created with the `hint` rune. Try changing the `type` attribute to `warning`, `caution`, or `check`.
|
|
34
|
+
{% /hint %}
|
|
35
|
+
|
|
36
|
+
## Next Steps
|
|
37
|
+
|
|
38
|
+
- Add more pages by creating `.md` files in `content/`
|
|
39
|
+
- Edit `content/_layout.md` to customize your site's header and navigation
|
|
40
|
+
- Explore the available runes in the refrakt.md documentation
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Welcome
|
|
3
|
+
description: A new refrakt.md site
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
{% cta %}
|
|
7
|
+
|
|
8
|
+
# Welcome to your site
|
|
9
|
+
|
|
10
|
+
This site is built with refrakt.md — a content framework that extends Markdown with semantic runes.
|
|
11
|
+
|
|
12
|
+
- [Get Started](/docs/getting-started)
|
|
13
|
+
|
|
14
|
+
{% /cta %}
|
|
15
|
+
|
|
16
|
+
{% hint type="note" %}
|
|
17
|
+
Edit the files in `content/` to start building your site. Run `npm run build` to regenerate after changes.
|
|
18
|
+
{% /hint %}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
import '@refrakt-md/lumina';
|
|
3
|
+
import { getTransform, getSite } from '../setup';
|
|
4
|
+
import manifest from '@refrakt-md/lumina/manifest';
|
|
5
|
+
import { layouts } from '@refrakt-md/lumina/layouts';
|
|
6
|
+
import { renderPage, buildSeoHead, hasInteractiveRunes } from '@refrakt-md/astro';
|
|
7
|
+
import type { RendererNode } from '@refrakt-md/types';
|
|
8
|
+
|
|
9
|
+
const theme = { manifest, layouts };
|
|
10
|
+
|
|
11
|
+
export async function getStaticPaths() {
|
|
12
|
+
const [transform, site] = await Promise.all([getTransform(), getSite()]);
|
|
13
|
+
|
|
14
|
+
return site.pages
|
|
15
|
+
.filter((p: any) => !p.route.draft)
|
|
16
|
+
.map((page: any) => {
|
|
17
|
+
const renderable = transform(page.renderable) as RendererNode;
|
|
18
|
+
const regions: Record<string, any> = {};
|
|
19
|
+
for (const [name, region] of page.layout.regions.entries()) {
|
|
20
|
+
regions[name] = {
|
|
21
|
+
name: region.name,
|
|
22
|
+
mode: region.mode,
|
|
23
|
+
content: region.content.map((c: any) => transform(c) as RendererNode),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const pages = site.pages
|
|
28
|
+
.filter((p: any) => !p.route.draft)
|
|
29
|
+
.map((p: any) => ({
|
|
30
|
+
url: p.route.url,
|
|
31
|
+
title: (p.frontmatter.title as string) ?? '',
|
|
32
|
+
draft: false,
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
const slug = page.route.url === '/' ? undefined : page.route.url.slice(1);
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
params: { slug },
|
|
39
|
+
props: {
|
|
40
|
+
page: {
|
|
41
|
+
renderable,
|
|
42
|
+
regions,
|
|
43
|
+
title: (page.frontmatter.title as string) ?? '',
|
|
44
|
+
url: page.route.url,
|
|
45
|
+
pages,
|
|
46
|
+
frontmatter: page.frontmatter,
|
|
47
|
+
headings: page.headings,
|
|
48
|
+
},
|
|
49
|
+
seo: page.seo,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const { page, seo } = Astro.props;
|
|
56
|
+
const html = renderPage({ theme, page });
|
|
57
|
+
const head = buildSeoHead({ title: page.title, frontmatter: page.frontmatter, seo });
|
|
58
|
+
const needsBehaviors = hasInteractiveRunes(page.renderable);
|
|
59
|
+
const contextData = JSON.stringify({ pages: page.pages, currentUrl: page.url });
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
<html lang="en">
|
|
63
|
+
<head>
|
|
64
|
+
<meta charset="utf-8" />
|
|
65
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
66
|
+
{head.title && <title>{head.title}</title>}
|
|
67
|
+
<Fragment set:html={head.metaTags} />
|
|
68
|
+
<Fragment set:html={head.jsonLd} />
|
|
69
|
+
</head>
|
|
70
|
+
<body>
|
|
71
|
+
<Fragment set:html={html} />
|
|
72
|
+
<script type="application/json" id="rf-context" set:html={contextData} />
|
|
73
|
+
{needsBehaviors && (
|
|
74
|
+
<script>
|
|
75
|
+
import { registerElements, RfContext, initRuneBehaviors, initLayoutBehaviors } from '@refrakt-md/behaviors';
|
|
76
|
+
function init() {
|
|
77
|
+
const el = document.getElementById('rf-context');
|
|
78
|
+
if (el) { try { const ctx = JSON.parse(el.textContent || '{}'); RfContext.pages = ctx.pages; RfContext.currentUrl = ctx.currentUrl; } catch {} }
|
|
79
|
+
registerElements();
|
|
80
|
+
initRuneBehaviors();
|
|
81
|
+
initLayoutBehaviors();
|
|
82
|
+
}
|
|
83
|
+
init();
|
|
84
|
+
document.addEventListener('astro:page-load', () => init());
|
|
85
|
+
</script>
|
|
86
|
+
)}
|
|
87
|
+
</body>
|
|
88
|
+
</html>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { loadContent } from '@refrakt-md/content';
|
|
2
|
+
import { assembleThemeConfig, createTransform } from '@refrakt-md/transform';
|
|
3
|
+
import { loadRunePackage, mergePackages, runes as coreRunes } from '@refrakt-md/runes';
|
|
4
|
+
import type { RefraktConfig } from '@refrakt-md/types';
|
|
5
|
+
import type { Schema } from '@markdoc/markdoc';
|
|
6
|
+
import { readFileSync } from 'node:fs';
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
|
|
9
|
+
const config: RefraktConfig = JSON.parse(readFileSync(path.resolve('refrakt.config.json'), 'utf-8'));
|
|
10
|
+
const contentDir = path.resolve(config.contentDir);
|
|
11
|
+
|
|
12
|
+
let _transform: ((tree: any) => any) | null = null;
|
|
13
|
+
let _communityTags: Record<string, Schema> | undefined;
|
|
14
|
+
|
|
15
|
+
async function init() {
|
|
16
|
+
if (_transform) return;
|
|
17
|
+
|
|
18
|
+
const themeModule = await import(config.theme + '/transform');
|
|
19
|
+
const themeConfig = themeModule.themeConfig ?? themeModule.luminaConfig ?? themeModule.default;
|
|
20
|
+
|
|
21
|
+
let transformConfig = themeConfig;
|
|
22
|
+
|
|
23
|
+
const packageNames = config.packages ?? [];
|
|
24
|
+
if (packageNames.length > 0) {
|
|
25
|
+
const loaded = await Promise.all(
|
|
26
|
+
packageNames.map((name: string) => loadRunePackage(name))
|
|
27
|
+
);
|
|
28
|
+
const coreRuneNames = new Set(Object.keys(coreRunes));
|
|
29
|
+
const merged = mergePackages(loaded, coreRuneNames, config.runes?.prefer);
|
|
30
|
+
|
|
31
|
+
_communityTags = Object.keys(merged.tags).length > 0 ? merged.tags : undefined;
|
|
32
|
+
|
|
33
|
+
const { config: assembledConfig } = assembleThemeConfig({
|
|
34
|
+
coreConfig: themeConfig,
|
|
35
|
+
packageRunes: merged.themeRunes,
|
|
36
|
+
packageIcons: merged.themeIcons,
|
|
37
|
+
packageBackgrounds: merged.themeBackgrounds,
|
|
38
|
+
extensions: merged.extensions as any,
|
|
39
|
+
provenance: merged.provenance,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
transformConfig = assembledConfig;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
_transform = createTransform(transformConfig);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function getTransform() {
|
|
49
|
+
await init();
|
|
50
|
+
return _transform!;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function getSite() {
|
|
54
|
+
await init();
|
|
55
|
+
return loadContent(contentDir, '/', {}, _communityTags);
|
|
56
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Getting Started
|
|
3
|
+
description: Learn how to work with your refrakt.md site
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Getting Started
|
|
7
|
+
|
|
8
|
+
This is your first documentation page. You can find this file at `content/docs/getting-started.md`.
|
|
9
|
+
|
|
10
|
+
## Project Structure
|
|
11
|
+
|
|
12
|
+
Your site has two key directories:
|
|
13
|
+
|
|
14
|
+
- `content/` — Markdown files that make up your pages
|
|
15
|
+
- `build/` — Generated HTML output (created by `npm run build`)
|
|
16
|
+
|
|
17
|
+
## Writing Content
|
|
18
|
+
|
|
19
|
+
Every Markdown file in `content/` becomes a page. Add frontmatter at the top for metadata:
|
|
20
|
+
|
|
21
|
+
```markdown
|
|
22
|
+
---
|
|
23
|
+
title: Page Title
|
|
24
|
+
description: A brief description
|
|
25
|
+
---
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Using Runes
|
|
29
|
+
|
|
30
|
+
Runes are Markdoc tags that give your Markdown semantic meaning:
|
|
31
|
+
|
|
32
|
+
{% hint type="note" %}
|
|
33
|
+
This callout is created with the `hint` rune. Try changing the `type` attribute to `warning`, `caution`, or `check`.
|
|
34
|
+
{% /hint %}
|
|
35
|
+
|
|
36
|
+
## Next Steps
|
|
37
|
+
|
|
38
|
+
- Add more pages by creating `.md` files in `content/`
|
|
39
|
+
- Edit `content/_layout.md` to customize your site's header and navigation
|
|
40
|
+
- Explore the available runes in the refrakt.md documentation
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Welcome
|
|
3
|
+
description: A new refrakt.md site
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
{% cta %}
|
|
7
|
+
|
|
8
|
+
# Welcome to your site
|
|
9
|
+
|
|
10
|
+
This site is built with refrakt.md — a content framework that extends Markdown with semantic runes.
|
|
11
|
+
|
|
12
|
+
- [Get Started](/docs/getting-started)
|
|
13
|
+
|
|
14
|
+
{% /cta %}
|
|
15
|
+
|
|
16
|
+
{% hint type="note" %}
|
|
17
|
+
Edit the files in `content/` to start building your site. Run `npm run build` to regenerate after changes.
|
|
18
|
+
{% /hint %}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { refraktPlugin } from '@refrakt-md/eleventy';
|
|
2
|
+
|
|
3
|
+
export default function (eleventyConfig) {
|
|
4
|
+
eleventyConfig.addPlugin(refraktPlugin, {
|
|
5
|
+
cssFiles: ['node_modules/@refrakt-md/lumina/index.css'],
|
|
6
|
+
cssPrefix: '/css',
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
eleventyConfig.addPassthroughCopy({
|
|
10
|
+
'node_modules/@refrakt-md/lumina/tokens': '/css/tokens',
|
|
11
|
+
'node_modules/@refrakt-md/lumina/styles': '/css/styles',
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
dir: {
|
|
16
|
+
input: 'src',
|
|
17
|
+
output: '_site',
|
|
18
|
+
includes: '_includes',
|
|
19
|
+
data: '_data',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
{% if seo.title %}<title>{{ seo.title }}</title>{% endif %}
|
|
7
|
+
{{ seo.metaTags | safe }}
|
|
8
|
+
{{ seo.jsonLd | safe }}
|
|
9
|
+
<link rel="stylesheet" href="/css/index.css">
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
{{ html | safe }}
|
|
13
|
+
<script type="module">
|
|
14
|
+
import { registerElements, RfContext, initRuneBehaviors, initLayoutBehaviors } from '/js/behaviors.js';
|
|
15
|
+
|
|
16
|
+
RfContext.currentUrl = '{{ url }}';
|
|
17
|
+
registerElements();
|
|
18
|
+
initRuneBehaviors();
|
|
19
|
+
initLayoutBehaviors();
|
|
20
|
+
</script>
|
|
21
|
+
</body>
|
|
22
|
+
</html>
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { loadContent } from '@refrakt-md/content';
|
|
2
|
+
import { assembleThemeConfig, createTransform } from '@refrakt-md/transform';
|
|
3
|
+
import { loadRunePackage, mergePackages, runes as coreRunes } from '@refrakt-md/runes';
|
|
4
|
+
import manifest from '@refrakt-md/lumina/manifest';
|
|
5
|
+
import { layouts } from '@refrakt-md/lumina/layouts';
|
|
6
|
+
const theme = { manifest, layouts };
|
|
7
|
+
import { RefraktContent, buildMetadata, buildUrlFromParams, hasInteractiveRunes } from '@refrakt-md/next';
|
|
8
|
+
import { BehaviorInit } from '@refrakt-md/next/client';
|
|
9
|
+
import type { RendererNode } from '@refrakt-md/types';
|
|
10
|
+
import type { RefraktConfig } from '@refrakt-md/types';
|
|
11
|
+
import type { Schema } from '@markdoc/markdoc';
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
|
|
15
|
+
const config: RefraktConfig = JSON.parse(readFileSync(path.resolve('refrakt.config.json'), 'utf-8'));
|
|
16
|
+
const contentDir = path.resolve(config.contentDir);
|
|
17
|
+
|
|
18
|
+
async function getTransformAndTags() {
|
|
19
|
+
const themeModule = await import(config.theme + '/transform');
|
|
20
|
+
const themeConfig = themeModule.themeConfig ?? themeModule.luminaConfig ?? themeModule.default;
|
|
21
|
+
|
|
22
|
+
const packageNames = config.packages ?? [];
|
|
23
|
+
if (packageNames.length === 0) {
|
|
24
|
+
return { transform: createTransform(themeConfig), communityTags: undefined };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const loaded = await Promise.all(
|
|
28
|
+
packageNames.map((name: string) => loadRunePackage(name))
|
|
29
|
+
);
|
|
30
|
+
const coreRuneNames = new Set(Object.keys(coreRunes));
|
|
31
|
+
const merged = mergePackages(loaded, coreRuneNames, config.runes?.prefer);
|
|
32
|
+
|
|
33
|
+
const communityTags: Record<string, Schema> | undefined =
|
|
34
|
+
Object.keys(merged.tags).length > 0 ? merged.tags : undefined;
|
|
35
|
+
|
|
36
|
+
const { config: assembledConfig } = assembleThemeConfig({
|
|
37
|
+
coreConfig: themeConfig,
|
|
38
|
+
packageRunes: merged.themeRunes,
|
|
39
|
+
packageIcons: merged.themeIcons,
|
|
40
|
+
packageBackgrounds: merged.themeBackgrounds,
|
|
41
|
+
extensions: merged.extensions as any,
|
|
42
|
+
provenance: merged.provenance,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return { transform: createTransform(assembledConfig), communityTags };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let _cached: Awaited<ReturnType<typeof getTransformAndTags>> | null = null;
|
|
49
|
+
async function getCached() {
|
|
50
|
+
if (!_cached) _cached = await getTransformAndTags();
|
|
51
|
+
return _cached;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function generateStaticParams() {
|
|
55
|
+
const { communityTags } = await getCached();
|
|
56
|
+
const site = await loadContent(contentDir, '/', {}, communityTags);
|
|
57
|
+
return site.pages
|
|
58
|
+
.filter((p: any) => !p.route.draft)
|
|
59
|
+
.map((page: any) => ({
|
|
60
|
+
slug: page.route.url === '/' ? [] : page.route.url.slice(1).split('/'),
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function generateMetadata({ params }: { params: Promise<{ slug?: string[] }> }) {
|
|
65
|
+
const resolvedParams = await params;
|
|
66
|
+
const url = buildUrlFromParams(resolvedParams);
|
|
67
|
+
const { communityTags } = await getCached();
|
|
68
|
+
const site = await loadContent(contentDir, '/', {}, communityTags);
|
|
69
|
+
const page = site.pages.find((p: any) => p.route.url === url);
|
|
70
|
+
if (!page) return {};
|
|
71
|
+
|
|
72
|
+
return buildMetadata({
|
|
73
|
+
title: (page.frontmatter.title as string) ?? '',
|
|
74
|
+
frontmatter: page.frontmatter,
|
|
75
|
+
seo: page.seo,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default async function Page({ params }: { params: Promise<{ slug?: string[] }> }) {
|
|
80
|
+
const resolvedParams = await params;
|
|
81
|
+
const url = buildUrlFromParams(resolvedParams);
|
|
82
|
+
const { transform, communityTags } = await getCached();
|
|
83
|
+
const site = await loadContent(contentDir, '/', {}, communityTags);
|
|
84
|
+
const currentPage = site.pages.find((p: any) => p.route.url === url);
|
|
85
|
+
if (!currentPage) return <div>Page not found</div>;
|
|
86
|
+
|
|
87
|
+
const renderable = transform(currentPage.renderable) as RendererNode;
|
|
88
|
+
|
|
89
|
+
const regions: Record<string, any> = {};
|
|
90
|
+
for (const [name, region] of currentPage.layout.regions.entries()) {
|
|
91
|
+
regions[name] = {
|
|
92
|
+
name: region.name,
|
|
93
|
+
mode: region.mode,
|
|
94
|
+
content: region.content.map((c: any) => transform(c) as RendererNode),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const pages = site.pages
|
|
99
|
+
.filter((p: any) => !p.route.draft)
|
|
100
|
+
.map((p: any) => ({
|
|
101
|
+
url: p.route.url,
|
|
102
|
+
title: (p.frontmatter.title as string) ?? '',
|
|
103
|
+
draft: false,
|
|
104
|
+
}));
|
|
105
|
+
|
|
106
|
+
const page = {
|
|
107
|
+
renderable,
|
|
108
|
+
regions,
|
|
109
|
+
title: (currentPage.frontmatter.title as string) ?? '',
|
|
110
|
+
url: currentPage.route.url,
|
|
111
|
+
pages,
|
|
112
|
+
frontmatter: currentPage.frontmatter,
|
|
113
|
+
headings: currentPage.headings,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const needsBehaviors = hasInteractiveRunes(page.renderable);
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<>
|
|
120
|
+
<RefraktContent theme={theme} page={page} />
|
|
121
|
+
{needsBehaviors && <BehaviorInit pages={pages} currentUrl={page.url} />}
|
|
122
|
+
</>
|
|
123
|
+
);
|
|
124
|
+
}
|