Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,17 @@ Before contributing, please read the following:
### Contributors

- [Ferretosan](https://github.com/ferretosan)
- [proplayer919](https://github.com/proplayer919)
- [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 <https://github.com/apps/utterances> 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/<filename>` (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.
59 changes: 59 additions & 0 deletions js/markdown-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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/<filename>" as the stable, deterministic issue title per post
const postId = 'blog/' + filename;
injectUtterances(comments, postId);
}
}, 100); // Small delay to ensure popup is fully rendered

Expand Down
18 changes: 18 additions & 0 deletions style/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down