Working with smaller chunks of thoughts; adding anchors to paragraphs in Org Mode HTML export
| org, jsI write my blog posts in Org Mode and export them to Eleventy with ox-11ty, which is derived from the ox-html backend.
Sometimes I want to link to something in a different blog post. This lets me build on thoughts that are part of a post instead of being a whole post on their own.
If I haven't added an anchor to the blog post yet,
I can add one so that I can link to that section.
For really old posts where I don't have an Org
source file, I can edit the HTML file directly and
add an id="some-id"
so that I can link to it
with /url/to/post#some-id
. Most of my new posts
have Org source, though. I have a
my-blog-edit-org
function and a
my-blog-edit-html
function in my Emacs
configuration to make it easier to jump to the Org
file or HTML for a blog post.
If the section has a heading, then it's easy to
make that linkable with a custom name. I can use
org-set-property
to set the CUSTOM_ID
property
to the anchor name. For example, this voice access
section has a heading that has CUSTOM_ID
, as you
can see in the . If I don't mind having
long anchor names, I can use the
my-assign-custom-ids
function from my config to
automatically set them based on the outline path.
my-assign-custom-ids
(defun my-assign-custom-ids () (interactive) (let ((custom-ids (org-map-entries (lambda () (org-entry-get (point) "CUSTOM_ID")) "CUSTOM_ID={.}"))) (org-map-entries (lambda () (let ((slug (replace-regexp-in-string "^-\\|-$" "" (replace-regexp-in-string "[^A-Za-z0-9]+" "-" (downcase (string-join (org-get-outline-path t) " ")))))) (while (member slug custom-ids) (setq slug (read-string "Manually set custom ID: "))) (org-entry-put (point) "CUSTOM_ID" slug))) "-CUSTOM_ID={.}")))
Adding anchors to paragraphs
If the part that I want to link to is not a
heading, I can add an ID by using the
#+ATTR_HTML: :id ...
directive, like this snippet from my reflection on landscapes and art:
That reminds me a little of another reflection
I've been noodling around on interest development...
Anchor links
It might be fun to have a little margin note with 🔗 to indicate that that's a specially-linkable section, which could be handy when I want to link when mobile. It feels like that would be a left margin thing on a large screen, so it'll just have to squeeze in there with the sticky table of contents. I've been meaning to add link icons to sub-headings with IDs, anyway, so I can probably solve both with a bit of Javascript.
/* Add link icons to headings and anchored paragraphs */ function addLinkIcons() { document.querySelectorAll('h1[id], h2[id], h3[id], p[id]').forEach((o) => { const link = document.createElement('a'); const article = o.closest('article[data-url]'); link.href = window.location.origin + (article?.getAttribute('data-url') || window.location.pathname) + '#' + o.getAttribute('id'); link.innerHTML = '🔗'; // link icon link.title = 'anchor'; link.classList.add('anchor-icon'); link.addEventListener('click', copyLink); o.prepend(link); }); } addLinkIcons();
And some CSS:
.entry h2, .entry h3, .entry h4, .entry p, .content h2, .content h3, .content h4, .content p { position: relative } .content a.anchor-icon:link, .entry a.anchor-icon:link { font-size: 60%; text-decoration: none !important; font-size: small; float: right } @media only screen and (min-width: 95rem) { .content a.anchor-icon:link, .entry a.anchor-icon:link { display: block; position: absolute; left: -2em; top: 0.2em; float: none} }
Text fragments
Text fragments are even more powerful, because I
can link to a specific part of a paragraph. I can
link to one segment with something like
#:
:text=text+to+highlight~. I can specify
multiple text fragments to highlight by using
#:
:text=first+text+to+highlight&text=second+text~,
and the browser will automatically scroll to the
first highlighted section. I can specify a longer
section by using text=textStart,textEnd. Example:
#:~:text=That%20is%20the%20gap,described The text
fragments documentation has more options,
including using prefixes and suffixes to
disambiguate matches.
Text fragment links require rel="noopener"
for
security, so I added
JKC-Codes/eleventy-plugin-automatic-noopener to my
11ty config.
If I find myself using this a lot, it might be interesting to figure out how to make it easier, maybe with something like the Text Fragment extension for Firefox.
These seem like good starting points for addressing smaller chunks of thoughts.