Replaced Disqus comment system with Remark42

This commit is contained in:
Sergey Yarkov 2026-03-17 16:28:09 +03:00
commit 50063fb9bf
7 changed files with 44 additions and 38 deletions

View File

@ -13,7 +13,7 @@ Personal website created with Astro.
- [x] Table of contents - [x] Table of contents
- [x] Content management via [Directus](https://directus.io/) - [x] Content management via [Directus](https://directus.io/)
- [x] Form handling - [x] Form handling
- [x] Comment system via [Disqus](https://disqus.com/) - [x] Comment system via [Remark42](https://github.com/umputun/remark42)
- [x] RSS Feed for articles - [x] RSS Feed for articles
- [x] SEO optimized - [x] SEO optimized
- [x] Views counter - [x] Views counter

View File

@ -1,7 +1,7 @@
{ {
"name": "yarkov.tech", "name": "yarkov.tech",
"private": false, "private": false,
"version": "2.1.0", "version": "2.2.0",
"description": "Personal website created with Astro.", "description": "Personal website created with Astro.",
"author": { "author": {
"name": "Sergey Yarkov", "name": "Sergey Yarkov",

View File

@ -1,44 +1,53 @@
--- ---
import UIString from "./UIString.astro";
interface Props { interface Props {
url: string; url: string;
id: string; id: string;
lang: LanguageKeys;
} }
const { url, id } = Astro.props as Props; const { url, id, lang } = Astro.props as Props;
--- ---
<footer itemscope itemtype="http://schema.org/UserComments"> <footer itemscope itemtype="http://schema.org/UserComments">
<div id="disqus_thread"></div> <h2><UIString key={"articlePost.comments"} />:</h2>
<div id="remark42"></div>
</footer> </footer>
<script is:inline define:vars={{ url, id }}> <script is:inline define:vars={{ url, id, lang }}>
var disqus_config = function () { window.remark_config = {
this.page.url = url; host: "https://remark.yarkov.tech",
this.page.identifier = id; site_id: "remark",
theme: window.theme,
show_email_subscription: true,
url,
locale: lang,
no_footer: true,
}; };
var e = document.getElementById("disqus_thread"); var e = document.getElementById("remark42");
if ("IntersectionObserver" in window) { if ("IntersectionObserver" in window) {
var t = new IntersectionObserver((e) => { var t = new IntersectionObserver((e) => {
e.forEach((e) => { e.forEach((e) => {
e.isIntersecting && if (e.isIntersecting) {
((function () { ((e, n) => {
var e = document, for (var o = 0; o < e.length; o++) {
t = e.createElement("script"); var r = n.createElement("script"),
((t.src = "https://yarkov-tech.disqus.com/embed.js"), c = ".js",
t.setAttribute("data-timestamp", +new Date()), d = n.head || n.body;
(e.head || e.body).appendChild(t)); ("noModule" in r ? ((r.type = "module"), (c = ".mjs")) : (r.async = !0),
})(), (r.defer = !0),
t.unobserve(e.target)); (r.src = remark_config.host + "/web/" + e[o] + c),
d.appendChild(r));
}
})(remark_config.components || ["embed"], document);
t.unobserve(e.target);
}
}); });
}); });
t.observe(e); t.observe(e);
} }
window.addEventListener( window.addEventListener("onthemetoggled", (e) => window.REMARK42.changeTheme(e.detail));
"onthemetoggled",
() =>
document.readyState == "complete" &&
setTimeout(() => "DISQUS" in window && DISQUS.reset({ reload: true, config: disqus_config }), 100)
);
</script> </script>

View File

@ -28,7 +28,9 @@ const {
views, views,
article_id: articleTranslations, article_id: articleTranslations,
} = article; } = article;
const t = useTranslation(Astro); const t = useTranslation(Astro);
// const articleCodeLangs = articleTranslations?.translations?.map((t) => t?.languages_code?.code);
--- ---
<article itemscope itemtype="http://schema.org/BlogPosting" class="article"> <article itemscope itemtype="http://schema.org/BlogPosting" class="article">
@ -63,11 +65,7 @@ const t = useTranslation(Astro);
</time> </time>
<span itemprop="author">{`${author?.first_name} ${author?.last_name}`}</span> <span itemprop="author">{`${author?.first_name} ${author?.last_name}`}</span>
</div> </div>
{ {cover_image && <ArticleCover src={`${DIRECTUS_URL}/assets/${cover_image.filename_disk}`} alt={title} />}
cover_image && (
<ArticleCover src={`${DIRECTUS_URL}/assets/${cover_image.filename_disk}`} alt={title} />
)
}
<div class="description"> <div class="description">
<p> <p>
{description} {description}
@ -76,9 +74,13 @@ const t = useTranslation(Astro);
<AvailableOnLangs articles={articleTranslations} /> <AvailableOnLangs articles={articleTranslations} />
</header> </header>
<slot /> <slot />
<ArticleComments url={canonicalUrl.href} id={slug} /> <ArticleComments lang={pageLang} url={canonicalUrl.href} id={slug} />
</article> </article>
<!-- <script define:vars={{ articleCodeLangs }} is:inline>
console.log(navigator.language, articleCodeLangs);
</script> -->
<style lang="scss" is:global> <style lang="scss" is:global>
.article { .article {
& header { & header {

View File

@ -151,6 +151,6 @@ button {
border: 1px solid var(--border-color-hover); border: 1px solid var(--border-color-hover);
} }
} }
#disqus_thread svg { #remark42 svg {
filter: none; filter: none;
} }

View File

@ -140,11 +140,4 @@
--icon-filter: invert(100%); --icon-filter: invert(100%);
--image-filter: grayscale(50%); --image-filter: grayscale(50%);
/*
https://sergeyski.com/css-color-scheme-and-iframes-lessons-learned-from-disqus-background-bug/
*/
iframe[src*="disqus.com"] {
color-scheme: light;
}
} }

2
src/types/main.d.ts vendored
View File

@ -10,6 +10,8 @@ declare global {
type: K, type: K,
listener: (this: Window, ev: CustomEventMap[K]) => void listener: (this: Window, ev: CustomEventMap[K]) => void
): void; ): void;
REMARK42: any;
remark_config: any;
} }
interface CustomEventMap { interface CustomEventMap {