diff --git a/content/blog/2024-10-11_example_post.md b/content/blog/2024-10-11_example_post.md index d82b8bf..8f33df4 100644 --- a/content/blog/2024-10-11_example_post.md +++ b/content/blog/2024-10-11_example_post.md @@ -158,3 +158,5 @@ You can also create `
` horizontal rule tags using `---` in markdown, like so --- But these should be used sparingly, if at all. + +You can also use emojis inline from the hackclub slack like this :yay:! This is just done by writing `:emoji:` and it gets progressively enhanced with a bit of js as long as the emoji is in cachet! diff --git a/sass/css/_emoji-inline.scss b/sass/css/_emoji-inline.scss new file mode 100644 index 0000000..09988f5 --- /dev/null +++ b/sass/css/_emoji-inline.scss @@ -0,0 +1,32 @@ +.emoji-inline--wrapper { + vertical-align: baseline; + height: auto; + position: relative; + overflow: visible; + vertical-align: top; + object-fit: contain; + align-items: center; + display: inline-flex; + overflow: hidden; + width: 22px; + height: 22px; +} + +.emoji-inline--wrapper img { + object-fit: contain; + position: absolute; + top: 50%; + overflow: hidden; + width: 22px !important; + height: 22px !important; + margin-top: -11px; + margin-left: 0 !important; + margin-right: 0 !important; + margin-bottom: 0 !important; + border: none !important; + border-radius: 0 !important; + padding: 0 !important; + opacity: 1 !important; + max-width: 22px !important; + display: inline !important; +} diff --git a/sass/css/main.scss b/sass/css/main.scss index 304b64c..15f20a8 100644 --- a/sass/css/main.scss +++ b/sass/css/main.scss @@ -6,3 +6,4 @@ @use "copy-button"; @use "view-transitions"; +@use "emoji-inline"; diff --git a/static/js/emoji-replace.js b/static/js/emoji-replace.js new file mode 100644 index 0000000..6f4c7d2 --- /dev/null +++ b/static/js/emoji-replace.js @@ -0,0 +1,65 @@ +document.addEventListener("DOMContentLoaded", () => { + const content = document.querySelector("main"); + if (!content) return; + + const walker = document.createTreeWalker(content, NodeFilter.SHOW_TEXT, { + acceptNode: (node) => { + // Skip code blocks, pre tags, and script/style tags + let parent = node.parentElement; + while (parent) { + const tag = parent.tagName.toLowerCase(); + if ( + tag === "code" || + tag === "pre" || + tag === "script" || + tag === "style" + ) { + return NodeFilter.FILTER_REJECT; + } + parent = parent.parentElement; + } + return NodeFilter.FILTER_ACCEPT; + }, + }); + + const nodesToReplace = []; + while (walker.nextNode()) { + const node = walker.currentNode; + if (/:[\w-]+:/.test(node.textContent)) { + nodesToReplace.push(node); + } + } + + nodesToReplace.forEach((node) => { + const frag = document.createDocumentFragment(); + const parts = node.textContent.split(/(:[\w-]+:)/); + + parts.forEach((part) => { + if (/^:[\w-]+:$/.test(part)) { + const name = part.slice(1, -1); + + const span = document.createElement("span"); + span.className = "emoji-inline--wrapper"; + + const img = document.createElement("img"); + img.src = `https://cachet.dunkirk.sh/emojis/${name}/r`; + img.alt = part; + img.className = "emoji-inline"; + img.loading = "lazy"; + img.setAttribute("aria-label", `${name} emoji`); + + // Fallback: if image fails to load, show original text + img.onerror = () => { + span.replaceWith(document.createTextNode(part)); + }; + + span.appendChild(img); + frag.appendChild(span); + } else if (part) { + frag.appendChild(document.createTextNode(part)); + } + }); + + node.replaceWith(frag); + }); +}); diff --git a/templates/head.html b/templates/head.html index 0a074bf..61b1339 100644 --- a/templates/head.html +++ b/templates/head.html @@ -86,6 +86,13 @@ base64=true) %} defer > +{% set emojiJsHash = get_hash(path="js/emoji-replace.js", sha_type=256, +base64=true) %} + +