diff --git a/eleventy.config.js b/eleventy.config.js
index 98afeae..3936499 100644
--- a/eleventy.config.js
+++ b/eleventy.config.js
@@ -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) {
diff --git a/markdown-it-image-size.js b/markdown-it-image-size.js
new file mode 100644
index 0000000..c20541e
--- /dev/null
+++ b/markdown-it-image-size.js
@@ -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 ``;
+ };
+}
+
+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;
diff --git a/package-lock.json b/package-lock.json
index ebcc674..01448a8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 8719bd3..93421ff 100644
--- a/package.json
+++ b/package.json
@@ -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"
}
}
diff --git a/src/img/BasicDescriptionList.png b/src/img/BasicDescriptionList_2x.png
similarity index 100%
rename from src/img/BasicDescriptionList.png
rename to src/img/BasicDescriptionList_2x.png
diff --git a/src/img/ColumnsDescriptionList.png b/src/img/ColumnsDescriptionList_2x.png
similarity index 100%
rename from src/img/ColumnsDescriptionList.png
rename to src/img/ColumnsDescriptionList_2x.png
diff --git a/src/img/IndexDescriptionList.png b/src/img/IndexDescriptionList_2x.png
similarity index 100%
rename from src/img/IndexDescriptionList.png
rename to src/img/IndexDescriptionList_2x.png
diff --git a/src/img/MixedDescriptionList.png b/src/img/MixedDescriptionList_2x.png
similarity index 100%
rename from src/img/MixedDescriptionList.png
rename to src/img/MixedDescriptionList_2x.png
diff --git a/src/posts/DescriptionListStyling.md b/src/posts/DescriptionListStyling.md
index 181f1d9..2e97b06 100644
--- a/src/posts/DescriptionListStyling.md
+++ b/src/posts/DescriptionListStyling.md
@@ -10,8 +10,7 @@ The `