Automatically set image size

This commit is contained in:
Neil Brommer 2023-10-27 14:59:22 -07:00
parent 3cfc97d5c1
commit a68663b8b4
9 changed files with 249 additions and 15 deletions

View File

@ -6,6 +6,7 @@ const eleventyDrafts = require("./eleventy.config.drafts");
const mdDefList = require("markdown-it-deflist");
const mdToc = require("markdown-it-table-of-contents");
const mdAnchor = require("markdown-it-anchor");
const { markdownItImageSize } = require("./markdown-it-image-size");
const nunjucksDate = require("nunjucks-date");
const markdownIt = require("markdown-it");
@ -22,12 +23,15 @@ function addEleventyPlugins(eleventyConfig) {
}
function configureMarkdown(eleventyConfig) {
console.log("markdownItImageSize", markdownItImageSize);
eleventyConfig.amendLibrary("md", mdLib => mdLib
.use(mdDefList)
.use(mdToc, {
includeLevel: [ 1, 2, 3, 4, 5, 6 ]
})
.use(mdAnchor));
.use(mdAnchor)
.use(markdownItImageSize));
}
function addFilters(eleventyConfig) {

110
markdown-it-image-size.js Normal file
View File

@ -0,0 +1,110 @@
const imageSize = require("image-size");
const markdownIt = require("markdown-it");
const fetch = require("sync-fetch");
function markdownItImageSize(md) {
md.renderer.rules.image = (tokens, index, options, env) => {
const token = tokens[index];
const srcIndex = token.attrIndex("src");
const imageUrl = token.attrs[srcIndex][1];
const caption = md.utils.escapeHtml(token.content);
const otherAttributes = generateAttributes(md, token);
const isExternalImage =
imageUrl.startsWith("http://") ||
imageUrl.startsWith("https://") ||
imageUrl.startsWith("//");
const isLocalAbsoluteUrl = imageUrl.startsWith("/");
let { width, height } = isExternalImage
? getImageDimensionsFromExternalImage(imageUrl)
: getImageDimensions(`${isLocalAbsoluteUrl ? "./src" : ""}${imageUrl}`);
let imageFileName = imageUrl
.replaceAll("\\", "/")
.split("/")
.pop();
let scaleMatches = Array.from(imageFileName.matchAll(/_([0-9])x/g));
if (scaleMatches.length > 0){
let scale = scaleMatches.pop()[1];
width = width / scale;
height = height / scale;
}
const dimensionsAttributes = width && height
? ` width="${width}" height="${height}"`
: "";
return `<img src="${imageUrl}" alt="${caption}"${dimensionsAttributes}${
otherAttributes ? " " + otherAttributes : ""
}>`;
};
}
function generateAttributes(md, token) {
const ignore = ["src", "alt"];
const escape = ["title"];
return token.attrs
.filter(([key]) => !ignore.includes(key))
.map(([key, value]) => {
const escapeAttributeValue = escape.includes(key);
const finalValue = escapeAttributeValue
? md.utils.escapeHtml(value)
: value;
return `${key}="${finalValue}"`;
})
.join(" ");
}
const customPluginDefaults = {
getAbsPathFromEnv: (env) => {
const markdownPath = env?.page?.inputPath; // 11ty
if (markdownPath) {
return markdownPath
.substring(0, markdownPath.lastIndexOf("/"))
.replace(/\/\.\//g, "/");
}
return undefined;
},
};
function getImageDimensions(imageUrl, env) {
try {
const { width, height } = imageSize(imageUrl);
return { width, height };
} catch (error) {
const isRelativePath = !imageUrl.startsWith("/");
const inputPath = customPluginDefaults.getAbsPathFromEnv(env);
if (isRelativePath && inputPath) {
return getImageDimensions(`${inputPath}/${imageUrl}`);
}
console.error(
`markdown-it-image-size: Could not get dimensions of image with url ${imageUrl}.\n\n`,
error,
);
return { width: undefined, height: undefined };
}
}
function getImageDimensionsFromExternalImage(imageUrl) {
const isMissingProtocol = imageUrl.startsWith("//");
const response = fetch(isMissingProtocol ? `https:${imageUrl}` : imageUrl);
const buffer = response.buffer();
const { width, height } = imageSize(buffer);
return { width, height };
}
exports.markdownItImageSize = markdownItImageSize;

132
package-lock.json generated
View File

@ -11,11 +11,13 @@
"dependencies": {
"@11ty/eleventy-plugin-rss": "^1.2.0",
"feather-icons": "^4.29.0",
"image-size": "^1.0.2",
"markdown-it-anchor": "^8.6.7",
"markdown-it-table-of-contents": "^0.6.0",
"normalize.css": "^8.0.1",
"nunjucks-date": "^1.5.0",
"prism-themes": "^1.9.0"
"prism-themes": "^1.9.0",
"sync-fetch": "^0.5.2"
},
"devDependencies": {
"@11ty/eleventy": "^2.0.0",
@ -1190,6 +1192,20 @@
"node": ">= 0.10"
}
},
"node_modules/image-size": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz",
"integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==",
"dependencies": {
"queue": "6.0.2"
},
"bin": {
"image-size": "bin/image-size.js"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@ -1203,8 +1219,7 @@
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/is-alphabetical": {
"version": "1.0.4",
@ -1729,6 +1744,25 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@ -2089,6 +2123,14 @@
"integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==",
"dev": true
},
"node_modules/queue": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
"integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
"dependencies": {
"inherits": "~2.0.3"
}
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -2374,6 +2416,17 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/sync-fetch": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.5.2.tgz",
"integrity": "sha512-6gBqqkHrYvkH65WI2bzrDwrIKmt3U10s4Exnz3dYuE5Ah62FIfNv/F63inrNhu2Nyh3GH5f42GKU3RrSJoaUyQ==",
"dependencies": {
"node-fetch": "^2.6.1"
},
"engines": {
"node": ">=14"
}
},
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@ -2401,6 +2454,11 @@
"integrity": "sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ=",
"dev": true
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
@ -2437,6 +2495,20 @@
"node": ">=0.10.0"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@ -3362,6 +3434,14 @@
"resolved": "https://registry.npmjs.org/http-equiv-refresh/-/http-equiv-refresh-1.0.0.tgz",
"integrity": "sha512-TScO04soylRN9i/QdOdgZyhydXg9z6XdaGzEyOgDKycePeDeTT4KvigjBcI+tgfTlieLWauGORMq5F1eIDa+1w=="
},
"image-size": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz",
"integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==",
"requires": {
"queue": "6.0.2"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@ -3375,8 +3455,7 @@
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"is-alphabetical": {
"version": "1.0.4",
@ -3773,6 +3852,14 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true
},
"node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"requires": {
"whatwg-url": "^5.0.0"
}
},
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@ -4077,6 +4164,14 @@
"integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==",
"dev": true
},
"queue": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
"integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
"requires": {
"inherits": "~2.0.3"
}
},
"queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -4269,6 +4364,14 @@
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true
},
"sync-fetch": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.5.2.tgz",
"integrity": "sha512-6gBqqkHrYvkH65WI2bzrDwrIKmt3U10s4Exnz3dYuE5Ah62FIfNv/F63inrNhu2Nyh3GH5f42GKU3RrSJoaUyQ==",
"requires": {
"node-fetch": "^2.6.1"
}
},
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@ -4290,6 +4393,11 @@
"integrity": "sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ=",
"dev": true
},
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
@ -4314,6 +4422,20 @@
"integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=",
"dev": true
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@ -21,10 +21,12 @@
"dependencies": {
"@11ty/eleventy-plugin-rss": "^1.2.0",
"feather-icons": "^4.29.0",
"image-size": "^1.0.2",
"markdown-it-anchor": "^8.6.7",
"markdown-it-table-of-contents": "^0.6.0",
"normalize.css": "^8.0.1",
"nunjucks-date": "^1.5.0",
"prism-themes": "^1.9.0"
"prism-themes": "^1.9.0",
"sync-fetch": "^0.5.2"
}
}

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -10,8 +10,7 @@ The `<dl>` element is useful for displaying metadata or a read only version of a
These are some basic styles to use by default:
<img src="/img/BasicDescriptionList.png" alt="Basic Description List Styles"
width="186" height="152" />
![Basic Description List Styles](/img/BasicDescriptionList_2x.png)
```html
<dl>
@ -52,8 +51,7 @@ dd + dd {
This styling will put the `<dt>` elements in one column and the `<dd>` elements into another. This can cause issues on small screens, so it supports breakpoints where it will fall back to the default style.
<img src="/img/ColumnsDescriptionList.png" alt="Side-By-Side Columns Description List Styles"
width="242" height="153" />
![Side-By-Side Columns Description List Styles](/img/ColumnsDescriptionList_2x.png)
```html
<dl class="dl-columns-tablet">
@ -125,8 +123,7 @@ $wsu-breakpoint-map: (
You can also mix this with the default stacked style:
<img src="/img/MixedDescriptionList.png" alt="Mixed Description List Styles"
width="252" height="160" />
![Mixed Description List Styles](/img/MixedDescriptionList_2x.png)
```html
<dl class="dl-columns-phone">
@ -150,8 +147,7 @@ You can also mix this with the default stacked style:
This styling is for a list of links with a description. This is particularly useful for index pages that have an actual list of pages:
<img src="/img/IndexDescriptionList.png" alt="Mixed Description List Styles"
width="261" height="129" />
![Index Description List](/img/IndexDescriptionList_2x.png)
```html
<dl class="index-list">