-
Notifications
You must be signed in to change notification settings - Fork 30
/
shortcodes.js
112 lines (100 loc) · 3.37 KB
/
shortcodes.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
const fs = require('fs');
const path = require('path');
const { outdent } = require('outdent');
const Image = require('@11ty/eleventy-img');
const markdown = require('./markdown');
const iconDefaultSize = 24;
const defaultSizes = '90vw';
const defaultImagesSizes = [1920, 1280, 640, 320];
const isFullUrl = (url) => {
try {
return !!new URL(url);
} catch {
return false;
}
};
const manifestPath = path.resolve(__dirname, '../_site/assets/manifest.json');
module.exports = {
// Allow embedding markdown in `.njk` files
// {% markdown %}
// # Heading
// {% endmarkdown %}
markdown: (content) => markdown.render(outdent.string(content)),
// Allow embedding webpack assets pulled out from `manifest.json`
// {% webpack "main.css" %}
webpack: async (name) =>
new Promise((resolve) => {
fs.readFile(manifestPath, { encoding: 'utf8' }, (err, data) =>
resolve(err ? `/assets/${name}` : JSON.parse(data)[name])
);
}),
// Allow embedding svg icon
// {% icon "github.svg", "my-class", [24, 24] %}
icon: (name, className, size = iconDefaultSize) => {
if (!Array.isArray(size)) size = [size];
return outdent({ newline: '' })`
<svg class="icon icon--${name} ${
className || ''
}" role="img" aria-hidden="true" width="${size[0]}" height="${
size[1] || size[0]
}">
<use xlink:href="/assets/images/sprite.svg#${name}"></use>
</svg>`;
},
// Allow embedding responsive images
// {% image "image.jpeg", "Image alt", "Image title", "my-class" %}
// {% image [100,100], "image.jpeg", "Image alt", "Image title", "my-class" %}
image: async (...args) => {
let fallbackWidth, fallbackHeight;
if (Array.isArray(args[0])) {
[fallbackWidth, fallbackHeight] = args.shift();
}
const src = args[0];
const alt = args[1];
const title = args[2];
const className = args[3];
const lazy = args[4] ?? true;
const sizes = args[5] ?? defaultSizes;
const extension = path.extname(src).slice(1).toLowerCase();
const fullSrc = isFullUrl(src) ? src : `./src/assets/images/${src}`;
let stats;
try {
stats = await Image(fullSrc, {
widths: defaultImagesSizes,
formats: extension === 'webp' ? ['webp', 'jpeg'] : ['webp', extension],
urlPath: '/assets/images/',
outputDir: '_site/assets/images/'
});
} catch (e) {
console.log('\n\x1b[31mERROR\x1b[0m creating image:');
console.log(`> (${fullSrc})`);
console.log(` ${e}\n`);
return '';
}
const fallback = stats[extension].reverse()[0];
const picture = outdent({ newline: '' })`
<picture>
${Object.values(stats)
.map(
(image) =>
`<source type="image/${image[0].format}" srcset="${image
.map((entry) => `${entry.url} ${entry.width}w`)
.join(', ')}" sizes="${sizes}">`
)
.join('')}
<img
class="${className ? `img-${className}` : ''}"
loading="${lazy ? 'lazy' : 'eager'}"
src="${fallback.url}"
width="${fallbackWidth ?? fallback.width}"
height="${fallbackHeight ?? fallback.height}" alt="${alt}">
</picture>`;
return title
? outdent({ newline: '' })`
<figure class="${className ? `fig-${className}` : ''}">
${picture}
<figcaption>${markdown.renderInline(title)}</figcaption>
</figure>`
: picture;
}
};