@anydigital/eleventy-bricks 0.28.0-alpha.2 → 0.28.0-alpha.4
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/package.json +2 -3
- package/src/do/package.json +1 -1
- package/src/eleventy.config.js +21 -20
- package/src/filters/fetch.js +1 -1
- package/src/filters/unindent.js +29 -0
- package/src/filters/unindent.test.js +49 -0
- package/src/index.js +4 -0
- package/src/processors/autoLinkFavicons.js +1 -10
- package/src/processors/autoLinkFavicons.test.js +7 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anydigital/eleventy-bricks",
|
|
3
|
-
"version": "0.28.0-alpha.
|
|
3
|
+
"version": "0.28.0-alpha.4",
|
|
4
4
|
"description": "A collection of helpful utilities and filters for Eleventy (11ty)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -11,8 +11,7 @@
|
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
-
"test": "node --test src/**/*.test.js"
|
|
15
|
-
"prepublishOnly": "npm run test"
|
|
14
|
+
"test": "node --test src/**/*.test.js"
|
|
16
15
|
},
|
|
17
16
|
"keywords": [
|
|
18
17
|
"11ty",
|
package/src/do/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"11ty": "cd ../ && NODE_OPTIONS='--preserve-symlinks' eleventy",
|
|
10
10
|
"11ty:clean": "rm -r ../_site",
|
|
11
11
|
"11ty:debug": "DEBUG=* npm run 11ty --",
|
|
12
|
-
"tw": "tailwindcss -i ../
|
|
12
|
+
"tw": "tailwindcss -i ../_includes/styles.css -o ../_site/styles.css",
|
|
13
13
|
"tw:debug": "DEBUG=* npm run tw --"
|
|
14
14
|
}
|
|
15
15
|
}
|
package/src/eleventy.config.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/* CLI */
|
|
2
|
-
import minimist from "minimist";
|
|
3
1
|
/* Plugins */
|
|
4
2
|
import { RenderPlugin } from "@11ty/eleventy";
|
|
5
3
|
import eleventyBricksPlugin from "@anydigital/eleventy-bricks";
|
|
@@ -46,9 +44,13 @@ import yaml from "js-yaml";
|
|
|
46
44
|
* @returns {Object} The Eleventy configuration object
|
|
47
45
|
*/
|
|
48
46
|
export default function (eleventyConfig) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
const inputDir = eleventyConfig.directories.input;
|
|
48
|
+
|
|
49
|
+
/* Jekyll parity */
|
|
50
|
+
eleventyConfig.addPassthroughCopy("assets");
|
|
51
|
+
eleventyConfig.addGlobalData("layout", "default");
|
|
52
|
+
eleventyConfig.setLiquidOptions({ dynamicPartials: false }); // allows unquoted Jekyll-style includes
|
|
53
|
+
eleventyConfig.addFilter("relative_url", (content) => content);
|
|
52
54
|
|
|
53
55
|
/* Plugins */
|
|
54
56
|
eleventyConfig.addPlugin(RenderPlugin);
|
|
@@ -58,7 +60,18 @@ export default function (eleventyConfig) {
|
|
|
58
60
|
mdAutoRawTags: true,
|
|
59
61
|
autoLinkFavicons: true,
|
|
60
62
|
siteData: true,
|
|
61
|
-
filters: [
|
|
63
|
+
filters: [
|
|
64
|
+
"attr_set",
|
|
65
|
+
"attr_includes",
|
|
66
|
+
"merge",
|
|
67
|
+
"remove_tag",
|
|
68
|
+
"if",
|
|
69
|
+
"attr_concat",
|
|
70
|
+
"fetch",
|
|
71
|
+
"section",
|
|
72
|
+
"strip_tag",
|
|
73
|
+
"unindent",
|
|
74
|
+
],
|
|
62
75
|
});
|
|
63
76
|
if (pluginTOC) {
|
|
64
77
|
eleventyConfig.addPlugin(pluginTOC, {
|
|
@@ -68,9 +81,6 @@ export default function (eleventyConfig) {
|
|
|
68
81
|
}
|
|
69
82
|
|
|
70
83
|
/* Libraries */
|
|
71
|
-
eleventyConfig.setLiquidOptions({
|
|
72
|
-
dynamicPartials: false, // This allows unquoted includes like Jekyll
|
|
73
|
-
});
|
|
74
84
|
let md = markdownIt({
|
|
75
85
|
html: true,
|
|
76
86
|
linkify: true,
|
|
@@ -86,14 +96,13 @@ export default function (eleventyConfig) {
|
|
|
86
96
|
eleventyConfig.addFilter("markdownify", (content) => md.render(String(content ?? "")));
|
|
87
97
|
|
|
88
98
|
/* Data */
|
|
89
|
-
eleventyConfig.addGlobalData("layout", "default"); // Jekyll parity
|
|
90
99
|
eleventyConfig.addDataExtension("yml", (contents) => yaml.load(contents));
|
|
91
100
|
|
|
92
101
|
/* Build */
|
|
93
102
|
eleventyConfig.addPassthroughCopy(
|
|
94
103
|
{
|
|
95
|
-
|
|
96
|
-
...(inputDir !== "
|
|
104
|
+
_public: ".",
|
|
105
|
+
...(inputDir !== "." && { [`${inputDir}/_public`]: "." }),
|
|
97
106
|
},
|
|
98
107
|
{ expand: true }, // This follows/resolves symbolic links
|
|
99
108
|
);
|
|
@@ -101,12 +110,4 @@ export default function (eleventyConfig) {
|
|
|
101
110
|
/* Dev tools */
|
|
102
111
|
// Follow symlinks in Chokidar used by 11ty to watch files
|
|
103
112
|
eleventyConfig.setChokidarConfig({ followSymlinks: true });
|
|
104
|
-
|
|
105
|
-
/* Config */
|
|
106
|
-
return {
|
|
107
|
-
dir: {
|
|
108
|
-
input: inputDir,
|
|
109
|
-
// includes: "_theme",
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
113
|
}
|
package/src/filters/fetch.js
CHANGED
|
@@ -18,7 +18,7 @@ export function fetchFilter(eleventyConfig) {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
// Get the input directory from Eleventy config
|
|
21
|
-
const inputDir =
|
|
21
|
+
const inputDir = this.eleventy.directories.input;
|
|
22
22
|
|
|
23
23
|
// Check if it's a URL or local path
|
|
24
24
|
const isUrl = url.startsWith("http://") || url.startsWith("https://");
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remove the minimal common indentation from a multi-line string
|
|
3
|
+
*
|
|
4
|
+
* Finds the smallest leading-whitespace count across all non-empty lines
|
|
5
|
+
* and strips that many characters from the beginning of every line.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} content - The input string
|
|
8
|
+
* @returns {string} The unindented string
|
|
9
|
+
*/
|
|
10
|
+
export function unindent(content) {
|
|
11
|
+
const lines = String(content ?? "").split("\n");
|
|
12
|
+
const minIndent = Math.min(...lines.filter((l) => l.trim()).map((l) => l.match(/^(\s*)/)[1].length));
|
|
13
|
+
return lines.map((l) => l.slice(minIndent)).join("\n");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* unindent filter - Remove minimal common indentation
|
|
18
|
+
*
|
|
19
|
+
* Strips the smallest leading-whitespace indent shared by all non-empty
|
|
20
|
+
* lines, useful for dedenting captured or indented template blocks.
|
|
21
|
+
*
|
|
22
|
+
* Usage in templates:
|
|
23
|
+
* {{ content | unindent }}
|
|
24
|
+
*
|
|
25
|
+
* @param {Object} eleventyConfig - The Eleventy configuration object
|
|
26
|
+
*/
|
|
27
|
+
export function unindentFilter(eleventyConfig) {
|
|
28
|
+
eleventyConfig.addFilter("unindent", unindent);
|
|
29
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { unindent } from "./unindent.js";
|
|
4
|
+
|
|
5
|
+
test("unindent - removes common leading spaces", () => {
|
|
6
|
+
const input = " hello\n world";
|
|
7
|
+
assert.strictEqual(unindent(input), "hello\nworld");
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test("unindent - removes common leading tabs", () => {
|
|
11
|
+
const input = "\tfoo\n\tbar";
|
|
12
|
+
assert.strictEqual(unindent(input), "foo\nbar");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("unindent - preserves relative indentation", () => {
|
|
16
|
+
const input = " if true\n inner\n end";
|
|
17
|
+
assert.strictEqual(unindent(input), "if true\n inner\nend");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("unindent - ignores blank lines when computing min indent", () => {
|
|
21
|
+
const input = " line1\n\n line2";
|
|
22
|
+
assert.strictEqual(unindent(input), "line1\n\nline2");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("unindent - does nothing when already at zero indent", () => {
|
|
26
|
+
const input = "hello\nworld";
|
|
27
|
+
assert.strictEqual(unindent(input), "hello\nworld");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("unindent - handles single line", () => {
|
|
31
|
+
assert.strictEqual(unindent(" hello"), "hello");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("unindent - handles null input", () => {
|
|
35
|
+
assert.strictEqual(unindent(null), "");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("unindent - handles undefined input", () => {
|
|
39
|
+
assert.strictEqual(unindent(undefined), "");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("unindent - handles empty string", () => {
|
|
43
|
+
assert.strictEqual(unindent(""), "");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("unindent - mixed indent levels, strips only the minimum", () => {
|
|
47
|
+
const input = " a\n b\n c";
|
|
48
|
+
assert.strictEqual(unindent(input), "a\n b\nc");
|
|
49
|
+
});
|
package/src/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import { stripTagFilter, stripTag } from "./filters/strip_tag.js";
|
|
|
15
15
|
import { ifFilter, iff } from "./filters/if.js";
|
|
16
16
|
import { attrConcatFilter, attrConcat } from "./filters/attr_concat.js";
|
|
17
17
|
import { sectionFilter, section as sectionFn } from "./filters/section.js";
|
|
18
|
+
import { unindentFilter, unindent } from "./filters/unindent.js";
|
|
18
19
|
import { siteData } from "./siteData.js";
|
|
19
20
|
|
|
20
21
|
// Conditionally import fetchFilter only if @11ty/eleventy-fetch is available
|
|
@@ -58,6 +59,7 @@ export default function eleventyBricksPlugin(eleventyConfig, options = {}) {
|
|
|
58
59
|
if: ifFilter,
|
|
59
60
|
attr_concat: attrConcatFilter,
|
|
60
61
|
section: sectionFilter,
|
|
62
|
+
unindent: unindentFilter,
|
|
61
63
|
...(fetchFilter && { fetch: fetchFilter }),
|
|
62
64
|
};
|
|
63
65
|
|
|
@@ -92,6 +94,7 @@ export {
|
|
|
92
94
|
ifFilter,
|
|
93
95
|
attrConcatFilter,
|
|
94
96
|
sectionFilter,
|
|
97
|
+
unindentFilter,
|
|
95
98
|
fetchFilter,
|
|
96
99
|
siteData,
|
|
97
100
|
};
|
|
@@ -112,4 +115,5 @@ export {
|
|
|
112
115
|
attrConcat,
|
|
113
116
|
attrSet,
|
|
114
117
|
sectionFn as section,
|
|
118
|
+
unindent,
|
|
115
119
|
};
|
|
@@ -36,21 +36,12 @@ export function cleanLinkText(linkText, domain) {
|
|
|
36
36
|
export function buildFaviconLink(attrs, domain, text) {
|
|
37
37
|
let updatedAttrs = attrs;
|
|
38
38
|
|
|
39
|
-
// Check if attrs already contains a class attribute
|
|
40
|
-
if (/class\s*=\s*["']/.test(attrs)) {
|
|
41
|
-
// Append whitespace-nowrap to existing class
|
|
42
|
-
updatedAttrs = attrs.replace(/class\s*=\s*["']([^"']*)["']/i, 'class="$1 whitespace-nowrap"');
|
|
43
|
-
} else {
|
|
44
|
-
// Add new class attribute
|
|
45
|
-
updatedAttrs = attrs + ' class="whitespace-nowrap"';
|
|
46
|
-
}
|
|
47
|
-
|
|
48
39
|
// Check if attrs already contains a target attribute
|
|
49
40
|
if (!/target\s*=/.test(attrs)) {
|
|
50
41
|
updatedAttrs = updatedAttrs + ' target="_blank"';
|
|
51
42
|
}
|
|
52
43
|
|
|
53
|
-
return `<a ${updatedAttrs}><i><img src="https://www.google.com/s2/favicons?domain=${domain}&sz=
|
|
44
|
+
return `<a ${updatedAttrs}><i><img src="https://www.google.com/s2/favicons?domain=${domain}&sz=64"></i><span>${text}</span></a>`;
|
|
54
45
|
}
|
|
55
46
|
|
|
56
47
|
/**
|
|
@@ -90,7 +90,7 @@ describe("buildFaviconLink", () => {
|
|
|
90
90
|
const result = buildFaviconLink('href="https://example.com/docs"', "example.com", "/docs");
|
|
91
91
|
assert.equal(
|
|
92
92
|
result,
|
|
93
|
-
'<a href="https://example.com/docs" class="whitespace-nowrap" target="_blank"><i><img src="https://www.google.com/s2/favicons?domain=example.com&sz=
|
|
93
|
+
'<a href="https://example.com/docs" class="whitespace-nowrap" target="_blank"><i><img src="https://www.google.com/s2/favicons?domain=example.com&sz=64"></i><span>/docs</span></a>',
|
|
94
94
|
);
|
|
95
95
|
});
|
|
96
96
|
|
|
@@ -98,13 +98,13 @@ describe("buildFaviconLink", () => {
|
|
|
98
98
|
const result = buildFaviconLink('href="https://example.com" class="link"', "example.com", "text");
|
|
99
99
|
assert.equal(
|
|
100
100
|
result,
|
|
101
|
-
'<a href="https://example.com" class="link whitespace-nowrap" target="_blank"><i><img src="https://www.google.com/s2/favicons?domain=example.com&sz=
|
|
101
|
+
'<a href="https://example.com" class="link whitespace-nowrap" target="_blank"><i><img src="https://www.google.com/s2/favicons?domain=example.com&sz=64"></i><span>text</span></a>',
|
|
102
102
|
);
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
it("should use sz=
|
|
105
|
+
it("should use sz=64 parameter for favicon size", () => {
|
|
106
106
|
const result = buildFaviconLink('href="https://example.com"', "example.com", "text");
|
|
107
|
-
assert.match(result, /sz=
|
|
107
|
+
assert.match(result, /sz=64/);
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
it("should wrap img in <i> tag", () => {
|
|
@@ -116,7 +116,7 @@ describe("buildFaviconLink", () => {
|
|
|
116
116
|
const result = buildFaviconLink('href="https://github.com/repo"', "github.com", "/repo");
|
|
117
117
|
assert.equal(
|
|
118
118
|
result,
|
|
119
|
-
'<a href="https://github.com/repo" class="whitespace-nowrap" target="_blank"><i><img src="https://www.google.com/s2/favicons?domain=github.com&sz=
|
|
119
|
+
'<a href="https://github.com/repo" class="whitespace-nowrap" target="_blank"><i><img src="https://www.google.com/s2/favicons?domain=github.com&sz=64"></i><span>/repo</span></a>',
|
|
120
120
|
);
|
|
121
121
|
});
|
|
122
122
|
|
|
@@ -136,7 +136,7 @@ describe("transformLink", () => {
|
|
|
136
136
|
);
|
|
137
137
|
assert.match(
|
|
138
138
|
result,
|
|
139
|
-
/<i><img src="https:\/\/www\.google\.com\/s2\/favicons\?domain=example\.com&sz=
|
|
139
|
+
/<i><img src="https:\/\/www\.google\.com\/s2\/favicons\?domain=example\.com&sz=64"><\/i><span>\/docs<\/span>/,
|
|
140
140
|
);
|
|
141
141
|
});
|
|
142
142
|
|
|
@@ -395,7 +395,7 @@ describe("replaceLinksInHtml", () => {
|
|
|
395
395
|
const html = '<a href="https://example.com/docs">https://example.com/docs</a>';
|
|
396
396
|
const result = replaceLinksInHtml(html, transformLink);
|
|
397
397
|
// transformLink should add favicon for plain URL links
|
|
398
|
-
assert.match(result, /<img src="https:\/\/www\.google\.com\/s2\/favicons\?domain=example\.com&sz=
|
|
398
|
+
assert.match(result, /<img src="https:\/\/www\.google\.com\/s2\/favicons\?domain=example\.com&sz=64">/);
|
|
399
399
|
assert.match(result, /<span>\/docs<\/span><\/a>/);
|
|
400
400
|
});
|
|
401
401
|
|