395 lines
No EOL
103 KiB
HTML
395 lines
No EOL
103 KiB
HTML
<!doctype html><html lang=en dir=auto><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name=robots content="noindex, nofollow"><title>New features for my blog! Adding Comments + RSS to Hugo PaperMod (Giscus and Isso FTW) | AlipourIm journeys</title>
|
||
<meta name=keywords content="hugo,papermod,giscus,rss,comments"><meta name=description content="A friendly, copy-pasteable guide to wiring up Giscus comments (GitHub Discussions) and Isso comments + RSS in Hugo PaperMod."><meta name=author content="Iman Alipour"><link rel=canonical href=https://blog.alipour.eu/posts/comments-rss-papermod/><link crossorigin=anonymous href=/assets/css/stylesheet.31b150d909186c48d6dbbf653acc2489945fa9ac2c8f8cd3fe8448e89e40fccf.css integrity="sha256-MbFQ2QkYbEjW279lOswkiZRfqawsj4zT/oRI6J5A/M8=" rel="preload stylesheet" as=style><link rel=icon href=https://blog.alipour.eu/favicon.ico><link rel=icon type=image/png sizes=16x16 href=https://blog.alipour.eu/favicon-16x16.png><link rel=icon type=image/png sizes=32x32 href=https://blog.alipour.eu/favicon-32x32.png><link rel=apple-touch-icon href=https://blog.alipour.eu/apple-touch-icon.png><link rel=mask-icon href=https://blog.alipour.eu/safari-pinned-tab.svg><meta name=theme-color content="#2e2e33"><meta name=msapplication-TileColor content="#2e2e33"><link rel=alternate hreflang=en href=https://blog.alipour.eu/posts/comments-rss-papermod/><noscript><style>#theme-toggle,.top-link{display:none}</style><style>@media(prefers-color-scheme:dark){:root{--theme:rgb(29, 30, 32);--entry:rgb(46, 46, 51);--primary:rgb(218, 218, 219);--secondary:rgb(155, 156, 157);--tertiary:rgb(65, 66, 68);--content:rgb(196, 196, 197);--code-block-bg:rgb(46, 46, 51);--code-bg:rgb(55, 56, 62);--border:rgb(51, 51, 51)}.list{background:var(--theme)}.list:not(.dark)::-webkit-scrollbar-track{background:0 0}.list:not(.dark)::-webkit-scrollbar-thumb{border-color:var(--theme)}}</style></noscript><script>(function(){window.goatcounter={endpoint:"/count"};const e=document.createElement("script");e.async=!0,e.src="/js/count.js",document.head.appendChild(e)})()</script><script>(function(){const s="",t=new Intl.NumberFormat,o="visit",i="visits";function a(e){document.readyState==="complete"||document.readyState==="interactive"?setTimeout(e,0):document.addEventListener("DOMContentLoaded",e)}function r(){try{return window.goatcounter&&window.goatcounter.get_data?window.goatcounter.get_data().p:location.pathname}catch{return location.pathname}}async function e(e,t){try{const o=new URLSearchParams({t:String(Date.now())});t&&o.set("start",t);const a=`${s}/counter/${encodeURIComponent(e)}.json?${o}`,n=await fetch(a,{credentials:"omit"});if(n.status===404)return 0;if(!n.ok)throw 0;const r=await n.json(),i=Number(String(r.count).replace(/,/g,""));return Number.isFinite(i)?i:0}catch{return null}}const n=e=>e===null?"—":`${t.format(e)} ${e===1?o:i}`;a(async function(){const s=document.querySelector(".post-single");if(s){const t=s.querySelector(".post-header .post-meta, .post-header .entry-meta, .post-meta"),o=await e(r());if(t){let e=t.querySelector(".post-views");e||(e=document.createElement("span"),e.className="post-views",t.appendChild(e)),e.textContent=n(o??0)}}const i=document.querySelectorAll("article.post-entry");await Promise.all(Array.from(i).map(async t=>{const s=t.querySelector(".entry-footer, .post-meta"),o=t.querySelector("a.entry-link, h2 a, .entry-title a");if(!s||!o)return;try{const i=new URL(o.getAttribute("href"),location.origin);if(i.origin!==location.origin)return;let t=s.querySelector(".post-views");t||(t=document.createElement("span"),t.className="post-views",s.appendChild(t)),t.textContent=n(await e(i.pathname)??0)}catch{}}));const o=document.getElementById("gc_site_visitors_week");if(o){const n=await e("TOTAL","week");o.textContent=n===null?"—":t.format(n)}})})()</script></head><body id=top><script>localStorage.getItem("pref-theme")==="dark"?document.body.classList.add("dark"):localStorage.getItem("pref-theme")==="light"?document.body.classList.remove("dark"):window.matchMedia("(prefers-color-scheme: dark)").matches&&document.body.classList.add("dark")</script><header class=header><nav class=nav><div class=logo><a href=https://blog.alipour.eu/ accesskey=h title="AlipourIm journeys (Alt + H)">AlipourIm journeys</a><div class=logo-switches><button id=theme-toggle accesskey=t title="(Alt + T)" aria-label="Toggle theme"><svg id="moon" width="24" height="18" viewBox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg><svg id="sun" width="24" height="18" viewBox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg></button></div></div><ul id=menu><li><a href=https://blog.alipour.eu/posts/ title=Posts><span>Posts</span></a></li><li><a href=https://blog.alipour.eu/phd_journey/ title=PhD_journey><span>PhD_journey</span></a></li><li><a href=https://blog.alipour.eu/about/ title=About><span>About</span></a></li></ul></nav></header><main class=main><article class=post-single><header class=post-header><div class=breadcrumbs><a href=https://blog.alipour.eu/>Home</a> » <a href=https://blog.alipour.eu/posts/>Posts</a></div><h1 class="post-title entry-hint-parent">New features for my blog! Adding Comments + RSS to Hugo PaperMod (Giscus and Isso FTW)</h1><div class=post-description>A friendly, copy-pasteable guide to wiring up Giscus comments (GitHub Discussions) and Isso comments + RSS in Hugo PaperMod.</div><div class=post-meta><span title='2025-10-23 19:31:12 +0200 +0200'>October 23, 2025</span> · 15 min · Iman Alipour
|
||
<span class=post-meta-item><a href=https://blog.alipour.eu/posts/comments-rss-papermod/#isso-thread class=isso-comments-link>Comments</a></span></div></header><div class=toc><details open><summary accesskey=c title="(Alt + C)"><span class=details>Table of Contents</span></summary><div class=inner><ul><ul><li><a href=#why-i-chose-giscus-instead-of-disqus aria-label="Why I chose Giscus (instead of Disqus)">Why I chose Giscus (instead of Disqus)</a></li><li><a href=#what-you-need-for-your-site-not-per-user aria-label="What you need (for your site, not per user)">What you need (for your site, not per user)</a></li><li><a href=#1-turn-on-comments-with-giscus aria-label="1) Turn on comments with Giscus">1) Turn on comments with Giscus</a><ul><li><a href=#11-enable-comments-globally aria-label="1.1 Enable comments globally">1.1 Enable comments globally</a></li><li><a href=#12-create-the-comments-partial aria-label="1.2 Create the comments partial">1.2 Create the comments partial</a></li></ul></li><li><a href=#2-enable-rss-home--sections aria-label="2) Enable RSS (home + sections)">2) Enable RSS (home + sections)</a></li><li><a href=#3-show-an-rss-button-on-the-home-page aria-label="3) Show an RSS button on the home page">3) Show an RSS button on the home page</a><ul><li><a href=#option-a--use-the-home-social-icons-row aria-label="Option A — Use the home “social icons” row">Option A — Use the home “social icons” row</a></li><li><a href=#option-b--add-an-icon-in-the-footer-theme-safe aria-label="Option B — Add an icon in the footer (theme-safe)">Option B — Add an icon in the footer (theme-safe)</a></li></ul></li><li><a href=#4-verify-everything aria-label="4) Verify everything">4) Verify everything</a></li><li><a href=#5-per-post-controls-handy-later aria-label="5) Per-post controls (handy later)">5) Per-post controls (handy later)</a></li><li><a href=#6-troubleshooting-aka-what-i-bumped-into aria-label="6) Troubleshooting (aka “what I bumped into”)">6) Troubleshooting (aka “what I bumped into”)</a></li><li><a href=#7-bonus-fast-setup-via-github-cli-optional-i-didnt-use-it-but-i-shouldve-perhaps aria-label="7) Bonus: fast setup via GitHub CLI (optional, I didn’t use it, but I should’ve perhaps)">7) Bonus: fast setup via GitHub CLI (optional, I didn’t use it, but I should’ve perhaps)</a><ul><li><a href=#final-config-snapshot-condensed aria-label="Final config snapshot (condensed)">Final config snapshot (condensed)</a></li></ul></li></ul><li><a href=#appendix--why-i-added-isso-how-i-wired-it-and-what-i-fixed aria-label="Appendix — Why I added Isso, how I wired it, and what I fixed">Appendix — Why I added Isso, how I wired it, and what I fixed</a><ul><li><a href=#the-story-why-isso--why-i-still-keep-giscus aria-label="The story (why Isso + why I still keep Giscus)">The story (why Isso + why I still keep Giscus)</a></li><li><a href=#how-i-run-it-high-level aria-label="How I run it (high-level)">How I run it (high-level)</a></li><li><a href=#hugo-partial-switcher--embeds aria-label="Hugo partial: switcher + embeds">Hugo partial: switcher + embeds</a></li><li><a href=#nginx-proxy-isso-on-both-sites-and-avoid-the-404-onion-trap aria-label="Nginx: proxy Isso on both sites (and avoid the 404-onion trap)">Nginx: proxy Isso on both sites (and avoid the 404-onion trap)</a></li><li><a href=#small-css-tweaks-one-color-across-lightdark--spacing aria-label="Small CSS tweaks (one color across light/dark + spacing)">Small CSS tweaks (one color across light/dark + spacing)</a></li><li><a href=#what-changed-the-fixes-i-actually-made aria-label="What changed (the fixes I actually made)">What changed (the fixes I actually made)</a></li><li><a href=#sanity-check aria-label="Sanity check">Sanity check</a></li><li><a href=#8-final-notes aria-label="8) Final notes!">8) Final notes!</a></li></ul></li><li><a href=#admin-note--delete-all-isso-comments-for-a-single-post aria-label="Admin note — Delete all Isso comments for a single post">Admin note — Delete all Isso comments for a single post</a><ul><li><a href=#tldr-host-with-sqlite aria-label="TL;DR (host with SQLite)">TL;DR (host with SQLite)</a></li><li><a href=#if-running-isso-in-docker aria-label="If running Isso in Docker">If running Isso in Docker</a></li><li><a href=#notes--gotchas aria-label="Notes & gotchas">Notes & gotchas</a></li><li><a href=#one-liners-for-the-impatient aria-label="One-liners for the impatient">One-liners for the impatient</a></li></ul></li></ul></div></details></div><div class=post-content><blockquote><p>Short story: I wanted comments and a proper RSS feed on my Hugo + PaperMod site.<br>Longer story: I spent 30 minutes poking around, and now you don’t have to. Here’s exactly what I did.</p></blockquote><hr><p>I’ve been wanting to add comment section to my blog for a while.
|
||
There are a few problems.</p><ul><li>I don’t want to get attacked by bots or random people for no reason.</li><li>I don’t want to allow weird things to happen.</li><li>I don’t want to have a database for it.</li></ul><p>So… I decided to take a path which is not necesserially the best.
|
||
It requires a third party to act on your behalf, but it is not as scary as it sounds.
|
||
According to Github:</p><blockquote><p><strong>What the app can do</strong>
|
||
The app’s rights are limited to the repo(s) where the site owner installed it and to the permissions it requested (basically: Discussions read/write + metadata). It can’t touch a commenter’s private repos or do things outside those scopes. GitHub’s docs also say a GitHub App can only do what both you and the app have permission to do.</p></blockquote><blockquote><p><strong>What “Act on your behalf” means</strong>
|
||
That scary wording is GitHub’s. The giscus maintainer explains it means “post comments under your username,” and shows that the app requests Discussions read/write + metadata when installed.</p></blockquote><blockquote><p><strong>Do commenters have alternatives?</strong>
|
||
Yes. Anyone can open the linked GitHub Discussion and comment directly on GitHub, bypassing the app’s OAuth popup. The README explicitly mentions this.</p></blockquote><blockquote><p><strong>Privacy & storage</strong>
|
||
No tracking/ads; comments live in GitHub Discussions. giscus is open-source and has a published privacy policy. You can also revoke the app any time in your GitHub settings.</p></blockquote><p>With the notice out of the way let’s dive right in!</p><hr><h2 id=why-i-chose-giscus-instead-of-disqus>Why I chose Giscus (instead of Disqus)<a hidden class=anchor aria-hidden=true href=#why-i-chose-giscus-instead-of-disqus>#</a></h2><ul><li><strong>No ads or trackers</strong> (my page weight thanks me).</li><li><strong>Uses GitHub Discussions</strong> (portable, transparent, easy to search).</li><li><strong>Readers log in with GitHub</strong> (no mystery auth popups).</li><li>In theory you can directly go to the repo’s discussion section and comment there!</li></ul><hr><h2 id=what-you-need-for-your-site-not-per-user>What you need (for your site, not per user)<a hidden class=anchor aria-hidden=true href=#what-you-need-for-your-site-not-per-user>#</a></h2><ul><li>A Hugo site using <strong>PaperMod</strong> ✅</li><li>A GitHub account ✅</li><li>A <strong>public</strong> repository for the discussion threads (I called mine <code>blog-comments</code>) with <strong>Discussions</strong> enabled ✅</li><li>Giscus app installed on that repo ✅</li></ul><p>If you like to keep your main site repo clean, use a separate one, e.g. <code>github-username/blog-comments</code>.</p><hr><h2 id=1-turn-on-comments-with-giscus>1) Turn on comments with Giscus<a hidden class=anchor aria-hidden=true href=#1-turn-on-comments-with-giscus>#</a></h2><p>PaperMod renders a <code>comments.html</code> partial when <code>params.comments = true</code>.<br>So we enable it in config and create the partial.</p><h3 id=11-enable-comments-globally>1.1 Enable comments globally<a hidden class=anchor aria-hidden=true href=#11-enable-comments-globally>#</a></h3><p><code>hugo.toml</code> (snippet)</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-toml data-lang=toml><span style=display:flex><span>[<span style=color:#a6e22e>params</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>comments</span> = <span style=color:#66d9ef>true</span>
|
||
</span></span></code></pre></div><p>You can still opt out per post with <code>comments = false</code> in front matter.</p><h3 id=12-create-the-comments-partial>1.2 Create the comments partial<a hidden class=anchor aria-hidden=true href=#12-create-the-comments-partial>#</a></h3><p>Create this file <strong>in your site</strong> (not inside the theme):</p><div class=mermaid>layouts/partials/comments.html</div><p>Paste the Giscus embed (swap the placeholders with yours from giscus.app):</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-html data-lang=html><span style=display:flex><span><<span style=color:#f92672>section</span> <span style=color:#a6e22e>id</span><span style=color:#f92672>=</span><span style=color:#e6db74>"comments"</span> <span style=color:#a6e22e>class</span><span style=color:#f92672>=</span><span style=color:#e6db74>"giscus"</span>>
|
||
</span></span><span style=display:flex><span> <<span style=color:#f92672>script</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>src</span><span style=color:#f92672>=</span><span style=color:#e6db74>"https://giscus.app/client.js"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data-repo</span><span style=color:#f92672>=</span><span style=color:#e6db74>"yourname/blog-comments"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data-repo-id</span><span style=color:#f92672>=</span><span style=color:#e6db74>"YOUR_REPO_ID"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data-category</span><span style=color:#f92672>=</span><span style=color:#e6db74>"Comments"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data-category-id</span><span style=color:#f92672>=</span><span style=color:#e6db74>"YOUR_CATEGORY_ID"</span> <span style=color:#960050;background-color:#1e0010><!</span><span style=color:#a6e22e>--</span> <span style=color:#a6e22e>Get</span> <span style=color:#a6e22e>them</span> <span style=color:#a6e22e>from</span> <span style=color:#a6e22e>Giscus</span><span style=color:#960050;background-color:#1e0010>'</span><span style=color:#a6e22e>s</span> <span style=color:#a6e22e>page</span><span style=color:#960050;background-color:#1e0010>!</span> <span style=color:#a6e22e>--</span>>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data</span><span style=color:#f92672>-</span><span style=color:#a6e22e>mapping</span><span style=color:#f92672>=</span><span style=color:#e6db74>"pathname"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data</span><span style=color:#f92672>-</span><span style=color:#a6e22e>strict</span><span style=color:#f92672>=</span><span style=color:#e6db74>"0"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data</span><span style=color:#f92672>-</span><span style=color:#a6e22e>reactions</span><span style=color:#f92672>-</span><span style=color:#a6e22e>enabled</span><span style=color:#f92672>=</span><span style=color:#e6db74>"1"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data</span><span style=color:#f92672>-</span><span style=color:#a6e22e>emit</span><span style=color:#f92672>-</span><span style=color:#a6e22e>metadata</span><span style=color:#f92672>=</span><span style=color:#e6db74>"0"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data</span><span style=color:#f92672>-</span><span style=color:#a6e22e>input</span><span style=color:#f92672>-</span><span style=color:#a6e22e>position</span><span style=color:#f92672>=</span><span style=color:#e6db74>"bottom"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data</span><span style=color:#f92672>-</span><span style=color:#a6e22e>theme</span><span style=color:#f92672>=</span><span style=color:#e6db74>"preferred_color_scheme"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data</span><span style=color:#f92672>-</span><span style=color:#a6e22e>lang</span><span style=color:#f92672>=</span><span style=color:#e6db74>"en"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data</span><span style=color:#f92672>-</span><span style=color:#a6e22e>loading</span><span style=color:#f92672>=</span><span style=color:#e6db74>"lazy"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>crossorigin</span><span style=color:#f92672>=</span><span style=color:#e6db74>"anonymous"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>async</span><span style=color:#f92672>></span>
|
||
</span></span><span style=display:flex><span> </<span style=color:#f92672>script</span>>
|
||
</span></span><span style=display:flex><span> <<span style=color:#f92672>noscript</span>>Enable JavaScript to view comments powered by Giscus.</<span style=color:#f92672>noscript</span>>
|
||
</span></span><span style=display:flex><span></<span style=color:#f92672>section</span>>
|
||
</span></span></code></pre></div><p><strong>Notes</strong></p><ul><li>You’ll get <code>repo-id</code> and <code>category-id</code> from <strong>giscus.app</strong> after picking your repo + category.</li><li><code>data-mapping="pathname"</code> works great for static sites.</li><li>Prefer a <strong>public</strong> repo so visitors can read discussions without friction.</li><li>Want a different language? Change <code>data-lang</code> (e.g., <code>de</code>, <code>fr</code>).</li></ul><hr><h2 id=2-enable-rss-home--sections>2) Enable RSS (home + sections)<a hidden class=anchor aria-hidden=true href=#2-enable-rss-home--sections>#</a></h2><p>Hugo already knows how to generate feeds; we just tell it where.</p><p><code>hugo.toml</code></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-toml data-lang=toml><span style=display:flex><span><span style=color:#a6e22e>baseURL</span> = <span style=color:#e6db74>"https://example.com/"</span> <span style=color:#75715e># set your production URL</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span>[<span style=color:#a6e22e>outputs</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>home</span> = [<span style=color:#e6db74>"HTML"</span>, <span style=color:#e6db74>"RSS"</span>, <span style=color:#e6db74>"JSON"</span>] <span style=color:#75715e># JSON is optional (e.g., for on-site search)</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>section</span> = [<span style=color:#e6db74>"HTML"</span>, <span style=color:#e6db74>"RSS"</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>taxonomy</span> = [<span style=color:#e6db74>"HTML"</span>, <span style=color:#e6db74>"RSS"</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>term</span> = [<span style=color:#e6db74>"HTML"</span>, <span style=color:#e6db74>"RSS"</span>]
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span>[<span style=color:#a6e22e>services</span>.<span style=color:#a6e22e>rss</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>limit</span> = <span style=color:#ae81ff>-1</span> <span style=color:#75715e># -1 = no cap; or set e.g. 20</span>
|
||
</span></span></code></pre></div><p><strong>Feed URLs</strong></p><ul><li>Home feed: <code>/index.xml</code> → <code>https://example.com/index.xml</code></li><li>Section feeds: <code>/posts/index.xml</code>, <code>/notes/index.xml</code>, etc. (folders are lowercase)</li></ul><blockquote><p>If you’re using a <code>.onion</code> address or staging domain, just set that in <code>baseURL</code>.<br>Locally, Hugo serves feeds at <code>http://localhost:1313/index.xml</code>.</p></blockquote><hr><h2 id=3-show-an-rss-button-on-the-home-page>3) Show an RSS button on the home page<a hidden class=anchor aria-hidden=true href=#3-show-an-rss-button-on-the-home-page>#</a></h2><p>PaperMod shows a nice RSS icon on <strong>section/taxonomy</strong> lists by default (when enabled), but not on the home page. Two options:</p><h3 id=option-a--use-the-home-social-icons-row>Option A — Use the home “social icons” row<a hidden class=anchor aria-hidden=true href=#option-a--use-the-home-social-icons-row>#</a></h3><p>This appears if you enable <strong>Home-Info</strong> or <strong>Profile</strong> mode:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-toml data-lang=toml><span style=display:flex><span>[<span style=color:#a6e22e>params</span>.<span style=color:#a6e22e>homeInfoParams</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>Title</span> = <span style=color:#e6db74>"Hello, internet!"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>Content</span> = <span style=color:#e6db74>"Notes, experiments, and occasional rabbit holes."</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span>[[<span style=color:#a6e22e>params</span>.<span style=color:#a6e22e>socialIcons</span>]]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>name</span> = <span style=color:#e6db74>"rss"</span> <span style=color:#75715e># lowercase matters</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>url</span> = <span style=color:#e6db74>"/index.xml"</span>
|
||
</span></span></code></pre></div><h3 id=option-b--add-an-icon-in-the-footer-theme-safe>Option B — Add an icon in the footer (theme-safe)<a hidden class=anchor aria-hidden=true href=#option-b--add-an-icon-in-the-footer-theme-safe>#</a></h3><p>Create:</p><div class=mermaid>layouts/partials/extend_footer.html</div><p>Paste:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-html data-lang=html><span style=display:flex><span><<span style=color:#f92672>a</span> <span style=color:#a6e22e>href</span><span style=color:#f92672>=</span><span style=color:#e6db74>"/index.xml"</span> <span style=color:#a6e22e>rel</span><span style=color:#f92672>=</span><span style=color:#e6db74>"alternate"</span> <span style=color:#a6e22e>type</span><span style=color:#f92672>=</span><span style=color:#e6db74>"application/rss+xml"</span> <span style=color:#a6e22e>title</span><span style=color:#f92672>=</span><span style=color:#e6db74>"RSS"</span> <span style=color:#a6e22e>class</span><span style=color:#f92672>=</span><span style=color:#e6db74>"rss-link"</span>>
|
||
</span></span><span style=display:flex><span> {{ partial "svg.html" (dict "name" "rss") }}
|
||
</span></span><span style=display:flex><span> <<span style=color:#f92672>span</span>>RSS</<span style=color:#f92672>span</span>>
|
||
</span></span><span style=display:flex><span></<span style=color:#f92672>a</span>>
|
||
</span></span></code></pre></div><p>Make it a sensible size:</p><p>Create:</p><div class=mermaid>assets/css/extended/rss.css</div><p>Paste:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-css data-lang=css><span style=display:flex><span><span style=color:#75715e>/* Small & aligned RSS icon in the footer */</span>
|
||
</span></span><span style=display:flex><span>.<span style=color:#a6e22e>rss-link</span> { <span style=color:#66d9ef>display</span>: <span style=color:#66d9ef>inline-flex</span>; <span style=color:#66d9ef>align-items</span>: <span style=color:#66d9ef>center</span>; <span style=color:#66d9ef>gap</span>: <span style=color:#ae81ff>.35</span><span style=color:#66d9ef>rem</span>; }
|
||
</span></span><span style=display:flex><span>.<span style=color:#a6e22e>rss-link</span> <span style=color:#f92672>svg</span> { <span style=color:#66d9ef>margin-left</span>: <span style=color:#ae81ff>10</span><span style=color:#66d9ef>px</span>; <span style=color:#66d9ef>width</span>: <span style=color:#ae81ff>18</span><span style=color:#66d9ef>px</span>; <span style=color:#66d9ef>height</span>: <span style=color:#ae81ff>18</span><span style=color:#66d9ef>px</span>; } <span style=color:#75715e>/* a bit of left margin for good measure!*/</span>
|
||
</span></span><span style=display:flex><span>.<span style=color:#a6e22e>rss-link</span> <span style=color:#f92672>span</span> { <span style=color:#66d9ef>font-size</span>: <span style=color:#ae81ff>.95</span><span style=color:#66d9ef>rem</span>; }
|
||
</span></span></code></pre></div><p>PaperMod auto-bundles anything under <code>assets/css/extended/</code>, so no extra imports needed.</p><hr><h2 id=4-verify-everything>4) Verify everything<a hidden class=anchor aria-hidden=true href=#4-verify-everything>#</a></h2><p>Build or run dev:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>hugo <span style=color:#75715e># outputs to ./public</span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># or</span>
|
||
</span></span><span style=display:flex><span>hugo server <span style=color:#75715e># serves at http://localhost:1313</span>
|
||
</span></span></code></pre></div><p>Check feeds:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span><span style=color:#75715e># Home feed:</span>
|
||
</span></span><span style=display:flex><span>curl -s http://localhost:1313/index.xml | head
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># A section feed (adjust path to your section name):</span>
|
||
</span></span><span style=display:flex><span>curl -s http://localhost:1313/posts/index.xml | head
|
||
</span></span></code></pre></div><p>Check comments:</p><ol><li>Open any post locally.</li><li>Scroll to the bottom — Giscus should appear.</li><li>Try a reaction or comment (you’ll be prompted to sign in with GitHub).</li></ol><hr><h2 id=5-per-post-controls-handy-later>5) Per-post controls (handy later)<a hidden class=anchor aria-hidden=true href=#5-per-post-controls-handy-later>#</a></h2><p>Turn comments off for a single post:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-toml data-lang=toml><span style=display:flex><span><span style=color:#75715e># in that post’s front matter</span>
|
||
</span></span><span style=display:flex><span><span style=color:#a6e22e>comments</span> = <span style=color:#66d9ef>false</span>
|
||
</span></span></code></pre></div><p>Full content in RSS (global):</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-toml data-lang=toml><span style=display:flex><span>[<span style=color:#a6e22e>params</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>ShowFullTextinRSS</span> = <span style=color:#66d9ef>true</span>
|
||
</span></span></code></pre></div><p>Show RSS buttons on section/taxonomy lists:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-toml data-lang=toml><span style=display:flex><span>[<span style=color:#a6e22e>params</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>ShowRssButtonInSectionTermList</span> = <span style=color:#66d9ef>true</span>
|
||
</span></span></code></pre></div><hr><h2 id=6-troubleshooting-aka-what-i-bumped-into>6) Troubleshooting (aka “what I bumped into”)<a hidden class=anchor aria-hidden=true href=#6-troubleshooting-aka-what-i-bumped-into>#</a></h2><ul><li><p><strong>Home page has no RSS icon</strong><br>That’s expected; either enable Home-Info/Profile mode + <code>socialIcons</code>, or use the footer partial.</p></li><li><p><strong>Section feed 404</strong><br>Folder names are lowercase (<code>content/posts/</code>, not <code>content/Posts/</code>).<br>The URL mirrors that: <code>/posts/index.xml</code>.</p></li><li><p><strong>Giscus doesn’t create a discussion</strong><br>Double-check the four attributes: <code>data-repo</code>, <code>data-repo-id</code>, <code>data-category</code>, <code>data-category-id</code>.<br>Make sure Discussions is enabled and the Giscus app is installed for the repo.</p></li><li><p><strong>Icon is comically large</strong><br>Keep the CSS above; 16–20px usually looks right.</p></li></ul><hr><h2 id=7-bonus-fast-setup-via-github-cli-optional-i-didnt-use-it-but-i-shouldve-perhaps>7) Bonus: fast setup via GitHub CLI (optional, I didn’t use it, but I should’ve perhaps)<a hidden class=anchor aria-hidden=true href=#7-bonus-fast-setup-via-github-cli-optional-i-didnt-use-it-but-i-shouldve-perhaps>#</a></h2><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span><span style=color:#75715e># Create the public comments repo (adjust names)</span>
|
||
</span></span><span style=display:flex><span>gh repo create yourname/blog-comments --public -d <span style=color:#e6db74>"Blog comment threads"</span> --confirm
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># Enable Discussions for it</span>
|
||
</span></span><span style=display:flex><span>gh repo edit yourname/blog-comments --enable-discussions
|
||
</span></span></code></pre></div><p>Then visit <strong>giscus.app</strong>, select the repo + category (e.g. “Comments”), and copy the generated IDs into <code>layouts/partials/comments.html</code>.</p><hr><h3 id=final-config-snapshot-condensed>Final config snapshot (condensed)<a hidden class=anchor aria-hidden=true href=#final-config-snapshot-condensed>#</a></h3><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-toml data-lang=toml><span style=display:flex><span><span style=color:#a6e22e>baseURL</span> = <span style=color:#e6db74>"https://example.com/"</span>
|
||
</span></span><span style=display:flex><span><span style=color:#a6e22e>theme</span> = <span style=color:#e6db74>"PaperMod"</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span>[<span style=color:#a6e22e>outputs</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>home</span> = [<span style=color:#e6db74>"HTML"</span>, <span style=color:#e6db74>"RSS"</span>, <span style=color:#e6db74>"JSON"</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>section</span> = [<span style=color:#e6db74>"HTML"</span>, <span style=color:#e6db74>"RSS"</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>taxonomy</span> = [<span style=color:#e6db74>"HTML"</span>, <span style=color:#e6db74>"RSS"</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>term</span> = [<span style=color:#e6db74>"HTML"</span>, <span style=color:#e6db74>"RSS"</span>]
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span>[<span style=color:#a6e22e>services</span>.<span style=color:#a6e22e>rss</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>limit</span> = <span style=color:#ae81ff>-1</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span>[<span style=color:#a6e22e>params</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>comments</span> = <span style=color:#66d9ef>true</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>ShowRssButtonInSectionTermList</span> = <span style=color:#66d9ef>true</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>ShowFullTextinRSS</span> = <span style=color:#66d9ef>true</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># Optional if using Home-Info/Profile mode:</span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># [[params.socialIcons]]</span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># name = "rss"</span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># url = "/index.xml"</span>
|
||
</span></span></code></pre></div><hr><h1 id=appendix--why-i-added-isso-how-i-wired-it-and-what-i-fixed>Appendix — Why I added Isso, how I wired it, and what I fixed<a hidden class=anchor aria-hidden=true href=#appendix--why-i-added-isso-how-i-wired-it-and-what-i-fixed>#</a></h1><h2 id=the-story-why-isso--why-i-still-keep-giscus>The story (why Isso + why I still keep Giscus)<a hidden class=anchor aria-hidden=true href=#the-story-why-isso--why-i-still-keep-giscus>#</a></h2><p>I wanted comments that:</p><ul><li>allow <strong>anonymous</strong> replies (no GitHub account required),</li><li>are <strong>lightweight</strong> and <strong>self-hosted</strong>, and</li><li>can work on my <strong>Tor <code>.onion</code> mirror</strong>.</li></ul><p><strong>Isso</strong> checks those boxes: it’s a tiny Python app with SQLite storage, no trackers, and a simple embed. At the same time, I like the developer-friendly workflow of <strong>Giscus</strong> (comments are GitHub Discussions), so I kept both and added a little switcher UI: <strong>“Anonymous (Isso)”</strong> or <strong>“GitHub (Giscus)”</strong>.</p><p>Result: readers can pick privacy/anon (Isso) or identity/notifications (Giscus).</p><h2 id=how-i-run-it-high-level>How I run it (high-level)<a hidden class=anchor aria-hidden=true href=#how-i-run-it-high-level>#</a></h2><ul><li><strong>Site:</strong> Hugo + PaperMod</li><li><strong>Isso:</strong> listening on <code>127.0.0.1:8080</code>, stored locally (SQLite)</li><li><strong>Nginx:</strong> reverse-proxies <strong><code>/isso/</code></strong> to Isso on both the clearnet and the <code>.onion</code> vhost</li><li><strong>Hugo partial:</strong> renders the two panels (Isso & Giscus) and a switcher; Giscus is <strong>lazy-loaded</strong> and <strong>auto-rethemed</strong> with the site theme</li></ul><blockquote><p>I’m deliberately keeping Isso’s own config tiny in this appendix; the important part for my setup is the <strong>Nginx proxying</strong> and the <strong>Hugo partial</strong>.</p></blockquote><h2 id=hugo-partial-switcher--embeds>Hugo partial: switcher + embeds<a hidden class=anchor aria-hidden=true href=#hugo-partial-switcher--embeds>#</a></h2><p>Save as <code>layouts/partials/comments.html</code> and include it in your single layout (e.g. <code>layouts/_default/single.html</code>) with <code>{{ partial "comments.html" . }}</code>.</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-html data-lang=html><span style=display:flex><span><span style=color:#75715e><!-- comments.html --></span>
|
||
</span></span><span style=display:flex><span><<span style=color:#f92672>div</span> <span style=color:#a6e22e>class</span><span style=color:#f92672>=</span><span style=color:#e6db74>"comments-switch"</span> <span style=color:#a6e22e>style</span><span style=color:#f92672>=</span><span style=color:#e6db74>"display:flex;gap:.5rem;margin:.5rem 0 1rem;"</span>>
|
||
</span></span><span style=display:flex><span> <<span style=color:#f92672>button</span> <span style=color:#a6e22e>id</span><span style=color:#f92672>=</span><span style=color:#e6db74>"btn-isso"</span> <span style=color:#a6e22e>type</span><span style=color:#f92672>=</span><span style=color:#e6db74>"button"</span> <span style=color:#a6e22e>aria-pressed</span><span style=color:#f92672>=</span><span style=color:#e6db74>"true"</span>>Anonymous (Isso)</<span style=color:#f92672>button</span>>
|
||
</span></span><span style=display:flex><span> <<span style=color:#f92672>button</span> <span style=color:#a6e22e>id</span><span style=color:#f92672>=</span><span style=color:#e6db74>"btn-giscus"</span> <span style=color:#a6e22e>type</span><span style=color:#f92672>=</span><span style=color:#e6db74>"button"</span> <span style=color:#a6e22e>aria-pressed</span><span style=color:#f92672>=</span><span style=color:#e6db74>"false"</span>>GitHub (Giscus)</<span style=color:#f92672>button</span>>
|
||
</span></span><span style=display:flex><span> <<span style=color:#f92672>a</span> <span style=color:#a6e22e>href</span><span style=color:#f92672>=</span><span style=color:#e6db74>"https://github.com/AlipourIm/blog-comments/discussions/categories/comments"</span> <span style=color:#a6e22e>target</span><span style=color:#f92672>=</span><span style=color:#e6db74>"_blank"</span> <span style=color:#a6e22e>rel</span><span style=color:#f92672>=</span><span style=color:#e6db74>"noopener"</span>>Open on GitHub ↗</<span style=color:#f92672>a</span>>
|
||
</span></span><span style=display:flex><span></<span style=color:#f92672>div</span>>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e><!-- Isso panel (default) --></span>
|
||
</span></span><span style=display:flex><span><<span style=color:#f92672>div</span> <span style=color:#a6e22e>id</span><span style=color:#f92672>=</span><span style=color:#e6db74>"panel-isso"</span>>
|
||
</span></span><span style=display:flex><span> <<span style=color:#f92672>section</span> <span style=color:#a6e22e>id</span><span style=color:#f92672>=</span><span style=color:#e6db74>"isso-thread"</span>></<span style=color:#f92672>section</span>>
|
||
</span></span><span style=display:flex><span> <<span style=color:#f92672>script</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>src</span><span style=color:#f92672>=</span><span style=color:#e6db74>"/isso/js/embed.min.js"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data-isso</span><span style=color:#f92672>=</span><span style=color:#e6db74>"/isso"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data-isso-css</span><span style=color:#f92672>=</span><span style=color:#e6db74>"true"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data-isso-lang</span><span style=color:#f92672>=</span><span style=color:#e6db74>"en"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data-isso-max-comments-nested</span><span style=color:#f92672>=</span><span style=color:#e6db74>"5"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>data-isso-sorting</span><span style=color:#f92672>=</span><span style=color:#e6db74>"newest"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>async</span>>
|
||
</span></span><span style=display:flex><span> </<span style=color:#f92672>script</span>>
|
||
</span></span><span style=display:flex><span> <<span style=color:#f92672>small</span> <span style=color:#a6e22e>class</span><span style=color:#f92672>=</span><span style=color:#e6db74>"isso-powered"</span> <span style=color:#a6e22e>style</span><span style=color:#f92672>=</span><span style=color:#e6db74>"display:block;margin:.5rem 0;color:var(--secondary,#888)"</span>>
|
||
</span></span><span style=display:flex><span> Comments powered by <<span style=color:#f92672>a</span> <span style=color:#a6e22e>href</span><span style=color:#f92672>=</span><span style=color:#e6db74>"https://isso-comments.de"</span> <span style=color:#a6e22e>target</span><span style=color:#f92672>=</span><span style=color:#e6db74>"_blank"</span> <span style=color:#a6e22e>rel</span><span style=color:#f92672>=</span><span style=color:#e6db74>"noopener"</span>>Isso</<span style=color:#f92672>a</span>>
|
||
</span></span><span style=display:flex><span> </<span style=color:#f92672>small</span>>
|
||
</span></span><span style=display:flex><span></<span style=color:#f92672>div</span>>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e><!-- Giscus panel (lazy-loaded on click) --></span>
|
||
</span></span><span style=display:flex><span><<span style=color:#f92672>div</span> <span style=color:#a6e22e>id</span><span style=color:#f92672>=</span><span style=color:#e6db74>"panel-giscus"</span> <span style=color:#a6e22e>style</span><span style=color:#f92672>=</span><span style=color:#e6db74>"display:none"</span>>
|
||
</span></span><span style=display:flex><span> <<span style=color:#f92672>section</span> <span style=color:#a6e22e>id</span><span style=color:#f92672>=</span><span style=color:#e6db74>"giscus-thread"</span>></<span style=color:#f92672>section</span>>
|
||
</span></span><span style=display:flex><span></<span style=color:#f92672>div</span>>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><<span style=color:#f92672>script</span>>
|
||
</span></span><span style=display:flex><span>(<span style=color:#66d9ef>function</span> () {
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>panelIsso</span> <span style=color:#f92672>=</span> document.<span style=color:#a6e22e>getElementById</span>(<span style=color:#e6db74>'panel-isso'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>panelGisc</span> <span style=color:#f92672>=</span> document.<span style=color:#a6e22e>getElementById</span>(<span style=color:#e6db74>'panel-giscus'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>issoBtn</span> <span style=color:#f92672>=</span> document.<span style=color:#a6e22e>getElementById</span>(<span style=color:#e6db74>'btn-isso'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>giscBtn</span> <span style=color:#f92672>=</span> document.<span style=color:#a6e22e>getElementById</span>(<span style=color:#e6db74>'btn-giscus'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>let</span> <span style=color:#a6e22e>gLoaded</span> <span style=color:#f92672>=</span> <span style=color:#66d9ef>false</span>;
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>function</span> <span style=color:#a6e22e>isDark</span>() {
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e>// 1) explicit PaperMod preference
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>pref</span> <span style=color:#f92672>=</span> <span style=color:#a6e22e>localStorage</span>.<span style=color:#a6e22e>getItem</span>(<span style=color:#e6db74>'pref-theme'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>if</span> (<span style=color:#a6e22e>pref</span> <span style=color:#f92672>===</span> <span style=color:#e6db74>'dark'</span>) <span style=color:#66d9ef>return</span> <span style=color:#66d9ef>true</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>if</span> (<span style=color:#a6e22e>pref</span> <span style=color:#f92672>===</span> <span style=color:#e6db74>'light'</span>) <span style=color:#66d9ef>return</span> <span style=color:#66d9ef>false</span>;
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e>// 2) page state (classes / data-theme)
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>H</span> <span style=color:#f92672>=</span> document.<span style=color:#a6e22e>documentElement</span>, <span style=color:#a6e22e>B</span> <span style=color:#f92672>=</span> document.<span style=color:#a6e22e>body</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>hasDark</span> <span style=color:#f92672>=</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>H</span>.<span style=color:#a6e22e>classList</span>.<span style=color:#a6e22e>contains</span>(<span style=color:#e6db74>'dark'</span>) <span style=color:#f92672>||</span> <span style=color:#a6e22e>B</span>.<span style=color:#a6e22e>classList</span>.<span style=color:#a6e22e>contains</span>(<span style=color:#e6db74>'dark'</span>) <span style=color:#f92672>||</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>H</span>.<span style=color:#a6e22e>dataset</span>.<span style=color:#a6e22e>theme</span> <span style=color:#f92672>===</span> <span style=color:#e6db74>'dark'</span> <span style=color:#f92672>||</span> <span style=color:#a6e22e>B</span>.<span style=color:#a6e22e>dataset</span>.<span style=color:#a6e22e>theme</span> <span style=color:#f92672>===</span> <span style=color:#e6db74>'dark'</span> <span style=color:#f92672>||</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>H</span>.<span style=color:#a6e22e>classList</span>.<span style=color:#a6e22e>contains</span>(<span style=color:#e6db74>'theme-dark'</span>) <span style=color:#f92672>||</span> <span style=color:#a6e22e>B</span>.<span style=color:#a6e22e>classList</span>.<span style=color:#a6e22e>contains</span>(<span style=color:#e6db74>'theme-dark'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>if</span> (<span style=color:#a6e22e>hasDark</span>) <span style=color:#66d9ef>return</span> <span style=color:#66d9ef>true</span>;
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e>// 3) OS preference
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#66d9ef>return</span> window.<span style=color:#a6e22e>matchMedia</span> <span style=color:#f92672>&&</span> window.<span style=color:#a6e22e>matchMedia</span>(<span style=color:#e6db74>'(prefers-color-scheme: dark)'</span>).<span style=color:#a6e22e>matches</span>;
|
||
</span></span><span style=display:flex><span> }
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>gTheme</span> <span style=color:#f92672>=</span> () => (<span style=color:#a6e22e>isDark</span>() <span style=color:#f92672>?</span> <span style=color:#e6db74>'dark_dimmed'</span> <span style=color:#f92672>:</span> <span style=color:#e6db74>'noborder_light'</span>);
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>function</span> <span style=color:#a6e22e>loadGiscus</span>() {
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>if</span> (<span style=color:#a6e22e>gLoaded</span>) <span style=color:#66d9ef>return</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>s</span> <span style=color:#f92672>=</span> document.<span style=color:#a6e22e>createElement</span>(<span style=color:#e6db74>'script'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#a6e22e>src</span> <span style=color:#f92672>=</span> <span style=color:#e6db74>'https://giscus.app/client.js'</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#66d9ef>async</span> <span style=color:#f92672>=</span> <span style=color:#66d9ef>true</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#a6e22e>crossOrigin</span> <span style=color:#f92672>=</span> <span style=color:#e6db74>'anonymous'</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#a6e22e>setAttribute</span>(<span style=color:#e6db74>'data-repo'</span>,<span style=color:#e6db74>'AlipourIm/blog-comments'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#a6e22e>setAttribute</span>(<span style=color:#e6db74>'data-repo-id'</span>,<span style=color:#e6db74>'R_kgDOQGARyA'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#a6e22e>setAttribute</span>(<span style=color:#e6db74>'data-category'</span>,<span style=color:#e6db74>'Comments'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#a6e22e>setAttribute</span>(<span style=color:#e6db74>'data-category-id'</span>,<span style=color:#e6db74>'DIC_kwDOQGARyM4Cw3x-'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#a6e22e>setAttribute</span>(<span style=color:#e6db74>'data-mapping'</span>,<span style=color:#e6db74>'pathname'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#a6e22e>setAttribute</span>(<span style=color:#e6db74>'data-strict'</span>,<span style=color:#e6db74>'0'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#a6e22e>setAttribute</span>(<span style=color:#e6db74>'data-reactions-enabled'</span>,<span style=color:#e6db74>'1'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#a6e22e>setAttribute</span>(<span style=color:#e6db74>'data-emit-metadata'</span>,<span style=color:#e6db74>'0'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#a6e22e>setAttribute</span>(<span style=color:#e6db74>'data-input-position'</span>,<span style=color:#e6db74>'bottom'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#a6e22e>setAttribute</span>(<span style=color:#e6db74>'data-lang'</span>,<span style=color:#e6db74>'en'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>s</span>.<span style=color:#a6e22e>setAttribute</span>(<span style=color:#e6db74>'data-theme'</span>, <span style=color:#a6e22e>gTheme</span>()); <span style=color:#75715e>// initial theme
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> document.<span style=color:#a6e22e>getElementById</span>(<span style=color:#e6db74>'giscus-thread'</span>).<span style=color:#a6e22e>appendChild</span>(<span style=color:#a6e22e>s</span>);
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e>// Retheme once iframe exists
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>reTheme</span> <span style=color:#f92672>=</span> () => {
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>iframe</span> <span style=color:#f92672>=</span> document.<span style=color:#a6e22e>querySelector</span>(<span style=color:#e6db74>'iframe.giscus-frame'</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>if</span> (<span style=color:#f92672>!</span><span style=color:#a6e22e>iframe</span>) <span style=color:#66d9ef>return</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>iframe</span>.<span style=color:#a6e22e>contentWindow</span><span style=color:#f92672>?</span>.<span style=color:#a6e22e>postMessage</span>(
|
||
</span></span><span style=display:flex><span> { <span style=color:#a6e22e>giscus</span><span style=color:#f92672>:</span> { <span style=color:#a6e22e>setConfig</span><span style=color:#f92672>:</span> { <span style=color:#a6e22e>theme</span><span style=color:#f92672>:</span> <span style=color:#a6e22e>gTheme</span>() } } },
|
||
</span></span><span style=display:flex><span> <span style=color:#e6db74>'https://giscus.app'</span>
|
||
</span></span><span style=display:flex><span> );
|
||
</span></span><span style=display:flex><span> };
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e>// PaperMod toggle button
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> document.<span style=color:#a6e22e>getElementById</span>(<span style=color:#e6db74>'theme-toggle'</span>)<span style=color:#f92672>?</span>.<span style=color:#a6e22e>addEventListener</span>(<span style=color:#e6db74>'click'</span>, () =>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>setTimeout</span>(<span style=color:#a6e22e>reTheme</span>, <span style=color:#ae81ff>0</span>)
|
||
</span></span><span style=display:flex><span> );
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e>// Also react to attribute changes
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>mo</span> <span style=color:#f92672>=</span> <span style=color:#66d9ef>new</span> <span style=color:#a6e22e>MutationObserver</span>(<span style=color:#a6e22e>reTheme</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>mo</span>.<span style=color:#a6e22e>observe</span>(document.<span style=color:#a6e22e>documentElement</span>, { <span style=color:#a6e22e>attributes</span><span style=color:#f92672>:</span> <span style=color:#66d9ef>true</span>, <span style=color:#a6e22e>attributeFilter</span><span style=color:#f92672>:</span> [<span style=color:#e6db74>'class'</span>,<span style=color:#e6db74>'data-theme'</span>] });
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>mo</span>.<span style=color:#a6e22e>observe</span>(document.<span style=color:#a6e22e>body</span>, { <span style=color:#a6e22e>attributes</span><span style=color:#f92672>:</span> <span style=color:#66d9ef>true</span>, <span style=color:#a6e22e>attributeFilter</span><span style=color:#f92672>:</span> [<span style=color:#e6db74>'class'</span>,<span style=color:#e6db74>'data-theme'</span>] });
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>gLoaded</span> <span style=color:#f92672>=</span> <span style=color:#66d9ef>true</span>;
|
||
</span></span><span style=display:flex><span> }
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>function</span> <span style=color:#a6e22e>show</span>(<span style=color:#a6e22e>which</span>) {
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>showIsso</span> <span style=color:#f92672>=</span> <span style=color:#a6e22e>which</span> <span style=color:#f92672>===</span> <span style=color:#e6db74>'isso'</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>panelIsso</span>.<span style=color:#a6e22e>style</span>.<span style=color:#a6e22e>display</span> <span style=color:#f92672>=</span> <span style=color:#a6e22e>showIsso</span> <span style=color:#f92672>?</span> <span style=color:#e6db74>'block'</span> <span style=color:#f92672>:</span> <span style=color:#e6db74>'none'</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>panelGisc</span>.<span style=color:#a6e22e>style</span>.<span style=color:#a6e22e>display</span> <span style=color:#f92672>=</span> <span style=color:#a6e22e>showIsso</span> <span style=color:#f92672>?</span> <span style=color:#e6db74>'none'</span> <span style=color:#f92672>:</span> <span style=color:#e6db74>'block'</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>issoBtn</span><span style=color:#f92672>?</span>.<span style=color:#a6e22e>setAttribute</span>(<span style=color:#e6db74>'aria-pressed'</span>, <span style=color:#a6e22e>showIsso</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>giscBtn</span><span style=color:#f92672>?</span>.<span style=color:#a6e22e>setAttribute</span>(<span style=color:#e6db74>'aria-pressed'</span>, <span style=color:#f92672>!</span><span style=color:#a6e22e>showIsso</span>);
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>if</span> (<span style=color:#f92672>!</span><span style=color:#a6e22e>showIsso</span>) <span style=color:#a6e22e>loadGiscus</span>();
|
||
</span></span><span style=display:flex><span> }
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>issoBtn</span><span style=color:#f92672>?</span>.<span style=color:#a6e22e>addEventListener</span>(<span style=color:#e6db74>'click'</span>, <span style=color:#a6e22e>e</span> => { <span style=color:#a6e22e>e</span>.<span style=color:#a6e22e>preventDefault</span>(); <span style=color:#a6e22e>show</span>(<span style=color:#e6db74>'isso'</span>); });
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>giscBtn</span><span style=color:#f92672>?</span>.<span style=color:#a6e22e>addEventListener</span>(<span style=color:#e6db74>'click'</span>, <span style=color:#a6e22e>e</span> => { <span style=color:#a6e22e>e</span>.<span style=color:#a6e22e>preventDefault</span>(); <span style=color:#a6e22e>show</span>(<span style=color:#e6db74>'giscus'</span>); });
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e>// default
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#a6e22e>show</span>(<span style=color:#e6db74>'isso'</span>);
|
||
</span></span><span style=display:flex><span>})();
|
||
</span></span><span style=display:flex><span></<span style=color:#f92672>script</span>>
|
||
</span></span></code></pre></div><h2 id=nginx-proxy-isso-on-both-sites-and-avoid-the-404-onion-trap>Nginx: proxy Isso on <strong>both</strong> sites (and avoid the 404-onion trap)<a hidden class=anchor aria-hidden=true href=#nginx-proxy-isso-on-both-sites-and-avoid-the-404-onion-trap>#</a></h2><p>The bug I hit: my <code>.onion</code> server had a regex static block that <strong>won over</strong> the plain <code>/isso/</code> location, so <code>/isso/js/embed.min.js</code> returned <strong>404</strong>.</p><p><strong>Fix:</strong> make <code>/isso/</code> a <code>^~</code> prefix location so it beats regex, and place it <strong>above</strong> the static block.</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-nginx data-lang=nginx><span style=display:flex><span><span style=color:#75715e># /etc/nginx/sites-enabled/onion-blog (same idea for the clearnet vhost)
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span><span style=color:#66d9ef>server</span> {
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>listen</span> 127.0.0.1:<span style=color:#ae81ff>3301</span> <span style=color:#e6db74>default_server</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>server_name</span> <span style=color:#e6db74>fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion</span> 127.0.0.1 <span style=color:#e6db74>localhost</span>;
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>add_header</span> <span style=color:#e6db74>Referrer-Policy</span> <span style=color:#e6db74>no-referrer</span> <span style=color:#e6db74>always</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>add_header</span> <span style=color:#e6db74>X-Content-Type-Options</span> <span style=color:#e6db74>nosniff</span> <span style=color:#e6db74>always</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>add_header</span> <span style=color:#e6db74>X-Frame-Options</span> <span style=color:#e6db74>SAMEORIGIN</span> <span style=color:#e6db74>always</span>;
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>root</span> <span style=color:#e6db74>/srv/hugo/mysite/public-onion</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>index</span> <span style=color:#e6db74>index.html</span>;
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>location</span> <span style=color:#e6db74>/</span> { <span style=color:#f92672>try_files</span> $uri $uri/ <span style=color:#e6db74>/index.html</span>; }
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e># /isso -> /isso/
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#f92672>location</span> = <span style=color:#e6db74>/isso</span> { <span style=color:#f92672>return</span> <span style=color:#ae81ff>301</span> <span style=color:#e6db74>/isso/</span>; }
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e># IMPORTANT: this must beat regex locations below
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#f92672>location</span> <span style=color:#e6db74>^~</span> <span style=color:#e6db74>/isso/</span> {
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_pass</span> <span style=color:#e6db74>http://127.0.0.1:8080/</span>; <span style=color:#75715e># Isso container/port
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#f92672>proxy_http_version</span> <span style=color:#ae81ff>1</span><span style=color:#e6db74>.1</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_set_header</span> <span style=color:#e6db74>Host</span> $host;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_set_header</span> <span style=color:#e6db74>X-Forwarded-Host</span> $host;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_set_header</span> <span style=color:#e6db74>X-Forwarded-Proto</span> $scheme;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_set_header</span> <span style=color:#e6db74>X-Forwarded-For</span> $proxy_add_x_forwarded_for;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_redirect</span> <span style=color:#66d9ef>off</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_read_timeout</span> <span style=color:#e6db74>60s</span>;
|
||
</span></span><span style=display:flex><span> }
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e># static
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#f92672>location</span> ~<span style=color:#e6db74>*</span> <span style=color:#e6db74>\\.(css|js|ico|png|jpg|jpeg|gif|svg|webp|txt|xml)</span>$ {
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>access_log</span> <span style=color:#66d9ef>off</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>add_header</span> <span style=color:#e6db74>Cache-Control</span> <span style=color:#e6db74>"public,</span> <span style=color:#e6db74>max-age=31536000,</span> <span style=color:#e6db74>immutable"</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>try_files</span> $uri =<span style=color:#ae81ff>404</span>;
|
||
</span></span><span style=display:flex><span> }
|
||
</span></span><span style=display:flex><span>}
|
||
</span></span></code></pre></div><p>Reload and smoke test:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>sudo nginx -t <span style=color:#f92672>&&</span> sudo systemctl reload nginx
|
||
</span></span><span style=display:flex><span>curl -I http://<your-onion-host>/isso/js/embed.min.js <span style=color:#75715e># expect 200</span>
|
||
</span></span></code></pre></div><blockquote><p>If you ever point <code>data-isso</code> to a <strong>different origin</strong>, add CORS headers on that vhost. For same-origin (<code>data-isso="/isso"</code>), you don’t need CORS.</p></blockquote><h2 id=small-css-tweaks-one-color-across-lightdark--spacing>Small CSS tweaks (one color across light/dark + spacing)<a hidden class=anchor aria-hidden=true href=#small-css-tweaks-one-color-across-lightdark--spacing>#</a></h2><p>I wanted the same blue for <strong>reply / edit / delete</strong> links and for <strong>Submit / Preview</strong> buttons, in both themes, and a little spacing:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-css data-lang=css><span style=display:flex><span><span style=color:#75715e>/* put this in your site CSS */</span>
|
||
</span></span><span style=display:flex><span>:<span style=color:#a6e22e>root</span> { --btn-blue: <span style=color:#ae81ff>#2563eb</span>; } <span style=color:#75715e>/* adjust to taste */</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e>/* Isso form buttons */</span>
|
||
</span></span><span style=display:flex><span>.<span style=color:#a6e22e>isso-post-action</span> <span style=color:#f92672>input</span><span style=color:#f92672>[</span><span style=color:#f92672>type</span><span style=color:#f92672>=</span><span style=color:#e6db74>"submit"</span><span style=color:#f92672>],</span>
|
||
</span></span><span style=display:flex><span>.<span style=color:#a6e22e>isso-post-action</span> <span style=color:#f92672>input</span><span style=color:#f92672>[</span><span style=color:#f92672>name</span><span style=color:#f92672>=</span><span style=color:#e6db74>"preview"</span><span style=color:#f92672>]</span> {
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>background</span>: <span style=color:#a6e22e>var</span>(<span style=color:#f92672>--</span>btn<span style=color:#f92672>-</span><span style=color:#66d9ef>blue</span>) <span style=color:#75715e>!important</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>color</span>: <span style=color:#ae81ff>#fff</span> <span style=color:#75715e>!important</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>border</span>: <span style=color:#66d9ef>none</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>padding</span>: <span style=color:#ae81ff>.5</span><span style=color:#66d9ef>rem</span> <span style=color:#ae81ff>.75</span><span style=color:#66d9ef>rem</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>border-radius</span>: <span style=color:#ae81ff>.4</span><span style=color:#66d9ef>rem</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>cursor</span>: <span style=color:#66d9ef>pointer</span>;
|
||
</span></span><span style=display:flex><span>}
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e>/* link actions under comments */</span>
|
||
</span></span><span style=display:flex><span>.<span style=color:#a6e22e>isso-comment-footer</span> <span style=color:#f92672>a</span> {
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>color</span>: <span style=color:#a6e22e>var</span>(<span style=color:#f92672>--</span>btn<span style=color:#f92672>-</span><span style=color:#66d9ef>blue</span>) <span style=color:#75715e>!important</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>margin-right</span>: <span style=color:#ae81ff>.5</span><span style=color:#66d9ef>rem</span>; <span style=color:#75715e>/* gives "edit" and "delete" some breathing room */</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>text-decoration</span>: <span style=color:#66d9ef>none</span>;
|
||
</span></span><span style=display:flex><span>}
|
||
</span></span><span style=display:flex><span>.<span style=color:#a6e22e>isso-comment-footer</span> <span style=color:#f92672>a</span>:<span style=color:#a6e22e>hover</span> { <span style=color:#66d9ef>text-decoration</span>: <span style=color:#66d9ef>underline</span>; }
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e>/* keep name/email/website stacked, slightly larger */</span>
|
||
</span></span><span style=display:flex><span>.<span style=color:#a6e22e>isso-auth-section</span> .<span style=color:#a6e22e>isso-input-wrapper</span> {
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>display</span>: <span style=color:#66d9ef>block</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>margin</span>: <span style=color:#ae81ff>.35</span><span style=color:#66d9ef>rem</span> <span style=color:#ae81ff>0</span>;
|
||
</span></span><span style=display:flex><span>}
|
||
</span></span><span style=display:flex><span>.<span style=color:#a6e22e>isso-auth-section</span> <span style=color:#f92672>label</span> { <span style=color:#66d9ef>font-size</span>: <span style=color:#ae81ff>.95</span><span style=color:#66d9ef>rem</span>; }
|
||
</span></span><span style=display:flex><span>.<span style=color:#a6e22e>isso-auth-section</span> <span style=color:#f92672>input</span><span style=color:#f92672>[</span><span style=color:#f92672>type</span><span style=color:#f92672>=</span><span style=color:#e6db74>"text"</span><span style=color:#f92672>],</span>
|
||
</span></span><span style=display:flex><span>.<span style=color:#a6e22e>isso-auth-section</span> <span style=color:#f92672>input</span><span style=color:#f92672>[</span><span style=color:#f92672>type</span><span style=color:#f92672>=</span><span style=color:#e6db74>"email"</span><span style=color:#f92672>],</span>
|
||
</span></span><span style=display:flex><span>.<span style=color:#a6e22e>isso-auth-section</span> <span style=color:#f92672>input</span><span style=color:#f92672>[</span><span style=color:#f92672>type</span><span style=color:#f92672>=</span><span style=color:#e6db74>"url"</span><span style=color:#f92672>]</span> {
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>width</span>: <span style=color:#ae81ff>100</span><span style=color:#66d9ef>%</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>font-size</span>: <span style=color:#ae81ff>1</span><span style=color:#66d9ef>rem</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#66d9ef>padding</span>: <span style=color:#ae81ff>.5</span><span style=color:#66d9ef>rem</span> <span style=color:#ae81ff>.6</span><span style=color:#66d9ef>rem</span>;
|
||
</span></span><span style=display:flex><span>}
|
||
</span></span></code></pre></div><h2 id=what-changed-the-fixes-i-actually-made>What changed (the fixes I actually made)<a hidden class=anchor aria-hidden=true href=#what-changed-the-fixes-i-actually-made>#</a></h2><ol><li><p><strong>Theme correctness for Giscus.</strong><br>PaperMod doesn’t add <code>.light</code>—it only toggles <code>.dark</code> and stores <code>pref-theme</code>. I now:</p><ul><li>read <code>localStorage.pref-theme</code> first,</li><li>fall back to class/data-theme, then</li><li>fall back to OS preference.<br>I also re-theme the Giscus iframe on every toggle via <code>postMessage</code>.</li></ul></li><li><p><strong>Isso over Tor.</strong><br>On the <code>.onion</code> vhost, I moved the proxy to a <code>^~ /isso/</code> block so it beats the static regex. That fixed the <code>404</code> on <code>/isso/js/embed.min.js</code>.</p></li><li><p><strong>UI polish.</strong></p><ul><li>Unified button/link color across themes,</li><li>ensured “edit”/“delete” aren’t touching,</li><li>kept the author/email/website inputs <strong>stacked</strong>, and</li><li>left <strong>Submit</strong>/<strong>Preview</strong> styled and grouped.</li></ul></li></ol><h2 id=sanity-check>Sanity check<a hidden class=anchor aria-hidden=true href=#sanity-check>#</a></h2><ul><li>Toggle the theme: Giscus switches between <code>noborder_light</code> and <code>dark_dimmed</code> without reload.</li><li>Open DevTools → Network on onion: <code>/isso/js/embed.min.js</code> loads with <strong>200</strong>.</li><li>Switcher buttons swap panels instantly; Giscus only loads when clicked.</li></ul><h2 id=8-final-notes>8) Final notes!<a hidden class=anchor aria-hidden=true href=#8-final-notes>#</a></h2><p>I could not fully fix the style of Isso.
|
||
CSS is not easy… drat!</p><p>I don’t think anyone actually reads the blog, let alone comment on it.
|
||
But it felt cool to have a comment section and also RSS for it.
|
||
I had a lot of not so fun debugging experience, and will probably work on the styling to make it look right, but for now I’m happy with it! ^^</p><h1 id=admin-note--delete-all-isso-comments-for-a-single-post>Admin note — Delete all <strong>Isso</strong> comments for a single post<a hidden class=anchor aria-hidden=true href=#admin-note--delete-all-isso-comments-for-a-single-post>#</a></h1><p>This note is for future me: how to remove every comment tied to one post in <strong>Isso</strong>.<br>Tested with SQLite-backed Isso (default). Works whether you serve via clearnet or <code>.onion</code> — because this operates directly on the database.</p><hr><h2 id=tldr-host-with-sqlite>TL;DR (host with SQLite)<a hidden class=anchor aria-hidden=true href=#tldr-host-with-sqlite>#</a></h2><blockquote><p>Replace the placeholders for <code>DB</code> and <code>POST_URI</code> first.</p></blockquote><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span><span style=color:#75715e># 0) Variables — edit these two lines for your setup</span>
|
||
</span></span><span style=display:flex><span>DB<span style=color:#f92672>=</span><span style=color:#e6db74>"/var/lib/isso/comments.db"</span> <span style=color:#75715e># path to your Isso SQLite DB (check isso.conf: [general] dbpath)</span>
|
||
</span></span><span style=display:flex><span>POST_URI<span style=color:#f92672>=</span><span style=color:#e6db74>"/posts/skin_routine/"</span> <span style=color:#75715e># the post's URI as stored by Isso (often just the path)</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># 1) Backup (always do this!)</span>
|
||
</span></span><span style=display:flex><span>sqlite3 <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span> <span style=color:#e6db74>".backup '</span><span style=color:#66d9ef>$(</span>dirname <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span><span style=color:#66d9ef>)</span><span style=color:#e6db74>/comments.</span><span style=color:#66d9ef>$(</span>date +%F-%H%M%S<span style=color:#66d9ef>)</span><span style=color:#e6db74>.backup.sqlite3'"</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># 2) Inspect: find the thread row and preview the comments</span>
|
||
</span></span><span style=display:flex><span>sqlite3 <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span> <span style=color:#e6db74>"
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>.headers on
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>.mode column
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>SELECT id, uri FROM threads WHERE uri LIKE '%' || '</span>$POST_URI<span style=color:#e6db74>' || '%';
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>SELECT id, tid, created, author, text
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>FROM comments
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>WHERE tid IN (SELECT id FROM threads WHERE uri LIKE '%' || '</span>$POST_URI<span style=color:#e6db74>' || '%')
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>ORDER BY created DESC
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>LIMIT 25;
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>"</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># 3) Delete all comments for that post (thread)</span>
|
||
</span></span><span style=display:flex><span>sqlite3 <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span> <span style=color:#e6db74>"
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>DELETE FROM comments
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>WHERE tid IN (SELECT id FROM threads WHERE uri LIKE '%' || '</span>$POST_URI<span style=color:#e6db74>' || '%');
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>"</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># 4) (Optional) Remove the now-empty thread row too</span>
|
||
</span></span><span style=display:flex><span>sqlite3 <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span> <span style=color:#e6db74>"
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>DELETE FROM threads WHERE uri LIKE '%' || '</span>$POST_URI<span style=color:#e6db74>' || '%';
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>VACUUM;
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>"</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># 5) Done. Isso usually picks this up automatically.</span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># If you're containerized and want to be safe:</span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># docker restart <isso_container_name></span>
|
||
</span></span></code></pre></div><hr><h2 id=if-running-isso-in-docker>If running Isso in Docker<a hidden class=anchor aria-hidden=true href=#if-running-isso-in-docker>#</a></h2><p>Open a shell in the container, then run the same steps:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>docker exec -it <isso_container_name> /bin/sh
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># Inside the container:</span>
|
||
</span></span><span style=display:flex><span>DB<span style=color:#f92672>=</span><span style=color:#e6db74>"/db/comments.db"</span> <span style=color:#75715e># or /data/comments.db, check your image/volume mapping</span>
|
||
</span></span><span style=display:flex><span>POST_URI<span style=color:#f92672>=</span><span style=color:#e6db74>"/posts/skin_routine/"</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span>sqlite3 <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span> <span style=color:#e6db74>".backup '/db/comments.</span><span style=color:#66d9ef>$(</span>date +%F-%H%M%S<span style=color:#66d9ef>)</span><span style=color:#e6db74>.backup.sqlite3'"</span>
|
||
</span></span><span style=display:flex><span>sqlite3 <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span> <span style=color:#e6db74>"SELECT id, uri FROM threads WHERE uri LIKE '%' || '</span>$POST_URI<span style=color:#e6db74>' || '%';"</span>
|
||
</span></span><span style=display:flex><span>sqlite3 <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span> <span style=color:#e6db74>"DELETE FROM comments WHERE tid IN (SELECT id FROM threads WHERE uri LIKE '%' || '</span>$POST_URI<span style=color:#e6db74>' || '%');"</span>
|
||
</span></span><span style=display:flex><span>sqlite3 <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span> <span style=color:#e6db74>"DELETE FROM threads WHERE uri LIKE '%' || '</span>$POST_URI<span style=color:#e6db74>' || '%'; VACUUM;"</span>
|
||
</span></span><span style=display:flex><span>exit
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># Optionally restart the container:</span>
|
||
</span></span><span style=display:flex><span>docker restart <isso_container_name>
|
||
</span></span></code></pre></div><hr><h2 id=notes--gotchas>Notes & gotchas<a hidden class=anchor aria-hidden=true href=#notes--gotchas>#</a></h2><ul><li><strong>Find the real DB path</strong>: In <code>isso.conf</code> (often <code>/etc/isso/isso.conf</code> or within your container at <code>/config/isso.conf</code>), look for:<div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-ini data-lang=ini><span style=display:flex><span><span style=color:#66d9ef>[general]</span>
|
||
</span></span><span style=display:flex><span><span style=color:#a6e22e>dbpath</span> <span style=color:#f92672>=</span> <span style=color:#e6db74>/var/lib/isso/comments.db</span>
|
||
</span></span></code></pre></div></li><li><strong>What goes in <code>POST_URI</code>?</strong> Isso stores a <code>uri</code> string per thread. With the default embed config, it’s usually the <strong>path</strong> (<code>/posts/<slug>/</code>). If you’re unsure, list recent threads:<div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>sqlite3 <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span> <span style=color:#e6db74>".headers on"</span> <span style=color:#e6db74>".mode column"</span> <span style=color:#e6db74>"SELECT id, uri FROM threads ORDER BY id DESC LIMIT 50;"</span>
|
||
</span></span></code></pre></div></li><li><strong>Clearnet vs <code>.onion</code></strong>: If you load the same post under multiple origins <em>and</em> your embed setup stores full origins, you may have <strong>multiple thread rows</strong>. The <code>LIKE</code> query above deliberately matches any uri containing your <code>POST_URI</code> to catch those.</li><li><strong>Rollback</strong>: To undo, stop Isso (optional), replace the DB with your backup (<code>comments.YYYY-MM-DD-HHMMSS.backup.sqlite3</code>), and start Isso again.</li><li><strong>HTTP API option</strong>: Isso supports <code>DELETE /<comment_id></code> if admin endpoints/auth are enabled. For bulk removal it’s simpler and safer to use SQLite directly.</li><li><strong>Safety</strong>: Always run a backup first, and <strong>preview with the SELECT</strong> before you run the DELETE.</li></ul><hr><h2 id=one-liners-for-the-impatient>One-liners for the impatient<a hidden class=anchor aria-hidden=true href=#one-liners-for-the-impatient>#</a></h2><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>DB<span style=color:#f92672>=</span><span style=color:#e6db74>"/var/lib/isso/comments.db"</span>; POST_URI<span style=color:#f92672>=</span><span style=color:#e6db74>"/posts/skin_routine/"</span>
|
||
</span></span><span style=display:flex><span>sqlite3 <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span> <span style=color:#e6db74>".backup '</span><span style=color:#66d9ef>$(</span>dirname <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span><span style=color:#66d9ef>)</span><span style=color:#e6db74>/comments.</span><span style=color:#66d9ef>$(</span>date +%F-%H%M%S<span style=color:#66d9ef>)</span><span style=color:#e6db74>.backup.sqlite3'"</span>
|
||
</span></span><span style=display:flex><span>sqlite3 <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span> <span style=color:#e6db74>"DELETE FROM comments WHERE tid IN (SELECT id FROM threads WHERE uri LIKE '%' || '</span>$POST_URI<span style=color:#e6db74>' || '%');"</span>
|
||
</span></span><span style=display:flex><span>sqlite3 <span style=color:#e6db74>"</span>$DB<span style=color:#e6db74>"</span> <span style=color:#e6db74>"DELETE FROM threads WHERE uri LIKE '%' || '</span>$POST_URI<span style=color:#e6db74>' || '%'; VACUUM;"</span>
|
||
</span></span></code></pre></div><hr><p><strong>Isso container: quick checks & fixes for future me! (thank past me later ^^)</strong></p><p><strong>Find the container</strong></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>docker ps -a --format <span style=color:#e6db74>'table {{.ID}} {{.Names}} {{.Status}} {{.Ports}}'</span> | grep -i isso
|
||
</span></span></code></pre></div><p><strong>Inspect basic state</strong></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>docker inspect -f <span style=color:#e6db74>'Name={{.Name}} Running={{.State.Running}} Status={{.State.Status}} StartedAt={{.State.StartedAt}} FinishedAt={{.State.FinishedAt}}'</span> isso
|
||
</span></span></code></pre></div><p><strong>Logs</strong></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>docker logs --tail<span style=color:#f92672>=</span><span style=color:#ae81ff>200</span> isso
|
||
</span></span><span style=display:flex><span>docker logs -f isso
|
||
</span></span></code></pre></div><p><strong>Ports & reachability</strong></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>docker port isso
|
||
</span></span><span style=display:flex><span>sudo ss -ltnp | grep <span style=color:#e6db74>':8080 '</span>
|
||
</span></span><span style=display:flex><span>curl -i http://127.0.0.1:8080/
|
||
</span></span></code></pre></div><p><strong>Restart policy (keep it running)</strong></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>docker inspect -f <span style=color:#e6db74>'{{.HostConfig.RestartPolicy.Name}}'</span> isso
|
||
</span></span><span style=display:flex><span>docker update --restart unless-stopped isso
|
||
</span></span></code></pre></div><p><strong>Start/stop the container</strong></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>docker start isso
|
||
</span></span><span style=display:flex><span>docker stop isso
|
||
</span></span></code></pre></div><p><strong>Who/what stopped it (events)</strong></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>docker events --since 24h --filter container<span style=color:#f92672>=</span>isso
|
||
</span></span></code></pre></div><p><strong>Common config issue: duplicate options/sections</strong>
|
||
If logs show DuplicateOptionError or DuplicateSectionError, fix <code>/config/isso.cfg</code> (remove duplicate <code>[server]</code> blocks or duplicate <code>public-endpoint</code>).</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>nl -ba /config/isso.cfg | sed -n <span style=color:#e6db74>'1,120p'</span>
|
||
</span></span><span style=display:flex><span>grep -n <span style=color:#e6db74>'^\[server\]'</span> /config/isso.cfg
|
||
</span></span><span style=display:flex><span>grep -n <span style=color:#e6db74>'^public-endpoint'</span> /config/isso.cfg
|
||
</span></span></code></pre></div><p><strong>Using Docker Compose</strong> <em>(run these in the directory with your compose file)</em></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>docker compose ps
|
||
</span></span><span style=display:flex><span>docker compose logs --tail<span style=color:#f92672>=</span><span style=color:#ae81ff>200</span> isso
|
||
</span></span><span style=display:flex><span>docker compose up -d isso
|
||
</span></span></code></pre></div><p><strong>If the container doesn’t exist (create/recreate)</strong></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>docker image ls | grep -i isso
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span>docker run -d --name isso -p 8080:8080 -v /srv/isso/config:/config -v /srv/isso/db:/db --restart unless-stopped ghcr.io/posativ/isso:latest
|
||
</span></span></code></pre></div><p><strong>Optional: exclude from auto-updaters (like Watchtower)</strong></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>docker update --label-add com.centurylinklabs.watchtower.enable<span style=color:#f92672>=</span>false isso
|
||
</span></span></code></pre></div><p><em>This note is intentionally self-contained so I can paste it at the end of the blog post as a maintainer-only appendix.</em></p><hr><div class=signature-block style=margin-top:1rem><p><strong>Downloads:</strong>
|
||
<a href=/sources/posts/new_features.md>Markdown</a> ·
|
||
<a href=/sources/posts/new_features.md.asc>Signature (.asc)</a></p><details class=signature><summary>View OpenPGP signature</summary><pre style=font-size:.85em;overflow-x:auto;padding:.75rem>-----BEGIN PGP SIGNATURE-----
|
||
|
||
iQIzBAABCgAdFiEEVaKl3oR5K6zGyu4/tYgoUOBMjSoFAmpkbuMACgkQtYgoUOBM
|
||
jSr2VxAAgdHpf+4EIx2ASmSB+MeAHp7s1+2EPhmn96QuhiQO9Dr1e9250LbF/R8S
|
||
A0zcN8mmyOtKv2rediU6HsGy6ddwdTAtpQDRvMw2Xuk2pBUZaG5LuvlNgSse9zVB
|
||
dcG3GVLuMSRgNmyolhFoSWn46aa+3wZGrzYZQVUt8op+2fVp36agq2YoB4zeGKSm
|
||
Ri43rO/kTingD0bclOA+SMbHpKQOcLyHwDlVrqIjVXcJ/kKLcm1G3Z5owo+gB6jY
|
||
EMjxYiqyf5Zcbt4q/WzojbHLffjXoMzOgZ1sDOIObVQni9atgV49X4oIZ3+xSXSH
|
||
W7ZbH6sg9LlrU8djddBXUKB0i72IVZ/4F5icVFUcK+szOmASy8fFP7gCOcCRATtb
|
||
eNIFtiAlRXI0CqJdeq5fE9b+LX8lRpNnX229tg7GFgddzYUmFkKAsoJ9EUzUvUHm
|
||
Xzqlm9DKy9LG/CeOxo473fIo4YCT2fcmMnt9nCZW4iDKOVl1nCupkTn5qsfNdpQM
|
||
KycaNwsLBHPZWV+jDon8NEzYQk07n1Q9rlEWdL0egvn2S+pYnvLZbfi5dRhe+ciC
|
||
qcEW/I1NZZRdU7MUEzhWvhbWsZtTkm6OevXjnqACv91DIQv7tNrKwZuASnpFeDRa
|
||
GE0QYRrsaI3vCLR3cUmBAFsvZdwgzH0RQLb8w21XBW/BoFvixbA=
|
||
=9k+S
|
||
-----END PGP SIGNATURE-----
|
||
</pre></details><p><em>Verify locally:</em></p><pre style=font-size:.85em;overflow-x:auto;padding:.75rem>curl -fSLO https://blog.alipour.eu/sources/posts/new_features.md
|
||
curl -fSLO https://blog.alipour.eu/sources/posts/new_features.md.asc
|
||
gpg --verify new_features.md.asc new_features.md
|
||
</pre></div></div><footer class=post-footer><ul class=post-tags><li><a href=https://blog.alipour.eu/tags/hugo/>Hugo</a></li><li><a href=https://blog.alipour.eu/tags/papermod/>PaperMod</a></li><li><a href=https://blog.alipour.eu/tags/giscus/>Giscus</a></li><li><a href=https://blog.alipour.eu/tags/rss/>Rss</a></li><li><a href=https://blog.alipour.eu/tags/comments/>Comments</a></li></ul><nav class=paginav><a class=prev href=https://blog.alipour.eu/posts/sadness/><span class=title>« Prev</span><br><span>Sadness</span>
|
||
</a><a class=next href=https://blog.alipour.eu/posts/danya/><span class=title>Next »</span><br><span>Danya</span></a></nav></footer><div class=comments-switch style="display:flex;gap:.5rem;margin:.5rem 0 1rem"><button id=btn-isso type=button aria-pressed=true>Anonymous (Isso)</button>
|
||
<button id=btn-giscus type=button aria-pressed=false>GitHub (Giscus)</button>
|
||
<a href=https://github.com/AlipourIm/blog-comments/discussions/categories/comments target=_blank rel=noopener>Open on GitHub ↗</a></div><div id=panel-giscus style=display:none><section id=giscus-thread></section></div><div id=panel-isso><section id=isso-thread data-isso-id=/posts/comments-rss-papermod/ data-title="New features for my blog! Adding Comments + RSS to Hugo PaperMod (Giscus and Isso FTW)"><noscript>Javascript needs to be activated to view comments.</noscript></section><script src=/isso/js/embed.min.js data-isso=/isso/ data-isso-css=false data-isso-lang=en data-isso-max-comments-nested=5 data-isso-sorting=newest async></script><small class=isso-powered style="display:block;margin:.5rem 0;color:var(--secondary,#888)">Comments powered by <a href=https://isso-comments.de target=_blank rel=noopener>Isso</a></small></div><script>(function(){var i=document.getElementById("panel-isso"),a=document.getElementById("panel-giscus"),e=document.getElementById("btn-isso"),t=document.getElementById("btn-giscus"),s=!1;function r(){if(n=localStorage.getItem("pref-theme"),n==="dark")return!0;if(n==="light")return!1;var n,e=document.documentElement,t=document.body;return!!(e.classList&&e.classList.contains("dark")||t.classList&&t.classList.contains("dark")||e.getAttribute("data-theme")==="dark"||t.getAttribute("data-theme")==="dark"||e.classList&&e.classList.contains("theme-dark")||t.classList&&t.classList.contains("theme-dark"))||window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches}function o(){return r()?"dark_dimmed":"noborder_light"}function c(){if(s)return;var t,n,e=document.createElement("script");e.src="https://giscus.app/client.js",e.async=!0,e.crossOrigin="anonymous",e.setAttribute("data-repo","AlipourIm/blog-comments"),e.setAttribute("data-repo-id","R_kgDOQGARyA"),e.setAttribute("data-category","Comments"),e.setAttribute("data-category-id","DIC_kwDOQGARyM4Cw3x-"),e.setAttribute("data-mapping","pathname"),e.setAttribute("data-strict","0"),e.setAttribute("data-reactions-enabled","1"),e.setAttribute("data-emit-metadata","0"),e.setAttribute("data-input-position","bottom"),e.setAttribute("data-lang","en"),e.setAttribute("data-theme",o()),document.getElementById("giscus-thread").appendChild(e);function i(){var e=document.querySelector("iframe.giscus-frame");e&&e.contentWindow&&e.contentWindow.postMessage({giscus:{setConfig:{theme:o()}}},"https://giscus.app")}t=document.getElementById("theme-toggle"),t&&t.addEventListener("click",function(){setTimeout(i,0)}),n=new MutationObserver(function(){i()}),n.observe(document.documentElement,{attributes:!0,attributeFilter:["class","data-theme"]}),n.observe(document.body,{attributes:!0,attributeFilter:["class","data-theme"]}),s=!0}function n(n){var s=n==="isso";i.style.display=s?"block":"none",a.style.display=s?"none":"block",e&&e.setAttribute("aria-pressed",s?"true":"false"),t&&t.setAttribute("aria-pressed",s?"false":"true"),s||c()}e&&e.addEventListener("click",function(e){e.preventDefault(),n("isso")}),t&&t.addEventListener("click",function(e){e.preventDefault(),n("giscus")}),n("isso")})()</script></article></main><footer class=footer><span>© 2026 <a href=https://blog.alipour.eu/>AlipourIm journeys</a></span> ·
|
||
<span>Powered by
|
||
<a href=https://gohugo.io/ rel="noopener noreferrer" target=_blank>Hugo</a> &
|
||
<a href=https://github.com/adityatelange/hugo-PaperMod/ rel=noopener target=_blank>PaperMod</a></span></footer><a href=#top aria-label="go to top" title="Go to Top (Alt + G)" class=top-link id=top-link accesskey=g><svg viewBox="0 0 12 6" fill="currentcolor"><path d="M12 6H0l6-6z"/></svg></a><div class=site-meta-row style=display:flex;align-items:center;gap:.75rem;flex-wrap:wrap><a href=/index.xml rel=alternate type=application/rss+xml title=RSS class=rss-link style=display:inline-flex;align-items:center;gap:.35rem><svg viewBox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11a9 9 0 019 9"/><path d="M4 4a16 16 0 0116 16"/><circle cx="5" cy="19" r="1"/></svg>
|
||
<span>RSS</span>
|
||
</a><span aria-hidden=true>·</span>
|
||
<span>Visitors this week: <span id=gc_site_visitors_week>—</span></span></div><script>let menu=document.getElementById("menu");menu&&(menu.scrollLeft=localStorage.getItem("menu-scroll-position"),menu.onscroll=function(){localStorage.setItem("menu-scroll-position",menu.scrollLeft)}),document.querySelectorAll('a[href^="#"]').forEach(e=>{e.addEventListener("click",function(e){e.preventDefault();var t=this.getAttribute("href").substr(1);window.matchMedia("(prefers-reduced-motion: reduce)").matches?document.querySelector(`[id='${decodeURIComponent(t)}']`).scrollIntoView():document.querySelector(`[id='${decodeURIComponent(t)}']`).scrollIntoView({behavior:"smooth"}),t==="top"?history.replaceState(null,null," "):history.pushState(null,null,`#${t}`)})})</script><script>var mybutton=document.getElementById("top-link");window.onscroll=function(){document.body.scrollTop>800||document.documentElement.scrollTop>800?(mybutton.style.visibility="visible",mybutton.style.opacity="1"):(mybutton.style.visibility="hidden",mybutton.style.opacity="0")}</script><script>document.getElementById("theme-toggle").addEventListener("click",()=>{document.body.className.includes("dark")?(document.body.classList.remove("dark"),localStorage.setItem("pref-theme","light")):(document.body.classList.add("dark"),localStorage.setItem("pref-theme","dark"))})</script><script>document.querySelectorAll("pre > code").forEach(e=>{const n=e.parentNode.parentNode,t=document.createElement("button");t.classList.add("copy-code"),t.innerHTML="copy";function s(){t.innerHTML="copied!",setTimeout(()=>{t.innerHTML="copy"},2e3)}t.addEventListener("click",t=>{if("clipboard"in navigator){navigator.clipboard.writeText(e.textContent),s();return}const n=document.createRange();n.selectNodeContents(e);const o=window.getSelection();o.removeAllRanges(),o.addRange(n);try{document.execCommand("copy"),s()}catch{}o.removeRange(n)}),n.classList.contains("highlight")?n.appendChild(t):n.parentNode.firstChild==n||(e.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName=="TABLE"?e.parentNode.parentNode.parentNode.parentNode.parentNode.appendChild(t):e.parentNode.appendChild(t))})</script></body></html> |