diff --git a/README.md b/README.md index c33504f..54818ff 100644 --- a/README.md +++ b/README.md @@ -18,4 +18,17 @@ Before contributing, please read the following: ### Contributors - [Ferretosan](https://github.com/ferretosan) -- [proplayer919](https://github.com/proplayer919) \ No newline at end of file +- [proplayer919](https://github.com/proplayer919) + +## Blog Comments (Utterances) + +Blog posts display a **Comments** section powered by [Utterances](https://utteranc.es/), which stores comments as GitHub Issues in [`Ferretosan/web-blog-comments`](https://github.com/Ferretosan/web-blog-comments) — no ads, no tracking beyond GitHub. + +### Setup + +1. **Install the Utterances GitHub App** on the `Ferretosan/web-blog-comments` repository: + - Visit and grant access to `Ferretosan/web-blog-comments`. +2. **Ensure the repo is public** — Utterances requires a public repository to create and read issues. +3. The embed is already wired up in `js/markdown-parser.js`. Each blog post gets its own GitHub Issue titled `blog/` (e.g. `blog/newyear26.md`), providing a stable, deterministic mapping regardless of URL changes. +4. To change the comment theme, update `UTTERANCES_THEME` at the top of `js/markdown-parser.js`. Available themes: `github-light`, `github-dark`, `preferred-color-scheme`, `github-dark-orange`, `icy-dark`, `dark-blue`, `photon-dark`, `boxy-light`, `catppuccin-mocha`. +5. **Permissions** — users must have a GitHub account and authorize Utterances via OAuth to post comments. Read-only viewing works without login. \ No newline at end of file diff --git a/js/markdown-parser.js b/js/markdown-parser.js index 9bed2f7..859e025 100644 --- a/js/markdown-parser.js +++ b/js/markdown-parser.js @@ -5,6 +5,52 @@ // markdown-parser.js - Simple Markdown to HTML parser // by Ferretosan !!!! +// --------------------------------------------------------------------------- +// Utterances comments configuration +// Utterances stores comments as GitHub Issues in the repo below. +// The repo must be public and have the Utterances GitHub App installed: +// https://github.com/apps/utterances +// Available themes: github-light, github-dark, preferred-color-scheme, +// github-dark-orange, icy-dark, dark-blue, photon-dark, boxy-light, +// catppuccin-mocha +// --------------------------------------------------------------------------- +const UTTERANCES_REPO = 'Ferretosan/web-blog-comments'; +const UTTERANCES_THEME = 'photon-dark'; + +// Inject (or replace) the Utterances widget inside targetEl. +// postId is used as the issue title so each post gets its own stable thread. +function injectUtterances(targetEl, postId) { + if (!targetEl) return; + + // Remove any existing Utterances iframe/container when switching posts + const existing = targetEl.querySelector('.utterances'); + if (existing) existing.remove(); + + // Use document.title to pass the stable postId to Utterances (issue-term="title"). + // We set it briefly while the script loads, then restore the original title. + const originalTitle = document.title; + document.title = postId; + + const s = document.createElement('script'); + s.src = 'https://utteranc.es/client.js'; + s.async = true; + s.crossOrigin = 'anonymous'; + s.setAttribute('repo', UTTERANCES_REPO); + s.setAttribute('issue-term', 'title'); + s.setAttribute('theme', UTTERANCES_THEME); + s.setAttribute('label', 'blog-comment'); + + // Restore the original page title after Utterances has read it. + s.addEventListener('load', function() { + document.title = originalTitle; + }); + s.addEventListener('error', function() { + document.title = originalTitle; + }); + + targetEl.appendChild(s); +} + function parseMarkdown(markdown) { let html = markdown; @@ -125,6 +171,19 @@ async function loadBlogPost(filename) { // Observe all animated elements in the popup const animatedElements = popupContent.querySelectorAll('.fade-in, .slide-in-left, .slide-in-right, .scale-in'); animatedElements.forEach(el => observer.observe(el)); + + // Append comments section and inject Utterances widget + const comments = document.createElement('div'); + comments.id = 'utterances-container'; + const heading = document.createElement('h2'); + heading.className = 'slide-in-right'; + heading.textContent = 'Comments'; + comments.appendChild(heading); + popupContent.appendChild(comments); + + // Use "blog/" as the stable, deterministic issue title per post + const postId = 'blog/' + filename; + injectUtterances(comments, postId); } }, 100); // Small delay to ensure popup is fully rendered diff --git a/style/popup.css b/style/popup.css index 5361596..4b71334 100644 --- a/style/popup.css +++ b/style/popup.css @@ -322,6 +322,24 @@ html.popup-open { bottom: 70px; /* 20px + 40px height + 10px gap */ } +/* Utterances comments embed */ +#utterances-container { + margin-top: 40px; + border-top: 3px solid #6d28d9; + padding-top: 10px; +} + +#utterances-container .utterances { + max-width: 100% !important; + width: 100% !important; +} + +#utterances-container .utterances-frame { + width: 100% !important; + min-width: unset !important; + box-sizing: border-box; +} + /* Image mode (unified image modal styling) */ #popup-overlay.image-mode { background: rgba(26, 11, 26, 0.97);