@jsnchn/buntastic 0.1.0 → 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/AGENTS.md +6 -3
- package/README.md +24 -1
- package/package.json +1 -1
- package/src/index.ts +42 -19
- package/src/layouts/base.html +4 -2
- package/src/layouts/page.html +2 -0
- package/src/layouts/post.html +4 -1
package/AGENTS.md
CHANGED
|
@@ -85,22 +85,25 @@ The `{{ content | safe }}` placeholder is where child content gets injected.
|
|
|
85
85
|
|
|
86
86
|
## Head Block
|
|
87
87
|
|
|
88
|
-
Layouts can inject content into the `<head>` section using `
|
|
88
|
+
Layouts can inject content into the `<head>` section using `[head]...[/head]` blocks:
|
|
89
89
|
|
|
90
90
|
```html
|
|
91
91
|
<!-- layouts/post.html -->
|
|
92
92
|
---
|
|
93
93
|
extends: base.html
|
|
94
94
|
---
|
|
95
|
+
[head]
|
|
95
96
|
<link rel="stylesheet" href="/post.css">
|
|
96
|
-
|
|
97
|
+
[/head]
|
|
98
|
+
[content]
|
|
97
99
|
<article class="post">
|
|
98
100
|
<h1>{{ title }}</h1>
|
|
99
101
|
{{ content | safe }}
|
|
100
102
|
</article>
|
|
103
|
+
[/content]
|
|
101
104
|
```
|
|
102
105
|
|
|
103
|
-
|
|
106
|
+
Content inside `[head]` blocks is automatically placed in the parent's `<head>` section. Child layout head content is appended to parent head content.
|
|
104
107
|
|
|
105
108
|
## Development
|
|
106
109
|
|
package/README.md
CHANGED
|
@@ -164,11 +164,12 @@ extends: base.html
|
|
|
164
164
|
| Variable | Description |
|
|
165
165
|
|----------|-------------|
|
|
166
166
|
| `{{ title }}` | Page title |
|
|
167
|
-
| `{{ content
|
|
167
|
+
| `{{ content | safe }}` | Rendered markdown HTML |
|
|
168
168
|
| `{{ date }}` | Page date |
|
|
169
169
|
| `{{ description }}` | Meta description |
|
|
170
170
|
| `{{ url }}` | Current page URL |
|
|
171
171
|
| `{{ collection }}` | List of posts in current folder (for index pages) |
|
|
172
|
+
| `{{ head | safe }}` | Head content from child layouts (appended to parent) |
|
|
172
173
|
|
|
173
174
|
### Layout Inheritance
|
|
174
175
|
|
|
@@ -187,6 +188,28 @@ Use `extends:` to build on top of other layouts:
|
|
|
187
188
|
</html>
|
|
188
189
|
```
|
|
189
190
|
|
|
191
|
+
### Head Block
|
|
192
|
+
|
|
193
|
+
Layouts can inject content into the `<head>` section using `[head]...[/head]` blocks:
|
|
194
|
+
|
|
195
|
+
```html
|
|
196
|
+
<!-- layouts/post.html -->
|
|
197
|
+
---
|
|
198
|
+
extends: base.html
|
|
199
|
+
---
|
|
200
|
+
[head]
|
|
201
|
+
<link rel="stylesheet" href="/post.css">
|
|
202
|
+
[/head]
|
|
203
|
+
[content]
|
|
204
|
+
<article class="post">
|
|
205
|
+
<h1>{{ title }}</h1>
|
|
206
|
+
{{ content | safe }}
|
|
207
|
+
</article>
|
|
208
|
+
[/content]
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Content inside `[head]` blocks is automatically placed in the parent's `<head>` section. Child layout head content is appended to parent head content.
|
|
212
|
+
|
|
190
213
|
## Collections
|
|
191
214
|
|
|
192
215
|
For folder index pages (e.g., `content/posts/index.md`), use `{{ collection }}` to list all pages in that folder:
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -101,35 +101,58 @@ async function resolveLayout(frontmatter: Frontmatter): Promise<{ template: stri
|
|
|
101
101
|
const extendsMatch = template.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
102
102
|
|
|
103
103
|
let childHead = "";
|
|
104
|
-
let childBody =
|
|
104
|
+
let childBody = "";
|
|
105
105
|
|
|
106
106
|
if (extendsMatch) {
|
|
107
107
|
const parentLayout = extendsMatch[1].match(/extends:\s*(\w+)/);
|
|
108
108
|
if (parentLayout) {
|
|
109
|
-
|
|
110
|
-
const headPlaceholderMatch = childBody.match(/(\{\{\s*head\s*\|\s*safe\s*\}\})/);
|
|
109
|
+
const childContent = extendsMatch[2];
|
|
111
110
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
111
|
+
const headMatch = childContent.match(/\[head\]([\s\S]*?)\[\/head\]/);
|
|
112
|
+
if (headMatch) {
|
|
113
|
+
childHead = headMatch[1].trim();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const bodyMatch = childContent.match(/\[content\]([\s\S]*?)\[\/content\]/);
|
|
117
|
+
if (bodyMatch) {
|
|
118
|
+
childBody = bodyMatch[1];
|
|
119
|
+
} else {
|
|
120
|
+
childBody = childContent;
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
const parentResult = await resolveLayout({ extends: parentLayout[1] } as Frontmatter);
|
|
121
124
|
|
|
122
|
-
let contentReplaced = parentResult.template
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
let contentReplaced = parentResult.template;
|
|
126
|
+
|
|
127
|
+
if (bodyMatch) {
|
|
128
|
+
contentReplaced = contentReplaced.replace(
|
|
129
|
+
/\[content\]([\s\S]*?)\[\/content\]/g,
|
|
130
|
+
childBody
|
|
131
|
+
);
|
|
132
|
+
} else {
|
|
133
|
+
contentReplaced = contentReplaced.replace(
|
|
134
|
+
/\{\{\s*content\s*\|\s*safe\s*\}\}/g,
|
|
135
|
+
childBody
|
|
136
|
+
);
|
|
137
|
+
}
|
|
126
138
|
|
|
127
139
|
const mergedHead = parentResult.head + (childHead ? "\n" + childHead : "");
|
|
128
140
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
141
|
+
if (headMatch) {
|
|
142
|
+
contentReplaced = contentReplaced.replace(
|
|
143
|
+
/\[head\]([\s\S]*?)\[\/head\]/g,
|
|
144
|
+
mergedHead
|
|
145
|
+
);
|
|
146
|
+
} else {
|
|
147
|
+
contentReplaced = contentReplaced.replace(
|
|
148
|
+
/\[head\]([\s\S]*?)\[\/head\]/g,
|
|
149
|
+
mergedHead
|
|
150
|
+
);
|
|
151
|
+
contentReplaced = contentReplaced.replace(
|
|
152
|
+
/\{\{\s*head\s*\|\s*safe\s*\}\}/g,
|
|
153
|
+
mergedHead
|
|
154
|
+
);
|
|
155
|
+
}
|
|
133
156
|
|
|
134
157
|
return { template: contentReplaced, head: mergedHead };
|
|
135
158
|
}
|
|
@@ -138,8 +161,8 @@ async function resolveLayout(frontmatter: Frontmatter): Promise<{ template: stri
|
|
|
138
161
|
let ownHead = "";
|
|
139
162
|
if (extendsMatch) {
|
|
140
163
|
const bodyMatch = extendsMatch[2];
|
|
141
|
-
const headMatch = bodyMatch.match(/\
|
|
142
|
-
ownHead = headMatch ? headMatch[
|
|
164
|
+
const headMatch = bodyMatch.match(/\[head\]([\s\S]*?)\[\/head\]/);
|
|
165
|
+
ownHead = headMatch ? headMatch[1].trim() : "";
|
|
143
166
|
}
|
|
144
167
|
|
|
145
168
|
return { template, head: ownHead };
|
package/src/layouts/base.html
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
<title>{{ title }}</title>
|
|
7
7
|
<meta name="description" content="{{ description }}">
|
|
8
8
|
<link rel="stylesheet" href="/style.css">
|
|
9
|
-
|
|
9
|
+
[head]
|
|
10
|
+
[/head]
|
|
10
11
|
</head>
|
|
11
12
|
<body>
|
|
12
13
|
<header>
|
|
@@ -17,7 +18,8 @@
|
|
|
17
18
|
</nav>
|
|
18
19
|
</header>
|
|
19
20
|
<main>
|
|
20
|
-
|
|
21
|
+
[content]
|
|
22
|
+
[/content]
|
|
21
23
|
</main>
|
|
22
24
|
<footer>
|
|
23
25
|
<p>Built with BunPress</p>
|
package/src/layouts/page.html
CHANGED
package/src/layouts/post.html
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
extends: base.html
|
|
3
3
|
---
|
|
4
|
+
[head]
|
|
4
5
|
<link rel="stylesheet" href="/post.css">
|
|
5
|
-
|
|
6
|
+
[/head]
|
|
7
|
+
[content]
|
|
6
8
|
<article class="post">
|
|
7
9
|
<header>
|
|
8
10
|
<h1>{{ title }}</h1>
|
|
@@ -12,3 +14,4 @@ extends: base.html
|
|
|
12
14
|
{{ content | safe }}
|
|
13
15
|
</div>
|
|
14
16
|
</article>
|
|
17
|
+
[/content]
|