From 1c3c777a1e57ca819c8630715d3e767e8870248b Mon Sep 17 00:00:00 2001 From: Zach Leatherman Date: Tue, 16 Jul 2024 15:45:08 -0500 Subject: [PATCH] Swap to use IdAttributePlugin instead of markdown-it-anchor --- _includes/layouts/base.njk | 7 ++++++- eleventy.config.js | 39 ++++++++++++++++++++---------------- package.json | 3 +-- public/css/index.css | 16 +++++++-------- public/js/heading-anchors.js | 37 ++++++++++++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 public/js/heading-anchors.js diff --git a/_includes/layouts/base.njk b/_includes/layouts/base.njk index 4814c79..8b7eea6 100644 --- a/_includes/layouts/base.njk +++ b/_includes/layouts/base.njk @@ -32,6 +32,8 @@ {#- Renders the CSS bundle using a separate file, if you can't set CSP directive style-src: 'unsafe-inline' #} {#- #} + + {%- js %}{% include "public/js/heading-anchors.js" %}{% endjs %} Skip to main content @@ -51,7 +53,9 @@
- {{ content | safe }} + + {{ content | safe }} +
+ diff --git a/eleventy.config.js b/eleventy.config.js index 45326ee..753bba8 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -1,6 +1,4 @@ -import markdownItAnchor from "markdown-it-anchor"; - -import { InputPathToUrlTransformPlugin, HtmlBasePlugin } from "@11ty/eleventy"; +import { IdAttributePlugin, InputPathToUrlTransformPlugin, HtmlBasePlugin } from "@11ty/eleventy"; import { feedPlugin } from "@11ty/eleventy-plugin-rss"; import pluginSyntaxHighlight from "@11ty/eleventy-plugin-syntaxhighlight"; import pluginNavigation from "@11ty/eleventy-navigation"; @@ -28,8 +26,8 @@ export default async function(eleventyConfig) { // Per-page bundles, see https://github.com/11ty/eleventy-plugin-bundle // Adds the {% css %} paired shortcode eleventyConfig.addBundle("css"); - // Do you want a {% js %} bundle shortcode too? - // eleventyConfig.addBundle("js"); + // Adds the {% js %} paired shortcode + eleventyConfig.addBundle("js"); // Official plugins eleventyConfig.addPlugin(pluginSyntaxHighlight, { @@ -84,20 +82,27 @@ export default async function(eleventyConfig) { // Filters eleventyConfig.addPlugin(pluginFilters); - // Customize Markdown library settings: - eleventyConfig.amendLibrary("md", mdLib => { - mdLib.use(markdownItAnchor, { - permalink: markdownItAnchor.permalink.ariaHidden({ - placement: "after", - class: "header-anchor", - symbol: "#", - ariaHidden: false, - }), - level: [1,2,3,4], - slugify: eleventyConfig.getFilter("slugify") - }); + eleventyConfig.addPlugin(IdAttributePlugin, { + // by default we use Eleventy’s built-in `slugify` filter: + // slugify: eleventyConfig.getFilter("slugify"), + // default: + // selector: "h1,h2,h3,h4,h5,h6", }); + // Customize Markdown library settings: + // eleventyConfig.amendLibrary("md", mdLib => { + // mdLib.use(markdownItAnchor, { + // permalink: markdownItAnchor.permalink.ariaHidden({ + // placement: "after", + // class: "header-anchor", + // symbol: "#", + // ariaHidden: false, + // }), + // level: [1,2,3,4], + // slugify: eleventyConfig.getFilter("slugify") + // }); + // }); + eleventyConfig.addShortcode("currentBuildDate", () => { return (new Date()).toISOString(); }); diff --git a/package.json b/package.json index ec9f28f..d25756c 100644 --- a/package.json +++ b/package.json @@ -35,14 +35,13 @@ }, "homepage": "https://github.com/11ty/eleventy-base-blog#readme", "devDependencies": { - "@11ty/eleventy": "3.0.0-alpha.16", + "@11ty/eleventy": "3.0.0-alpha.17", "@11ty/eleventy-img": "5.0.0-beta.5", "@11ty/eleventy-navigation": "^0.3.5", "@11ty/eleventy-plugin-rss": "2.0.0-beta.8", "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0", "cross-env": "^7.0.3", "luxon": "^3.4.4", - "markdown-it-anchor": "^8.6.7", "zod": "^3.23.8", "zod-validation-error": "^3.3.0" } diff --git a/public/css/index.css b/public/css/index.css index f38dda1..c48c8e4 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -257,25 +257,25 @@ header { } /* Direct Links / Markdown Headers */ -.header-anchor { +.heading-anchor { text-decoration: none; font-style: normal; font-size: 1em; margin-left: .1em; } -a[href].header-anchor, -a[href].header-anchor:visited { +a[href].heading-anchor, +a[href].heading-anchor:visited { color: transparent; } -a[href].header-anchor:focus, -a[href].header-anchor:hover { +a[href].heading-anchor:focus, +a[href].heading-anchor:hover { text-decoration: underline; } -a[href].header-anchor:focus, -:hover > a[href].header-anchor { +a[href].heading-anchor:focus, +:hover > a[href].heading-anchor { color: #aaa; } -h2 + .header-anchor { +h2 + .heading-anchor { font-size: 1.5em; } diff --git a/public/js/heading-anchors.js b/public/js/heading-anchors.js new file mode 100644 index 0000000..0c1b706 --- /dev/null +++ b/public/js/heading-anchors.js @@ -0,0 +1,37 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors + +class HeadingAnchors extends HTMLElement { + static register(tagName) { + if ("customElements" in window) { + customElements.define(tagName || "heading-anchors", HeadingAnchors); + } + } + + connectedCallback() { + this.headings.forEach((heading) => { + if(!heading.querySelector("a.direct-link") || heading.hasAttribute("data-heading-anchors-optout")) { + heading.append(this.anchor(heading)); + } + }); + } + + anchor(heading) { + // TODO this would be good use case for shadow dom + let anchor = document.createElement("a"); + anchor.setAttribute("data-pagefind-ignore", ""); + anchor.href = `#${heading.id}`; + anchor.classList.add("heading-anchor"); + anchor.innerHTML = `Jump to heading`; + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || "h1,h2,h3,h4" + } +} + +HeadingAnchors.register();