@anydigital/eleventy-bricks 1.0.0-alpha.16 → 1.0.0-alpha.18
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/README.md +449 -175
- package/package.json +1 -1
- package/src/do/package.json +4 -9
- package/src/eleventy.config.js +29 -21
- package/src/{setAttrFilter.js → filters/attr.js} +5 -6
- package/src/filters/attr_concat.js +65 -0
- package/src/filters/attr_concat.test.js +205 -0
- package/src/filters/if.js +39 -0
- package/src/filters/if.test.js +63 -0
- package/src/filters/merge.js +47 -0
- package/src/filters/merge.test.js +51 -0
- package/src/filters/remove_tag.js +42 -0
- package/src/filters/remove_tag.test.js +60 -0
- package/src/filters/where_in.js +49 -0
- package/src/filters/where_in.test.js +148 -0
- package/src/index.cjs +5 -5
- package/src/index.js +59 -15
- package/src/siteData.js +3 -3
- package/src/bricks.js +0 -125
- package/src/byAttrFilter.js +0 -35
- package/src/byAttrFilter.test.js +0 -105
package/README.md
CHANGED
|
@@ -17,27 +17,35 @@ You can use this library in two ways:
|
|
|
17
17
|
Import and use the entire plugin. You can configure which helpers to enable using the options parameter:
|
|
18
18
|
|
|
19
19
|
**ES Modules:**
|
|
20
|
+
|
|
20
21
|
```javascript
|
|
21
22
|
import eleventyBricks from "@anydigital/eleventy-bricks";
|
|
22
23
|
|
|
23
|
-
export default function(eleventyConfig) {
|
|
24
|
+
export default function (eleventyConfig) {
|
|
24
25
|
eleventyConfig.addPlugin(eleventyBricks, {
|
|
25
|
-
mdAutoRawTags: true
|
|
26
|
+
mdAutoRawTags: true,
|
|
27
|
+
mdAutoNl2br: true,
|
|
28
|
+
siteData: true,
|
|
29
|
+
filters: ["attr", "where_in", "merge", "remove_tag", "if", "attr_concat"],
|
|
26
30
|
});
|
|
27
|
-
|
|
31
|
+
|
|
28
32
|
// Your other configuration...
|
|
29
33
|
}
|
|
30
34
|
```
|
|
31
35
|
|
|
32
36
|
**CommonJS:**
|
|
37
|
+
|
|
33
38
|
```javascript
|
|
34
39
|
const eleventyBricks = require("@anydigital/eleventy-bricks");
|
|
35
40
|
|
|
36
|
-
module.exports = function(eleventyConfig) {
|
|
41
|
+
module.exports = function (eleventyConfig) {
|
|
37
42
|
eleventyConfig.addPlugin(eleventyBricks, {
|
|
38
|
-
mdAutoRawTags: true
|
|
43
|
+
mdAutoRawTags: true,
|
|
44
|
+
mdAutoNl2br: true,
|
|
45
|
+
siteData: true,
|
|
46
|
+
filters: ["attr", "where_in", "merge", "remove_tag", "if", "attr_concat"],
|
|
39
47
|
});
|
|
40
|
-
|
|
48
|
+
|
|
41
49
|
// Your other configuration...
|
|
42
50
|
};
|
|
43
51
|
```
|
|
@@ -49,33 +57,61 @@ module.exports = function(eleventyConfig) {
|
|
|
49
57
|
Import only the specific helpers you need without using the plugin:
|
|
50
58
|
|
|
51
59
|
**ES Modules:**
|
|
52
|
-
```javascript
|
|
53
|
-
import { bricks, mdAutoRawTags, mdAutoNl2br, setAttrFilter, byAttrFilter, siteData } from "@anydigital/eleventy-bricks";
|
|
54
60
|
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
```javascript
|
|
62
|
+
import {
|
|
63
|
+
mdAutoRawTags,
|
|
64
|
+
mdAutoNl2br,
|
|
65
|
+
setAttrFilter,
|
|
66
|
+
whereInFilter,
|
|
67
|
+
mergeFilter,
|
|
68
|
+
removeTagFilter,
|
|
69
|
+
ifFilter,
|
|
70
|
+
attrConcatFilter,
|
|
71
|
+
siteData,
|
|
72
|
+
} from "@anydigital/eleventy-bricks";
|
|
73
|
+
|
|
74
|
+
export default function (eleventyConfig) {
|
|
57
75
|
mdAutoRawTags(eleventyConfig);
|
|
58
76
|
mdAutoNl2br(eleventyConfig);
|
|
59
77
|
setAttrFilter(eleventyConfig);
|
|
60
|
-
|
|
78
|
+
whereInFilter(eleventyConfig);
|
|
79
|
+
mergeFilter(eleventyConfig);
|
|
80
|
+
removeTagFilter(eleventyConfig);
|
|
81
|
+
ifFilter(eleventyConfig);
|
|
82
|
+
attrConcatFilter(eleventyConfig);
|
|
61
83
|
siteData(eleventyConfig);
|
|
62
|
-
|
|
84
|
+
|
|
63
85
|
// Your other configuration...
|
|
64
86
|
}
|
|
65
87
|
```
|
|
66
88
|
|
|
67
89
|
**CommonJS:**
|
|
68
|
-
```javascript
|
|
69
|
-
const { bricks, mdAutoRawTags, mdAutoNl2br, setAttrFilter, byAttrFilter, siteData } = require("@anydigital/eleventy-bricks");
|
|
70
90
|
|
|
71
|
-
|
|
72
|
-
|
|
91
|
+
```javascript
|
|
92
|
+
const {
|
|
93
|
+
mdAutoRawTags,
|
|
94
|
+
mdAutoNl2br,
|
|
95
|
+
setAttrFilter,
|
|
96
|
+
whereInFilter,
|
|
97
|
+
mergeFilter,
|
|
98
|
+
removeTagFilter,
|
|
99
|
+
ifFilter,
|
|
100
|
+
attrConcatFilter,
|
|
101
|
+
siteData,
|
|
102
|
+
} = require("@anydigital/eleventy-bricks");
|
|
103
|
+
|
|
104
|
+
module.exports = async function (eleventyConfig) {
|
|
73
105
|
await mdAutoRawTags(eleventyConfig);
|
|
74
106
|
await mdAutoNl2br(eleventyConfig);
|
|
75
107
|
await setAttrFilter(eleventyConfig);
|
|
76
|
-
await
|
|
108
|
+
await whereInFilter(eleventyConfig);
|
|
109
|
+
await mergeFilter(eleventyConfig);
|
|
110
|
+
await removeTagFilter(eleventyConfig);
|
|
111
|
+
await ifFilter(eleventyConfig);
|
|
112
|
+
await attrConcatFilter(eleventyConfig);
|
|
77
113
|
await siteData(eleventyConfig);
|
|
78
|
-
|
|
114
|
+
|
|
79
115
|
// Your other configuration...
|
|
80
116
|
};
|
|
81
117
|
```
|
|
@@ -86,132 +122,35 @@ module.exports = async function(eleventyConfig) {
|
|
|
86
122
|
|
|
87
123
|
When using the plugin (Option 1), you can configure which helpers to enable:
|
|
88
124
|
|
|
89
|
-
| Option
|
|
90
|
-
|
|
91
|
-
| `
|
|
92
|
-
| `
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
95
|
-
|
|
96
|
-
|
|
125
|
+
| Option | Type | Default | Description |
|
|
126
|
+
| --------------- | --------------- | ------- | ---------------------------------------------------------------- |
|
|
127
|
+
| `mdAutoRawTags` | boolean | `false` | Enable the mdAutoRawTags preprocessor for Markdown files |
|
|
128
|
+
| `mdAutoNl2br` | boolean | `false` | Enable the mdAutoNl2br preprocessor to convert \n to `<br>` tags |
|
|
129
|
+
| `siteData` | boolean | `false` | Enable site.year and site.prod global data |
|
|
130
|
+
| `filters` | array of string | `[]` | Array of filter names to enable (see Available Filters section) |
|
|
131
|
+
|
|
132
|
+
**Available filter names for the `filters` array:**
|
|
133
|
+
|
|
134
|
+
- `'attr'` - Override object attributes
|
|
135
|
+
- `'where_in'` - Filter collections by attribute values
|
|
136
|
+
- `'merge'` - Merge arrays or objects
|
|
137
|
+
- `'remove_tag'` - Remove HTML elements from content
|
|
138
|
+
- `'if'` - Inline conditional/ternary operator
|
|
139
|
+
- `'attr_concat'` - Concatenate values to an attribute array
|
|
97
140
|
|
|
98
141
|
**Example:**
|
|
142
|
+
|
|
99
143
|
```javascript
|
|
100
144
|
eleventyConfig.addPlugin(eleventyBricks, {
|
|
101
|
-
bricks: true,
|
|
102
145
|
mdAutoRawTags: true,
|
|
103
|
-
|
|
104
|
-
siteData: true
|
|
146
|
+
mdAutoNl2br: true,
|
|
147
|
+
siteData: true,
|
|
148
|
+
filters: ["attr", "where_in", "merge", "remove_tag", "if", "attr_concat"],
|
|
105
149
|
});
|
|
106
150
|
```
|
|
107
151
|
|
|
108
152
|
## Available 11ty Helpers
|
|
109
153
|
|
|
110
|
-
### bricks
|
|
111
|
-
|
|
112
|
-
A dependency management system for Eleventy that automatically collects and injects CSS and JavaScript dependencies (both external and inline) per page. This allows brick components to declare their dependencies, and the system will inject them in the correct location in your HTML.
|
|
113
|
-
|
|
114
|
-
**Why use this?**
|
|
115
|
-
|
|
116
|
-
When building reusable components (bricks) in Eleventy, you often need to include CSS and JavaScript dependencies. Instead of manually adding these to every page, `bricks` automatically:
|
|
117
|
-
- Collects dependencies from all bricks used on a page
|
|
118
|
-
- Categorizes them (external CSS, external JS, inline styles, inline scripts)
|
|
119
|
-
- Injects them in the correct location in your HTML output
|
|
120
|
-
|
|
121
|
-
**How it works:**
|
|
122
|
-
|
|
123
|
-
1. Use the `bricksDependencies` shortcode in your base template to mark where dependencies should be injected
|
|
124
|
-
2. Use the `brick` shortcode to register and render brick components that declare their dependencies
|
|
125
|
-
3. The system automatically collects all dependencies and injects them when the page is built
|
|
126
|
-
|
|
127
|
-
**Usage:**
|
|
128
|
-
|
|
129
|
-
1. Enable `bricks` in your Eleventy config:
|
|
130
|
-
|
|
131
|
-
```javascript
|
|
132
|
-
import { bricks } from "@anydigital/eleventy-bricks";
|
|
133
|
-
|
|
134
|
-
export default function(eleventyConfig) {
|
|
135
|
-
bricks(eleventyConfig);
|
|
136
|
-
// Or use as plugin:
|
|
137
|
-
// eleventyConfig.addPlugin(eleventyBricks, { bricks: true });
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
2. Add the `bricksDependencies` shortcode in your base template (typically in the `<head>` section):
|
|
142
|
-
|
|
143
|
-
```njk
|
|
144
|
-
<head>
|
|
145
|
-
<meta charset="UTF-8">
|
|
146
|
-
<title>My Site</title>
|
|
147
|
-
{% bricksDependencies [
|
|
148
|
-
... (global dependencies can be set here) ...
|
|
149
|
-
] %}
|
|
150
|
-
<!-- Other head content -->
|
|
151
|
-
</head>
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
3. Create brick components that declare their dependencies:
|
|
155
|
-
|
|
156
|
-
```javascript
|
|
157
|
-
// myBrick.js
|
|
158
|
-
export default {
|
|
159
|
-
dependencies: [
|
|
160
|
-
'https://cdn.example.com/library.css',
|
|
161
|
-
'https://cdn.example.com/library.js'
|
|
162
|
-
],
|
|
163
|
-
style: `
|
|
164
|
-
.my-component { color: blue; }
|
|
165
|
-
`,
|
|
166
|
-
script: `
|
|
167
|
-
console.log('Component initialized');
|
|
168
|
-
`,
|
|
169
|
-
render: function() {
|
|
170
|
-
return '<div class="my-component">Hello World</div>';
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
4. Use the `brick` shortcode in your templates:
|
|
176
|
-
|
|
177
|
-
```njk
|
|
178
|
-
{% set myBrick = require('./myBrick.js') %}
|
|
179
|
-
{% brick myBrick %}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
**Brick Component Structure:**
|
|
183
|
-
|
|
184
|
-
A brick component is a JavaScript object with the following optional properties:
|
|
185
|
-
|
|
186
|
-
- `dependencies`: Array of URLs to external CSS or JavaScript files (e.g., `['https://cdn.example.com/style.css', 'https://cdn.example.com/script.js']`)
|
|
187
|
-
- `style`: String containing inline CSS
|
|
188
|
-
- `script`: String containing inline JavaScript
|
|
189
|
-
- `render`: Function that returns the HTML markup for the component
|
|
190
|
-
|
|
191
|
-
**Output:**
|
|
192
|
-
|
|
193
|
-
The system will automatically inject all dependencies in the order they were registered:
|
|
194
|
-
|
|
195
|
-
```html
|
|
196
|
-
<head>
|
|
197
|
-
<meta charset="UTF-8">
|
|
198
|
-
<title>My Site</title>
|
|
199
|
-
<link rel="stylesheet" href="https://cdn.example.com/library.css">
|
|
200
|
-
<style>.my-component { color: blue; }</style>
|
|
201
|
-
<script src="https://cdn.example.com/library.js"></script>
|
|
202
|
-
<script>console.log('Component initialized');</script>
|
|
203
|
-
<!-- Other head content -->
|
|
204
|
-
</head>
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
**Features:**
|
|
208
|
-
|
|
209
|
-
- Automatic dependency collection per page
|
|
210
|
-
- Categorizes dependencies (CSS vs JS, external vs inline)
|
|
211
|
-
- Deduplicates dependencies (using Sets internally)
|
|
212
|
-
- Works with both external URLs and inline code
|
|
213
|
-
- Clears registry before each build to prevent stale data
|
|
214
|
-
|
|
215
154
|
### mdAutoRawTags
|
|
216
155
|
|
|
217
156
|
Prevents Nunjucks syntax from being processed in Markdown files by automatically wrapping `{{`, `}}`, `{%`, and `%}` with `{% raw %}` tags.
|
|
@@ -227,7 +166,7 @@ When writing documentation or tutorials about templating in Markdown files, you
|
|
|
227
166
|
```javascript
|
|
228
167
|
import { mdAutoRawTags } from "@anydigital/eleventy-bricks";
|
|
229
168
|
|
|
230
|
-
export default function(eleventyConfig) {
|
|
169
|
+
export default function (eleventyConfig) {
|
|
231
170
|
mdAutoRawTags(eleventyConfig);
|
|
232
171
|
// Or use as plugin:
|
|
233
172
|
// eleventyConfig.addPlugin(eleventyBricks, { mdAutoRawTags: true });
|
|
@@ -237,6 +176,7 @@ export default function(eleventyConfig) {
|
|
|
237
176
|
**Example:**
|
|
238
177
|
|
|
239
178
|
Before `mdAutoRawTags`, writing this in Markdown:
|
|
179
|
+
|
|
240
180
|
```markdown
|
|
241
181
|
Use {{ variable }} to output variables.
|
|
242
182
|
```
|
|
@@ -258,7 +198,7 @@ Markdown tables don't support multi-line content in cells. By using `\n` in your
|
|
|
258
198
|
```javascript
|
|
259
199
|
import { mdAutoNl2br } from "@anydigital/eleventy-bricks";
|
|
260
200
|
|
|
261
|
-
export default function(eleventyConfig) {
|
|
201
|
+
export default function (eleventyConfig) {
|
|
262
202
|
mdAutoNl2br(eleventyConfig);
|
|
263
203
|
// Or use as plugin:
|
|
264
204
|
// eleventyConfig.addPlugin(eleventyBricks, { mdAutoNl2br: true });
|
|
@@ -268,39 +208,41 @@ export default function(eleventyConfig) {
|
|
|
268
208
|
**Example:**
|
|
269
209
|
|
|
270
210
|
In your Markdown file:
|
|
211
|
+
|
|
271
212
|
```markdown
|
|
272
|
-
| Column 1
|
|
273
|
-
|
|
213
|
+
| Column 1 | Column 2 |
|
|
214
|
+
| ---------------------- | --------------------------------- |
|
|
274
215
|
| Line 1\nLine 2\nLine 3 | Another cell\nWith multiple lines |
|
|
275
216
|
```
|
|
276
217
|
|
|
277
218
|
Will render as:
|
|
219
|
+
|
|
278
220
|
```html
|
|
279
|
-
<td>Line 1<br
|
|
280
|
-
<td>Another cell<br
|
|
221
|
+
<td>Line 1<br />Line 2<br />Line 3</td>
|
|
222
|
+
<td>Another cell<br />With multiple lines</td>
|
|
281
223
|
```
|
|
282
224
|
|
|
283
225
|
**Note:** This processes literal `\n` sequences (backslash followed by 'n'), not actual newline characters. Type `\n` in your source files where you want line breaks.
|
|
284
226
|
|
|
285
|
-
###
|
|
227
|
+
### attr
|
|
286
228
|
|
|
287
229
|
A filter that creates a new object with an overridden attribute value. This is useful for modifying data objects in templates without mutating the original.
|
|
288
230
|
|
|
289
231
|
**Why use this?**
|
|
290
232
|
|
|
291
|
-
When working with Eleventy data, you sometimes need to modify an object's properties for a specific use case. The `
|
|
233
|
+
When working with Eleventy data, you sometimes need to modify an object's properties for a specific use case. The `attr` filter provides a clean way to create a modified copy of an object without affecting the original.
|
|
292
234
|
|
|
293
235
|
**Usage:**
|
|
294
236
|
|
|
295
|
-
1. Enable `
|
|
237
|
+
1. Enable the `attr` filter in your Eleventy config:
|
|
296
238
|
|
|
297
239
|
```javascript
|
|
298
240
|
import { setAttrFilter } from "@anydigital/eleventy-bricks";
|
|
299
241
|
|
|
300
|
-
export default function(eleventyConfig) {
|
|
242
|
+
export default function (eleventyConfig) {
|
|
301
243
|
setAttrFilter(eleventyConfig);
|
|
302
244
|
// Or use as plugin:
|
|
303
|
-
// eleventyConfig.addPlugin(eleventyBricks, {
|
|
245
|
+
// eleventyConfig.addPlugin(eleventyBricks, { filters: ['attr'] });
|
|
304
246
|
}
|
|
305
247
|
```
|
|
306
248
|
|
|
@@ -308,7 +250,7 @@ export default function(eleventyConfig) {
|
|
|
308
250
|
|
|
309
251
|
```njk
|
|
310
252
|
{# Create a modified version of a page object #}
|
|
311
|
-
{% set modifiedPage = page |
|
|
253
|
+
{% set modifiedPage = page | attr('title', 'New Title') %}
|
|
312
254
|
|
|
313
255
|
<h1>{{ modifiedPage.title }}</h1>
|
|
314
256
|
<p>Original title: {{ page.title }}</p>
|
|
@@ -335,49 +277,50 @@ A new object with the specified attribute set to the given value. The original o
|
|
|
335
277
|
|
|
336
278
|
```njk
|
|
337
279
|
{# Override a single attribute #}
|
|
338
|
-
{% set updatedPost = post |
|
|
280
|
+
{% set updatedPost = post | attr('featured', true) %}
|
|
339
281
|
|
|
340
|
-
{# Chain multiple
|
|
341
|
-
{% set modifiedPost = post
|
|
342
|
-
|
|
|
343
|
-
|
|
|
282
|
+
{# Chain multiple attr filters #}
|
|
283
|
+
{% set modifiedPost = post
|
|
284
|
+
| attr('category', 'blog')
|
|
285
|
+
| attr('priority', 1)
|
|
344
286
|
%}
|
|
345
287
|
|
|
346
288
|
{# Use in loops #}
|
|
347
289
|
{% for item in collection %}
|
|
348
|
-
{% set enhancedItem = item |
|
|
290
|
+
{% set enhancedItem = item | attr('processed', true) %}
|
|
349
291
|
{# ... use enhancedItem ... #}
|
|
350
292
|
{% endfor %}
|
|
351
293
|
```
|
|
352
294
|
|
|
353
|
-
###
|
|
295
|
+
### where_in
|
|
354
296
|
|
|
355
|
-
A filter that filters collection items by attribute value. It checks if an item's attribute matches a target value. If the attribute is an array, it checks if the array includes the target value.
|
|
297
|
+
A filter that filters collection items by attribute value. It checks if an item's attribute matches a target value. If the attribute is an array, it checks if the array includes the target value. Supports nested attribute names using dot notation.
|
|
356
298
|
|
|
357
299
|
**Why use this?**
|
|
358
300
|
|
|
359
|
-
When working with Eleventy collections, you often need to filter items based on front matter data. The `
|
|
301
|
+
When working with Eleventy collections, you often need to filter items based on front matter data. The `where_in` filter provides a flexible way to filter by any attribute, with special handling for array attributes (like tags) and support for nested properties using dot notation.
|
|
360
302
|
|
|
361
303
|
**Usage:**
|
|
362
304
|
|
|
363
|
-
1. Enable `
|
|
305
|
+
1. Enable the `where_in` filter in your Eleventy config:
|
|
364
306
|
|
|
365
307
|
```javascript
|
|
366
|
-
import {
|
|
308
|
+
import { whereInFilter } from "@anydigital/eleventy-bricks";
|
|
367
309
|
|
|
368
|
-
export default function(eleventyConfig) {
|
|
369
|
-
|
|
310
|
+
export default function (eleventyConfig) {
|
|
311
|
+
whereInFilter(eleventyConfig);
|
|
370
312
|
// Or use as plugin:
|
|
371
|
-
// eleventyConfig.addPlugin(eleventyBricks, {
|
|
313
|
+
// eleventyConfig.addPlugin(eleventyBricks, { filters: ['where_in'] });
|
|
372
314
|
}
|
|
373
315
|
```
|
|
374
316
|
|
|
375
317
|
2. Use the filter in your templates:
|
|
376
318
|
|
|
377
319
|
**Filter by exact attribute match:**
|
|
320
|
+
|
|
378
321
|
```njk
|
|
379
322
|
{# Get all posts with category 'blog' #}
|
|
380
|
-
{% set blogPosts = collections.all |
|
|
323
|
+
{% set blogPosts = collections.all | where_in('data.category', 'blog') %}
|
|
381
324
|
|
|
382
325
|
{% for post in blogPosts %}
|
|
383
326
|
<h2>{{ post.data.title }}</h2>
|
|
@@ -385,9 +328,10 @@ export default function(eleventyConfig) {
|
|
|
385
328
|
```
|
|
386
329
|
|
|
387
330
|
**Filter by array attribute (tags):**
|
|
331
|
+
|
|
388
332
|
```njk
|
|
389
333
|
{# Get all posts that include 'javascript' tag #}
|
|
390
|
-
{% set jsPosts = collections.all |
|
|
334
|
+
{% set jsPosts = collections.all | where_in('data.tags', 'javascript') %}
|
|
391
335
|
|
|
392
336
|
{% for post in jsPosts %}
|
|
393
337
|
<h2>{{ post.data.title }}</h2>
|
|
@@ -397,13 +341,13 @@ export default function(eleventyConfig) {
|
|
|
397
341
|
**Parameters:**
|
|
398
342
|
|
|
399
343
|
- `collection`: The collection to filter (array of items)
|
|
400
|
-
- `attrName`: The attribute name to check (string)
|
|
344
|
+
- `attrName`: The attribute name to check (string, supports dot notation for nested properties)
|
|
401
345
|
- `targetValue`: The value to match against (any type)
|
|
402
346
|
|
|
403
347
|
**Features:**
|
|
404
348
|
|
|
405
349
|
- Works with any attribute in front matter
|
|
406
|
-
-
|
|
350
|
+
- Supports dot notation for nested properties (e.g., `'data.tags'`, `'data.author.name'`)
|
|
407
351
|
- Special handling for array attributes (uses `includes()` check)
|
|
408
352
|
- Returns empty array if collection is invalid
|
|
409
353
|
- Filters out items without the specified attribute
|
|
@@ -411,6 +355,7 @@ export default function(eleventyConfig) {
|
|
|
411
355
|
**Examples:**
|
|
412
356
|
|
|
413
357
|
Front matter:
|
|
358
|
+
|
|
414
359
|
```yaml
|
|
415
360
|
---
|
|
416
361
|
title: My Post
|
|
@@ -421,18 +366,337 @@ priority: 1
|
|
|
421
366
|
```
|
|
422
367
|
|
|
423
368
|
Template usage:
|
|
369
|
+
|
|
424
370
|
```njk
|
|
425
|
-
{# Filter by category #}
|
|
426
|
-
{% set blogPosts = collections.all |
|
|
371
|
+
{# Filter by category (using dot notation for nested properties) #}
|
|
372
|
+
{% set blogPosts = collections.all | where_in('data.category', 'blog') %}
|
|
427
373
|
|
|
428
374
|
{# Filter by tag (array) #}
|
|
429
|
-
{% set jsTutorials = collections.all |
|
|
375
|
+
{% set jsTutorials = collections.all | where_in('data.tags', 'javascript') %}
|
|
430
376
|
|
|
431
377
|
{# Filter by numeric value #}
|
|
432
|
-
{% set highPriority = collections.all |
|
|
378
|
+
{% set highPriority = collections.all | where_in('data.priority', 1) %}
|
|
433
379
|
|
|
434
380
|
{# Chain filters #}
|
|
435
|
-
{% set recentBlogPosts = collections.all |
|
|
381
|
+
{% set recentBlogPosts = collections.all | where_in('data.category', 'blog') | reverse | limit(5) %}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### merge
|
|
385
|
+
|
|
386
|
+
A filter that merges arrays or objects together, similar to Twig's merge filter. For arrays, it concatenates them. For objects, it performs a shallow merge where later values override earlier ones.
|
|
387
|
+
|
|
388
|
+
**Why use this?**
|
|
389
|
+
|
|
390
|
+
When working with data in templates, you often need to combine multiple arrays or objects. The `merge` filter provides a clean way to merge data structures without writing custom JavaScript, making it easy to combine collections, merge configuration objects, or aggregate data from multiple sources.
|
|
391
|
+
|
|
392
|
+
**Usage:**
|
|
393
|
+
|
|
394
|
+
1. Enable the `merge` filter in your Eleventy config:
|
|
395
|
+
|
|
396
|
+
```javascript
|
|
397
|
+
import { mergeFilter } from "@anydigital/eleventy-bricks";
|
|
398
|
+
|
|
399
|
+
export default function (eleventyConfig) {
|
|
400
|
+
mergeFilter(eleventyConfig);
|
|
401
|
+
// Or use as plugin:
|
|
402
|
+
// eleventyConfig.addPlugin(eleventyBricks, { filters: ['merge'] });
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
2. Use the filter in your templates:
|
|
407
|
+
|
|
408
|
+
**Merge arrays:**
|
|
409
|
+
|
|
410
|
+
```njk
|
|
411
|
+
{# Combine two arrays #}
|
|
412
|
+
{% set allItems = featured | merge(regular) %}
|
|
413
|
+
|
|
414
|
+
{# Merge multiple arrays #}
|
|
415
|
+
{% set combined = array1 | merge(array2, array3, array4) %}
|
|
416
|
+
|
|
417
|
+
{% for item in allItems %}
|
|
418
|
+
<p>{{ item }}</p>
|
|
419
|
+
{% endfor %}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
**Merge objects:**
|
|
423
|
+
|
|
424
|
+
```njk
|
|
425
|
+
{# Merge configuration objects #}
|
|
426
|
+
{% set defaultConfig = { theme: 'light', lang: 'en' } %}
|
|
427
|
+
{% set userConfig = { theme: 'dark' } %}
|
|
428
|
+
{% set finalConfig = defaultConfig | merge(userConfig) %}
|
|
429
|
+
|
|
430
|
+
{# Result: { theme: 'dark', lang: 'en' } #}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
**Parameters:**
|
|
434
|
+
|
|
435
|
+
- `first`: The first array or object (the base to merge into)
|
|
436
|
+
- `...rest`: One or more arrays or objects to merge in
|
|
437
|
+
|
|
438
|
+
**Features:**
|
|
439
|
+
|
|
440
|
+
- Works with both arrays and objects
|
|
441
|
+
- Supports merging multiple items at once
|
|
442
|
+
- Non-mutating: Creates new arrays/objects, leaving originals unchanged
|
|
443
|
+
- For objects: Later values override earlier ones (shallow merge)
|
|
444
|
+
- For arrays: Concatenates all arrays together
|
|
445
|
+
- Handles null/undefined gracefully
|
|
446
|
+
|
|
447
|
+
**Examples:**
|
|
448
|
+
|
|
449
|
+
```njk
|
|
450
|
+
{# Combine featured and regular posts #}
|
|
451
|
+
{% set featuredPosts = collections.all | where_in('data.featured', true) %}
|
|
452
|
+
{% set regularPosts = collections.all | where_in('data.featured', false) %}
|
|
453
|
+
{% set allPosts = featuredPosts | merge(regularPosts) %}
|
|
454
|
+
|
|
455
|
+
{# Merge page metadata with defaults #}
|
|
456
|
+
{% set defaultMeta = {
|
|
457
|
+
author: 'Site Admin',
|
|
458
|
+
category: 'general',
|
|
459
|
+
comments: false
|
|
460
|
+
} %}
|
|
461
|
+
{% set pageMeta = defaultMeta | merge(page.data) %}
|
|
462
|
+
|
|
463
|
+
{# Combine arrays of tags #}
|
|
464
|
+
{% set commonTags = ['javascript', 'html', 'css'] %}
|
|
465
|
+
{% set specialTags = page.data.tags or [] %}
|
|
466
|
+
{% set allTags = commonTags | merge(specialTags) %}
|
|
467
|
+
|
|
468
|
+
{# Merge multiple configuration sources #}
|
|
469
|
+
{% set config = defaults | merge(siteConfig, pageConfig, userPrefs) %}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### remove_tag
|
|
473
|
+
|
|
474
|
+
A filter that removes a specified HTML element from provided HTML content. It removes the tag along with its content, including self-closing tags.
|
|
475
|
+
|
|
476
|
+
**Why use this?**
|
|
477
|
+
|
|
478
|
+
When working with content from external sources or user-generated content, you may need to strip certain HTML tags for security or presentation purposes. The `remove_tag` filter provides a simple way to remove unwanted tags like `<script>`, `<style>`, or any other HTML elements from your content.
|
|
479
|
+
|
|
480
|
+
**Usage:**
|
|
481
|
+
|
|
482
|
+
1. Enable the `remove_tag` filter in your Eleventy config:
|
|
483
|
+
|
|
484
|
+
```javascript
|
|
485
|
+
import { removeTagFilter } from "@anydigital/eleventy-bricks";
|
|
486
|
+
|
|
487
|
+
export default function (eleventyConfig) {
|
|
488
|
+
removeTagFilter(eleventyConfig);
|
|
489
|
+
// Or use as plugin:
|
|
490
|
+
// eleventyConfig.addPlugin(eleventyBricks, { filters: ['remove_tag'] });
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
2. Use the filter in your templates:
|
|
495
|
+
|
|
496
|
+
```njk
|
|
497
|
+
{# Remove all script tags from content #}
|
|
498
|
+
{% set cleanContent = htmlContent | remove_tag('script') %}
|
|
499
|
+
|
|
500
|
+
{{ cleanContent | safe }}
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
**Parameters:**
|
|
504
|
+
|
|
505
|
+
- `html`: The HTML content to process (string)
|
|
506
|
+
- `tagName`: The tag name to remove (string)
|
|
507
|
+
|
|
508
|
+
**Features:**
|
|
509
|
+
|
|
510
|
+
- Removes both opening and closing tags along with their content
|
|
511
|
+
- Handles self-closing tags (e.g., `<br />`, `<img />`)
|
|
512
|
+
- Handles tags with attributes
|
|
513
|
+
- Case-insensitive matching
|
|
514
|
+
- Non-destructive: Returns new string, doesn't modify original
|
|
515
|
+
|
|
516
|
+
**Examples:**
|
|
517
|
+
|
|
518
|
+
```njk
|
|
519
|
+
{# Remove scripts from user-generated content #}
|
|
520
|
+
{% set userContent = '<p>Hello</p><script>alert("XSS")</script><p>World</p>' %}
|
|
521
|
+
{% set safeContent = userContent | remove_tag('script') %}
|
|
522
|
+
{# Result: '<p>Hello</p><p>World</p>' #}
|
|
523
|
+
|
|
524
|
+
{# Strip specific formatting tags #}
|
|
525
|
+
{% set formatted = '<div><strong>Bold</strong> and <em>italic</em> text</div>' %}
|
|
526
|
+
{% set noStrong = formatted | remove_tag('strong') %}
|
|
527
|
+
{# Result: '<div>Bold and <em>italic</em> text</div>' #}
|
|
528
|
+
|
|
529
|
+
{# Chain multiple remove_tag filters for multiple tags #}
|
|
530
|
+
{% set richContent = page.content %}
|
|
531
|
+
{% set stripped = richContent
|
|
532
|
+
| remove_tag('script')
|
|
533
|
+
| remove_tag('style')
|
|
534
|
+
| remove_tag('iframe')
|
|
535
|
+
%}
|
|
536
|
+
|
|
537
|
+
{# Remove images for text-only preview #}
|
|
538
|
+
{% set textOnly = htmlContent | remove_tag('img') %}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
**Security Note:**
|
|
542
|
+
|
|
543
|
+
While this filter can help sanitize HTML content, it should not be relied upon as the sole security measure. For critical security requirements, use a dedicated HTML sanitization library on the server side before content reaches your templates.
|
|
544
|
+
|
|
545
|
+
### if
|
|
546
|
+
|
|
547
|
+
An inline conditional/ternary operator filter that returns one value if a condition is truthy, and another if it's falsy. Similar to Nunjucks' inline if syntax.
|
|
548
|
+
|
|
549
|
+
**Why use this?**
|
|
550
|
+
|
|
551
|
+
When you need simple conditional values in templates without verbose if/else blocks, the `if` filter provides a clean inline solution. It's especially useful for class names, attributes, or displaying alternate text based on conditions.
|
|
552
|
+
|
|
553
|
+
**Usage:**
|
|
554
|
+
|
|
555
|
+
1. Enable the `if` filter in your Eleventy config:
|
|
556
|
+
|
|
557
|
+
```javascript
|
|
558
|
+
import { ifFilter } from "@anydigital/eleventy-bricks";
|
|
559
|
+
|
|
560
|
+
export default function (eleventyConfig) {
|
|
561
|
+
ifFilter(eleventyConfig);
|
|
562
|
+
// Or use as plugin:
|
|
563
|
+
// eleventyConfig.addPlugin(eleventyBricks, { filters: ['if'] });
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
2. Use the filter in your templates:
|
|
568
|
+
|
|
569
|
+
```njk
|
|
570
|
+
{# Basic usage #}
|
|
571
|
+
<div class="{{ 'active' | if: isActive, 'inactive' }}">Status</div>
|
|
572
|
+
|
|
573
|
+
{# Without falsy value (defaults to empty string) #}
|
|
574
|
+
<span class="{{ 'highlight' | if: shouldHighlight }}">Text</span>
|
|
575
|
+
|
|
576
|
+
{# With variable values #}
|
|
577
|
+
{% set status = 'Published' | if: post.published, 'Draft' %}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**Parameters:**
|
|
581
|
+
|
|
582
|
+
- `trueValue`: The value to return if condition is truthy
|
|
583
|
+
- `condition`: The condition to evaluate
|
|
584
|
+
- `falseValue`: The value to return if condition is falsy (optional, defaults to empty string)
|
|
585
|
+
|
|
586
|
+
**Features:**
|
|
587
|
+
|
|
588
|
+
- Returns `trueValue` if condition is truthy, otherwise returns `falseValue`
|
|
589
|
+
- Treats empty objects `{}` as falsy
|
|
590
|
+
- Default `falseValue` is an empty string if not provided
|
|
591
|
+
- Works with any data type for values
|
|
592
|
+
|
|
593
|
+
**Examples:**
|
|
594
|
+
|
|
595
|
+
```njk
|
|
596
|
+
{# Toggle CSS classes #}
|
|
597
|
+
<button class="{{ 'btn-primary' | if: isPrimary, 'btn-secondary' }}">
|
|
598
|
+
Click me
|
|
599
|
+
</button>
|
|
600
|
+
|
|
601
|
+
{# Display different text #}
|
|
602
|
+
<p>{{ 'Online' | if: user.isOnline, 'Offline' }}</p>
|
|
603
|
+
|
|
604
|
+
{# Use with boolean values #}
|
|
605
|
+
{% set isEnabled = true %}
|
|
606
|
+
<div>{{ 'Enabled' | if: isEnabled, 'Disabled' }}</div>
|
|
607
|
+
|
|
608
|
+
{# Conditional attribute values #}
|
|
609
|
+
<input type="checkbox" {{ 'checked' | if: isChecked }}>
|
|
610
|
+
|
|
611
|
+
{# With numeric values #}
|
|
612
|
+
<span class="{{ 'has-items' | if: items.length }}">
|
|
613
|
+
{{ items.length }} items
|
|
614
|
+
</span>
|
|
615
|
+
|
|
616
|
+
{# Chain with other filters #}
|
|
617
|
+
{% set cssClass = 'featured' | if: post.featured | upper %}
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
### attr_concat
|
|
621
|
+
|
|
622
|
+
A filter that concatenates values to an attribute array, returning a new object with the combined array. Useful for adding items to arrays like tags, classes, or other list-based attributes.
|
|
623
|
+
|
|
624
|
+
**Why use this?**
|
|
625
|
+
|
|
626
|
+
When working with objects that have array attributes (like tags), you often need to add additional values without mutating the original object. The `attr_concat` filter provides a clean way to combine existing array values with new ones, automatically handling duplicates.
|
|
627
|
+
|
|
628
|
+
**Usage:**
|
|
629
|
+
|
|
630
|
+
1. Enable the `attr_concat` filter in your Eleventy config:
|
|
631
|
+
|
|
632
|
+
```javascript
|
|
633
|
+
import { attrConcatFilter } from "@anydigital/eleventy-bricks";
|
|
634
|
+
|
|
635
|
+
export default function (eleventyConfig) {
|
|
636
|
+
attrConcatFilter(eleventyConfig);
|
|
637
|
+
// Or use as plugin:
|
|
638
|
+
// eleventyConfig.addPlugin(eleventyBricks, { filters: ['attr_concat'] });
|
|
639
|
+
}
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
2. Use the filter in your templates:
|
|
643
|
+
|
|
644
|
+
```njk
|
|
645
|
+
{# Add tags to a post object #}
|
|
646
|
+
{% set enhancedPost = post | attr_concat('tags', ['featured', 'popular']) %}
|
|
647
|
+
|
|
648
|
+
{# Add a single value #}
|
|
649
|
+
{% set updatedPost = post | attr_concat('tags', 'important') %}
|
|
650
|
+
|
|
651
|
+
{# Add values from a JSON string #}
|
|
652
|
+
{% set modifiedPost = post | attr_concat('tags', '["new", "trending"]') %}
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
**Parameters:**
|
|
656
|
+
|
|
657
|
+
- `obj`: The object to modify
|
|
658
|
+
- `attr`: The attribute name (must be an array or will be treated as one)
|
|
659
|
+
- `values`: Values to concatenate (can be an array, JSON string array, or single value)
|
|
660
|
+
|
|
661
|
+
**Returns:**
|
|
662
|
+
|
|
663
|
+
A new object with the specified attribute containing the combined unique array. The original object is not modified.
|
|
664
|
+
|
|
665
|
+
**Features:**
|
|
666
|
+
|
|
667
|
+
- Non-mutating: Creates a new object, leaving the original unchanged
|
|
668
|
+
- Automatically removes duplicates using Set
|
|
669
|
+
- Handles multiple input types: arrays, JSON string arrays, or single values
|
|
670
|
+
- Creates the attribute as an empty array if it doesn't exist
|
|
671
|
+
- Logs an error if the existing attribute is not an array
|
|
672
|
+
|
|
673
|
+
**Examples:**
|
|
674
|
+
|
|
675
|
+
```njk
|
|
676
|
+
{# Add multiple tags #}
|
|
677
|
+
{% set post = { title: 'My Post', tags: ['javascript'] } %}
|
|
678
|
+
{% set enhancedPost = post | attr_concat('tags', ['tutorial', 'beginner']) %}
|
|
679
|
+
{# Result: { title: 'My Post', tags: ['javascript', 'tutorial', 'beginner'] } #}
|
|
680
|
+
|
|
681
|
+
{# Add single value #}
|
|
682
|
+
{% set updatedPost = post | attr_concat('tags', 'featured') %}
|
|
683
|
+
{# Result: { title: 'My Post', tags: ['javascript', 'tutorial', 'beginner', 'featured'] } #}
|
|
684
|
+
|
|
685
|
+
{# No duplicates #}
|
|
686
|
+
{% set deduped = post | attr_concat('tags', ['javascript', 'advanced']) %}
|
|
687
|
+
{# Result: Only 'advanced' is added, 'javascript' already exists #}
|
|
688
|
+
|
|
689
|
+
{# Chain multiple attr_concat filters #}
|
|
690
|
+
{% set finalPost = post
|
|
691
|
+
| attr_concat('tags', 'popular')
|
|
692
|
+
| attr_concat('categories', ['tech', 'programming'])
|
|
693
|
+
%}
|
|
694
|
+
|
|
695
|
+
{# Use in loops to enhance collection items #}
|
|
696
|
+
{% for item in collections.posts %}
|
|
697
|
+
{% set enhancedItem = item | attr_concat('data.tags', 'blog') %}
|
|
698
|
+
{# ... use enhancedItem ... #}
|
|
699
|
+
{% endfor %}
|
|
436
700
|
```
|
|
437
701
|
|
|
438
702
|
### siteData
|
|
@@ -450,7 +714,7 @@ Many websites need access to the current year (for copyright notices) and enviro
|
|
|
450
714
|
```javascript
|
|
451
715
|
import { siteData } from "@anydigital/eleventy-bricks";
|
|
452
716
|
|
|
453
|
-
export default function(eleventyConfig) {
|
|
717
|
+
export default function (eleventyConfig) {
|
|
454
718
|
siteData(eleventyConfig);
|
|
455
719
|
// Or use as plugin:
|
|
456
720
|
// eleventyConfig.addPlugin(eleventyBricks, { siteData: true });
|
|
@@ -460,6 +724,7 @@ export default function(eleventyConfig) {
|
|
|
460
724
|
2. Use the global data in your templates:
|
|
461
725
|
|
|
462
726
|
**Current Year:**
|
|
727
|
+
|
|
463
728
|
```njk
|
|
464
729
|
<footer>
|
|
465
730
|
<p>© {{ site.year }} Your Company Name. All rights reserved.</p>
|
|
@@ -467,8 +732,9 @@ export default function(eleventyConfig) {
|
|
|
467
732
|
```
|
|
468
733
|
|
|
469
734
|
**Environment Check:**
|
|
735
|
+
|
|
470
736
|
```njk
|
|
471
|
-
{% if site.
|
|
737
|
+
{% if site.prod %}
|
|
472
738
|
<!-- Production-only features -->
|
|
473
739
|
<script async src="https://www.googletagmanager.com/gtag/js?id=GA_TRACKING_ID"></script>
|
|
474
740
|
{% else %}
|
|
@@ -480,7 +746,7 @@ export default function(eleventyConfig) {
|
|
|
480
746
|
**Available Data:**
|
|
481
747
|
|
|
482
748
|
- `site.year`: The current year as a number (e.g., `2026`)
|
|
483
|
-
- `site.
|
|
749
|
+
- `site.prod`: Boolean indicating if running in production mode (`true` for `eleventy build`, `false` for `eleventy serve`)
|
|
484
750
|
|
|
485
751
|
**Features:**
|
|
486
752
|
|
|
@@ -496,12 +762,12 @@ export default function(eleventyConfig) {
|
|
|
496
762
|
<p>Copyright © {{ site.year }} My Site</p>
|
|
497
763
|
|
|
498
764
|
{# Conditional loading of analytics #}
|
|
499
|
-
{% if site.
|
|
765
|
+
{% if site.prod %}
|
|
500
766
|
<script src="/analytics.js"></script>
|
|
501
767
|
{% endif %}
|
|
502
768
|
|
|
503
769
|
{# Different behavior in dev vs prod #}
|
|
504
|
-
{% if site.
|
|
770
|
+
{% if site.prod %}
|
|
505
771
|
<link rel="stylesheet" href="/css/styles.min.css">
|
|
506
772
|
{% else %}
|
|
507
773
|
<link rel="stylesheet" href="/css/styles.css">
|
|
@@ -511,10 +777,14 @@ export default function(eleventyConfig) {
|
|
|
511
777
|
|
|
512
778
|
### Additional Exports
|
|
513
779
|
|
|
514
|
-
The plugin also exports the following for advanced usage:
|
|
780
|
+
The plugin also exports the following utility functions for advanced usage:
|
|
515
781
|
|
|
516
782
|
- `transformAutoRaw(content)`: The transform function used by `mdAutoRawTags` preprocessor. Can be used programmatically to wrap Nunjucks syntax with raw tags.
|
|
517
783
|
- `transformNl2br(content)`: The transform function used by `mdAutoNl2br` preprocessor. Can be used programmatically to convert `\n` sequences to `<br>` tags.
|
|
784
|
+
- `merge(first, ...rest)`: The core merge function used by the `merge` filter. Can be used programmatically to merge arrays or objects.
|
|
785
|
+
- `removeTag(html, tagName)`: The core function used by the `remove_tag` filter. Can be used programmatically to remove HTML tags from content.
|
|
786
|
+
- `iff(trueValue, condition, falseValue)`: The core conditional function used by the `if` filter. Can be used programmatically as a ternary operator.
|
|
787
|
+
- `attrConcat(obj, attr, values)`: The core function used by the `attr_concat` filter. Can be used programmatically to concatenate values to an attribute array.
|
|
518
788
|
|
|
519
789
|
## Starter Configuration Files
|
|
520
790
|
|
|
@@ -525,6 +795,7 @@ The package includes pre-configured starter files in `node_modules/@anydigital/e
|
|
|
525
795
|
#### eleventy.config.js
|
|
526
796
|
|
|
527
797
|
A fully-configured Eleventy config file with:
|
|
798
|
+
|
|
528
799
|
- All eleventy-bricks plugins enabled
|
|
529
800
|
- Eleventy Navigation plugin
|
|
530
801
|
- Markdown-it with anchors
|
|
@@ -533,11 +804,13 @@ A fully-configured Eleventy config file with:
|
|
|
533
804
|
- Symlink support for development
|
|
534
805
|
|
|
535
806
|
**Required dependencies:**
|
|
807
|
+
|
|
536
808
|
```bash
|
|
537
809
|
npm install @11ty/eleventy-navigation markdown-it markdown-it-anchor js-yaml minimist
|
|
538
810
|
```
|
|
539
811
|
|
|
540
812
|
**Symlink to your project:**
|
|
813
|
+
|
|
541
814
|
```bash
|
|
542
815
|
ln -s node_modules/@anydigital/eleventy-bricks/src/eleventy.config.js eleventy.config.js
|
|
543
816
|
```
|
|
@@ -547,6 +820,7 @@ ln -s node_modules/@anydigital/eleventy-bricks/src/eleventy.config.js eleventy.c
|
|
|
547
820
|
A ready-to-use Sveltia CMS admin interface for content management.
|
|
548
821
|
|
|
549
822
|
**Symlink to your project:**
|
|
823
|
+
|
|
550
824
|
```bash
|
|
551
825
|
mkdir -p admin
|
|
552
826
|
ln -s ../node_modules/@anydigital/eleventy-bricks/src/admin/index.html admin/index.html
|