@kamod-ch/preactpress 1.0.3 → 2.0.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/client/app.d.ts.map +1 -1
- package/dist/client/app.js +34 -4
- package/dist/client/app.js.map +1 -1
- package/dist/client/mermaid.d.ts +2 -0
- package/dist/client/mermaid.d.ts.map +1 -0
- package/dist/client/mermaid.js +68 -0
- package/dist/client/mermaid.js.map +1 -0
- package/dist/client/theme-default/Layout.d.ts.map +1 -1
- package/dist/client/theme-default/Layout.js +43 -0
- package/dist/client/theme-default/Layout.js.map +1 -1
- package/dist/node/markdown.d.ts.map +1 -1
- package/dist/node/markdown.js +24 -6
- package/dist/node/markdown.js.map +1 -1
- package/dist/shared/scrollRestoration.d.ts +2 -1
- package/dist/shared/scrollRestoration.d.ts.map +1 -1
- package/dist/shared/scrollRestoration.js +36 -14
- package/dist/shared/scrollRestoration.js.map +1 -1
- package/package.json +2 -1
- package/src/client/app.tsx +33 -3
- package/src/client/mermaid.ts +74 -0
- package/src/client/theme-default/Layout.tsx +43 -0
- package/src/client/theme-default/styles.css +181 -5
- package/src/shared/scrollRestoration.ts +45 -14
- package/templates/docs/.preactpress/config.ts +5 -0
- package/templates/docs/examples/cloudflare-pages.md +117 -0
- package/templates/docs/examples/custom-theme.md +266 -0
- package/templates/docs/examples/mermaid.md +53 -0
- package/templates/docs/examples/preact-signals.md +102 -0
- package/templates/docs/examples/rss.md +104 -0
- package/templates/docs/guide/custom-themes.md +1 -1
- package/templates/docs/guide/deploy.md +2 -0
- package/templates/docs/guide/markdown-and-mdx.md +1 -1
- package/templates/docs/markdown-examples.md +10 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Custom theme example
|
|
3
|
+
description: A minimal copy-pasteable PreactPress theme with navigation, Markdown, MDX, and styling.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
This example shows a small custom theme you can copy into your project. For a larger production-style example, scaffold the bundled magazine template:
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
pnpm exec preactpress init my-magazine --template magazine
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## File structure
|
|
13
|
+
|
|
14
|
+
```txt
|
|
15
|
+
.preactpress/
|
|
16
|
+
config.ts
|
|
17
|
+
theme/
|
|
18
|
+
Layout.tsx
|
|
19
|
+
theme.css
|
|
20
|
+
index.md
|
|
21
|
+
about.md
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Configure the theme
|
|
25
|
+
|
|
26
|
+
```ts [.preactpress/config.ts]
|
|
27
|
+
import { defineConfig } from "@kamod-ch/preactpress/config";
|
|
28
|
+
|
|
29
|
+
export default defineConfig({
|
|
30
|
+
site: {
|
|
31
|
+
title: "Acme Docs",
|
|
32
|
+
description: "A custom themed PreactPress site",
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
// Relative to .preactpress/
|
|
36
|
+
theme: "./theme/Layout.tsx",
|
|
37
|
+
|
|
38
|
+
themeConfig: {
|
|
39
|
+
nav: [
|
|
40
|
+
{ text: "Home", link: "/" },
|
|
41
|
+
{ text: "About", link: "/about" },
|
|
42
|
+
],
|
|
43
|
+
footer: "Built with PreactPress",
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Layout component
|
|
49
|
+
|
|
50
|
+
```tsx [.preactpress/theme/Layout.tsx]
|
|
51
|
+
import type { FunctionalComponent } from "preact";
|
|
52
|
+
import {
|
|
53
|
+
createMdxHeadingComponents,
|
|
54
|
+
isActive,
|
|
55
|
+
withBase,
|
|
56
|
+
type LayoutProps,
|
|
57
|
+
} from "@kamod-ch/preactpress/client";
|
|
58
|
+
import "./theme.css";
|
|
59
|
+
|
|
60
|
+
const Layout: FunctionalComponent<LayoutProps> = ({ site, themeConfig, routePath, page }) => {
|
|
61
|
+
const MdxComponent = page?.kind === "mdx" ? page.Component : undefined;
|
|
62
|
+
const mdxComponents = createMdxHeadingComponents({
|
|
63
|
+
headingClass: "ct-heading",
|
|
64
|
+
anchorClass: "ct-heading-anchor",
|
|
65
|
+
anchorLabel: "Link to this section",
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<div class="ct-layout">
|
|
70
|
+
<a class="ct-skip" href="#content">
|
|
71
|
+
Skip to content
|
|
72
|
+
</a>
|
|
73
|
+
|
|
74
|
+
<header class="ct-header">
|
|
75
|
+
<a class="ct-brand" href={withBase(site.base, "/")}>
|
|
76
|
+
{site.title}
|
|
77
|
+
</a>
|
|
78
|
+
<nav class="ct-nav" aria-label="Main navigation">
|
|
79
|
+
{(themeConfig.nav ?? []).map((item) => {
|
|
80
|
+
const active = isActive(routePath, item.link);
|
|
81
|
+
return (
|
|
82
|
+
<a
|
|
83
|
+
key={item.link}
|
|
84
|
+
href={withBase(site.base, item.link)}
|
|
85
|
+
class={active ? "active" : ""}
|
|
86
|
+
aria-current={active ? "page" : undefined}
|
|
87
|
+
>
|
|
88
|
+
{item.text}
|
|
89
|
+
</a>
|
|
90
|
+
);
|
|
91
|
+
})}
|
|
92
|
+
</nav>
|
|
93
|
+
</header>
|
|
94
|
+
|
|
95
|
+
<main id="content" class="ct-main" tabIndex={-1}>
|
|
96
|
+
<article class="ct-article">
|
|
97
|
+
<h1>{page?.title ?? site.title}</h1>
|
|
98
|
+
{page?.description ? <p class="ct-lead">{page.description}</p> : null}
|
|
99
|
+
|
|
100
|
+
{MdxComponent ? (
|
|
101
|
+
<div class="ct-content">
|
|
102
|
+
<MdxComponent components={mdxComponents} />
|
|
103
|
+
</div>
|
|
104
|
+
) : (
|
|
105
|
+
<div
|
|
106
|
+
class="ct-content"
|
|
107
|
+
dangerouslySetInnerHTML={{ __html: page?.kind === "markdown" ? page.html : "" }}
|
|
108
|
+
/>
|
|
109
|
+
)}
|
|
110
|
+
</article>
|
|
111
|
+
</main>
|
|
112
|
+
|
|
113
|
+
{themeConfig.footer ? <footer class="ct-footer">{themeConfig.footer}</footer> : null}
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export default Layout;
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Styling
|
|
122
|
+
|
|
123
|
+
```css [.preactpress/theme/theme.css]
|
|
124
|
+
:root {
|
|
125
|
+
color-scheme: light dark;
|
|
126
|
+
--ct-bg: #f7f3ea;
|
|
127
|
+
--ct-panel: #fffaf0;
|
|
128
|
+
--ct-text: #1f2937;
|
|
129
|
+
--ct-muted: #6b7280;
|
|
130
|
+
--ct-border: #eadfca;
|
|
131
|
+
--ct-accent: #b45309;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@media (prefers-color-scheme: dark) {
|
|
135
|
+
:root {
|
|
136
|
+
--ct-bg: #15110b;
|
|
137
|
+
--ct-panel: #1f1a12;
|
|
138
|
+
--ct-text: #f8ecd5;
|
|
139
|
+
--ct-muted: #c5bba9;
|
|
140
|
+
--ct-border: #3b3022;
|
|
141
|
+
--ct-accent: #fbbf24;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
body {
|
|
146
|
+
margin: 0;
|
|
147
|
+
background: var(--ct-bg);
|
|
148
|
+
color: var(--ct-text);
|
|
149
|
+
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.ct-skip {
|
|
153
|
+
position: absolute;
|
|
154
|
+
left: 1rem;
|
|
155
|
+
top: -4rem;
|
|
156
|
+
z-index: 10;
|
|
157
|
+
background: var(--ct-accent);
|
|
158
|
+
color: #111827;
|
|
159
|
+
padding: 0.5rem 0.75rem;
|
|
160
|
+
border-radius: 999px;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.ct-skip:focus {
|
|
164
|
+
top: 1rem;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.ct-header {
|
|
168
|
+
max-width: 1040px;
|
|
169
|
+
margin: 0 auto;
|
|
170
|
+
padding: 1.25rem;
|
|
171
|
+
display: flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
justify-content: space-between;
|
|
174
|
+
gap: 1rem;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.ct-brand {
|
|
178
|
+
color: inherit;
|
|
179
|
+
font-weight: 800;
|
|
180
|
+
text-decoration: none;
|
|
181
|
+
letter-spacing: -0.04em;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.ct-nav {
|
|
185
|
+
display: flex;
|
|
186
|
+
gap: 0.35rem;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.ct-nav a {
|
|
190
|
+
color: var(--ct-muted);
|
|
191
|
+
text-decoration: none;
|
|
192
|
+
padding: 0.45rem 0.7rem;
|
|
193
|
+
border-radius: 999px;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.ct-nav a:hover,
|
|
197
|
+
.ct-nav a.active {
|
|
198
|
+
background: color-mix(in srgb, var(--ct-accent) 16%, transparent);
|
|
199
|
+
color: var(--ct-text);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.ct-main {
|
|
203
|
+
max-width: 1040px;
|
|
204
|
+
margin: 0 auto;
|
|
205
|
+
padding: 1.25rem;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.ct-article {
|
|
209
|
+
background: var(--ct-panel);
|
|
210
|
+
border: 1px solid var(--ct-border);
|
|
211
|
+
border-radius: 28px;
|
|
212
|
+
padding: clamp(1.5rem, 4vw, 3rem);
|
|
213
|
+
box-shadow: 0 24px 70px rgb(0 0 0 / 0.08);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.ct-article h1 {
|
|
217
|
+
margin: 0;
|
|
218
|
+
font-size: clamp(2.4rem, 8vw, 5rem);
|
|
219
|
+
letter-spacing: -0.07em;
|
|
220
|
+
line-height: 0.95;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.ct-lead {
|
|
224
|
+
color: var(--ct-muted);
|
|
225
|
+
font-size: 1.2rem;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.ct-content {
|
|
229
|
+
line-height: 1.75;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.ct-content a {
|
|
233
|
+
color: var(--ct-accent);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.ct-content pre {
|
|
237
|
+
overflow: auto;
|
|
238
|
+
padding: 1rem;
|
|
239
|
+
border-radius: 16px;
|
|
240
|
+
background: #111827;
|
|
241
|
+
color: #f9fafb;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.ct-heading-anchor {
|
|
245
|
+
opacity: 0;
|
|
246
|
+
margin-left: 0.4rem;
|
|
247
|
+
color: var(--ct-muted);
|
|
248
|
+
text-decoration: none;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.ct-heading:hover .ct-heading-anchor,
|
|
252
|
+
.ct-heading-anchor:focus-visible {
|
|
253
|
+
opacity: 1;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.ct-footer {
|
|
257
|
+
max-width: 1040px;
|
|
258
|
+
margin: 0 auto;
|
|
259
|
+
padding: 2rem 1.25rem;
|
|
260
|
+
color: var(--ct-muted);
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Notes
|
|
265
|
+
|
|
266
|
+
A custom theme receives the same `LayoutProps` as the default theme. Your layout is responsible for rendering Markdown versus MDX pages, navigation, responsive behavior, search UI, focus management, and any theme-specific styling.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Mermaid diagrams
|
|
3
|
+
description: Render flowcharts, sequence diagrams, and other Mermaid diagrams in Markdown and MDX.
|
|
4
|
+
tags:
|
|
5
|
+
- examples
|
|
6
|
+
- markdown
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
PreactPress renders Mermaid diagrams from fenced code blocks. Use the `mermaid` language name:
|
|
10
|
+
|
|
11
|
+
````md
|
|
12
|
+
```mermaid
|
|
13
|
+
graph TD
|
|
14
|
+
A[Markdown] --> B[PreactPress]
|
|
15
|
+
B --> C[Static HTML]
|
|
16
|
+
```
|
|
17
|
+
````
|
|
18
|
+
|
|
19
|
+
## Flowchart
|
|
20
|
+
|
|
21
|
+
```mermaid
|
|
22
|
+
graph TD
|
|
23
|
+
A[Markdown] --> B[PreactPress]
|
|
24
|
+
B --> C[Static HTML]
|
|
25
|
+
C --> D[Fast docs site]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Sequence diagram
|
|
29
|
+
|
|
30
|
+
```mermaid
|
|
31
|
+
sequenceDiagram
|
|
32
|
+
participant User
|
|
33
|
+
participant Site as PreactPress Site
|
|
34
|
+
participant Mermaid
|
|
35
|
+
|
|
36
|
+
User->>Site: Open docs page
|
|
37
|
+
Site->>Mermaid: Render diagram block
|
|
38
|
+
Mermaid-->>Site: SVG diagram
|
|
39
|
+
Site-->>User: Interactive documentation
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## State diagram
|
|
43
|
+
|
|
44
|
+
```mermaid
|
|
45
|
+
stateDiagram-v2
|
|
46
|
+
[*] --> Draft
|
|
47
|
+
Draft --> Review
|
|
48
|
+
Review --> Published
|
|
49
|
+
Review --> Draft
|
|
50
|
+
Published --> [*]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Mermaid is loaded on the client only when a page contains a diagram.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Preact Signals
|
|
3
|
+
description: Use @preact/signals in MDX components and custom PreactPress themes.
|
|
4
|
+
tags:
|
|
5
|
+
- examples
|
|
6
|
+
- mdx
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
PreactPress is built on Preact, so you can use `@preact/signals` in MDX components and custom themes.
|
|
10
|
+
|
|
11
|
+
Install Signals in your site project:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
pnpm add @preact/signals
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Component example
|
|
18
|
+
|
|
19
|
+
Create a normal Preact component:
|
|
20
|
+
|
|
21
|
+
```tsx [components/SignalCounter.tsx]
|
|
22
|
+
import { signal } from "@preact/signals";
|
|
23
|
+
|
|
24
|
+
const count = signal(0);
|
|
25
|
+
|
|
26
|
+
export default function SignalCounter() {
|
|
27
|
+
return (
|
|
28
|
+
<button type="button" onClick={() => count.value++}>
|
|
29
|
+
Count: {count}
|
|
30
|
+
</button>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Then import it from an MDX page:
|
|
36
|
+
|
|
37
|
+
```mdx [interactive.mdx]
|
|
38
|
+
import SignalCounter from "./components/SignalCounter";
|
|
39
|
+
|
|
40
|
+
# Signals demo
|
|
41
|
+
|
|
42
|
+
<SignalCounter />
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Derived values
|
|
46
|
+
|
|
47
|
+
Use `computed` for derived state:
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import { computed, signal } from "@preact/signals";
|
|
51
|
+
|
|
52
|
+
const count = signal(0);
|
|
53
|
+
const doubled = computed(() => count.value * 2);
|
|
54
|
+
|
|
55
|
+
export default function DoubledCounter() {
|
|
56
|
+
return (
|
|
57
|
+
<div>
|
|
58
|
+
<button type="button" onClick={() => count.value++}>
|
|
59
|
+
Count: {count}
|
|
60
|
+
</button>
|
|
61
|
+
<p>Doubled: {doubled}</p>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Custom theme usage
|
|
68
|
+
|
|
69
|
+
Signals also work inside a custom theme:
|
|
70
|
+
|
|
71
|
+
```tsx [.preactpress/theme/Layout.tsx]
|
|
72
|
+
import type { FunctionalComponent } from "preact";
|
|
73
|
+
import { signal } from "@preact/signals";
|
|
74
|
+
import type { LayoutProps } from "@kamod-ch/preactpress/client";
|
|
75
|
+
|
|
76
|
+
const menuOpen = signal(false);
|
|
77
|
+
|
|
78
|
+
const Layout: FunctionalComponent<LayoutProps> = ({ site, page }) => (
|
|
79
|
+
<div>
|
|
80
|
+
<header>
|
|
81
|
+
<a href="/">{site.title}</a>
|
|
82
|
+
<button type="button" onClick={() => (menuOpen.value = !menuOpen.value)}>
|
|
83
|
+
Menu
|
|
84
|
+
</button>
|
|
85
|
+
</header>
|
|
86
|
+
|
|
87
|
+
{menuOpen.value ? <nav>Navigation…</nav> : null}
|
|
88
|
+
|
|
89
|
+
<main id="content">
|
|
90
|
+
{page?.kind === "markdown" ? (
|
|
91
|
+
<article dangerouslySetInnerHTML={{ __html: page.html }} />
|
|
92
|
+
) : page?.kind === "mdx" ? (
|
|
93
|
+
<page.Component />
|
|
94
|
+
) : null}
|
|
95
|
+
</main>
|
|
96
|
+
</div>
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
export default Layout;
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
No special PreactPress configuration is required beyond installing `@preact/signals`.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: RSS / Atom feed
|
|
3
|
+
description: Generate a static feed.xml for blogs, changelogs, and magazine-style sites.
|
|
4
|
+
tags:
|
|
5
|
+
- examples
|
|
6
|
+
- deploy
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
PreactPress can generate a static `feed.xml` during production builds. The feed uses the Atom XML format and is suitable for RSS readers.
|
|
10
|
+
|
|
11
|
+
## Enable the feed
|
|
12
|
+
|
|
13
|
+
Set `site.url` and enable `build.feed` in `.preactpress/config.ts`:
|
|
14
|
+
|
|
15
|
+
```ts [.preactpress/config.ts]
|
|
16
|
+
import { defineConfig } from "@kamod-ch/preactpress/config";
|
|
17
|
+
|
|
18
|
+
export default defineConfig({
|
|
19
|
+
site: {
|
|
20
|
+
title: "Acme Blog",
|
|
21
|
+
description: "Product updates and engineering notes",
|
|
22
|
+
url: "https://example.com",
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
build: {
|
|
26
|
+
feed: { limit: 20 },
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
After running a production build, PreactPress writes:
|
|
32
|
+
|
|
33
|
+
```txt
|
|
34
|
+
dist/feed.xml
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Add page metadata
|
|
38
|
+
|
|
39
|
+
Feed entries use each page's title, description, route, and `lastUpdated` value.
|
|
40
|
+
|
|
41
|
+
```md [posts/launch.md]
|
|
42
|
+
---
|
|
43
|
+
title: Launch notes
|
|
44
|
+
description: What shipped in our first public release.
|
|
45
|
+
lastUpdated: 2026-07-01T10:00:00.000Z
|
|
46
|
+
tags:
|
|
47
|
+
- changelog
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
We shipped the first public version today.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Build and inspect
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
pnpm run build
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Then open or publish:
|
|
60
|
+
|
|
61
|
+
```txt
|
|
62
|
+
https://example.com/feed.xml
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Link the feed from your HTML head
|
|
66
|
+
|
|
67
|
+
You can expose the feed to browsers and feed readers with `transformHead`:
|
|
68
|
+
|
|
69
|
+
```ts [.preactpress/config.ts]
|
|
70
|
+
import { defineConfig } from "@kamod-ch/preactpress/config";
|
|
71
|
+
|
|
72
|
+
export default defineConfig({
|
|
73
|
+
site: {
|
|
74
|
+
title: "Acme Blog",
|
|
75
|
+
description: "Product updates and engineering notes",
|
|
76
|
+
url: "https://example.com",
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
build: {
|
|
80
|
+
feed: { limit: 20 },
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
transformHead() {
|
|
84
|
+
return [
|
|
85
|
+
[
|
|
86
|
+
"link",
|
|
87
|
+
{
|
|
88
|
+
rel: "alternate",
|
|
89
|
+
type: "application/atom+xml",
|
|
90
|
+
title: "Acme Blog feed",
|
|
91
|
+
href: "/feed.xml",
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
];
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Notes
|
|
100
|
+
|
|
101
|
+
- Feed generation requires `site.url`.
|
|
102
|
+
- Draft pages are excluded from production output and therefore from the feed.
|
|
103
|
+
- `build.feed: true` includes all pages.
|
|
104
|
+
- `build.feed: { limit: 20 }` keeps only the newest entries.
|
|
@@ -36,4 +36,4 @@ export default Layout;
|
|
|
36
36
|
|
|
37
37
|
Theme authors are responsible for navigation, responsive behavior, focus management, search UI, and rendering Markdown versus MDX pages. Helpers for routes, page head data, tags, slugs, and theme state are exported from `@kamod-ch/preactpress/client` and `@kamod-ch/preactpress/shared`.
|
|
38
38
|
|
|
39
|
-
The `magazine` and `hono` init templates are complete custom-theme examples.
|
|
39
|
+
See the [custom theme example](/examples/custom-theme) for a copy-pasteable minimal theme. The `magazine` and `hono` init templates are complete custom-theme examples.
|
|
@@ -97,6 +97,8 @@ For most static hosts, use these settings:
|
|
|
97
97
|
| Cloudflare Pages | `pnpm run build` | `dist` |
|
|
98
98
|
| Render Static Site | `pnpm run build` | `dist` |
|
|
99
99
|
|
|
100
|
+
See the [Cloudflare Pages deployment guide](/examples/cloudflare-pages) for dashboard settings, environment variables, Wrangler deployment, and custom domain notes.
|
|
101
|
+
|
|
100
102
|
Install command:
|
|
101
103
|
|
|
102
104
|
```bash
|
|
@@ -7,7 +7,7 @@ Use `.md` for content that does not need browser-side components. Use `.mdx` whe
|
|
|
7
7
|
|
|
8
8
|
## Markdown
|
|
9
9
|
|
|
10
|
-
Markdown pages support frontmatter, heading anchors, syntax highlighting, tables, containers, GFM alerts, code groups, file includes, snippet imports, emoji, optional MathJax, and `[[toc]]`.
|
|
10
|
+
Markdown pages support frontmatter, heading anchors, syntax highlighting, Mermaid diagrams, tables, containers, GFM alerts, code groups, file includes, snippet imports, emoji, optional MathJax, and `[[toc]]`.
|
|
11
11
|
|
|
12
12
|
```md
|
|
13
13
|
---
|
|
@@ -23,6 +23,16 @@ export function greet(name: string) {
|
|
|
23
23
|
|
|
24
24
|
Inline code like `themeConfig.outline` uses the same theme tokens as code blocks.
|
|
25
25
|
|
|
26
|
+
## Mermaid diagrams
|
|
27
|
+
|
|
28
|
+
Use a `mermaid` fenced code block to render diagrams in Markdown and MDX pages:
|
|
29
|
+
|
|
30
|
+
```mermaid
|
|
31
|
+
graph TD
|
|
32
|
+
A[Markdown] --> B[PreactPress]
|
|
33
|
+
B --> C[Static HTML]
|
|
34
|
+
```
|
|
35
|
+
|
|
26
36
|
## Snippet import
|
|
27
37
|
|
|
28
38
|
Reuse source files instead of duplicating code:
|