Skip to content

Commit d89478c

Browse files
Enhance Giscus integration by adding theme detection (#6)
* Enhance Giscus integration by adding theme detection * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 1b49b9d commit d89478c

2 files changed

Lines changed: 219 additions & 21 deletions

File tree

giscus-light.css

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*!
2+
* Based on GitHub's light theme variables used by giscus, with small
3+
* adjustments so the widget sits more naturally inside the MyST site layout.
4+
* Original theme variables are MIT-licensed by GitHub Inc.
5+
*/
6+
7+
main {
8+
--color-prettylights-syntax-comment: #6e7781;
9+
--color-prettylights-syntax-constant: #0550ae;
10+
--color-prettylights-syntax-entity: #8250df;
11+
--color-prettylights-syntax-storage-modifier-import: #24292f;
12+
--color-prettylights-syntax-entity-tag: #116329;
13+
--color-prettylights-syntax-keyword: #cf222e;
14+
--color-prettylights-syntax-string: #0a3069;
15+
--color-prettylights-syntax-variable: #953800;
16+
--color-prettylights-syntax-brackethighlighter-unmatched: #82071e;
17+
--color-prettylights-syntax-invalid-illegal-text: #f6f8fa;
18+
--color-prettylights-syntax-invalid-illegal-bg: #82071e;
19+
--color-prettylights-syntax-carriage-return-text: #f6f8fa;
20+
--color-prettylights-syntax-carriage-return-bg: #cf222e;
21+
--color-prettylights-syntax-string-regexp: #116329;
22+
--color-prettylights-syntax-markup-list: #3b2300;
23+
--color-prettylights-syntax-markup-heading: #0550ae;
24+
--color-prettylights-syntax-markup-italic: #24292f;
25+
--color-prettylights-syntax-markup-bold: #24292f;
26+
--color-prettylights-syntax-markup-deleted-text: #82071e;
27+
--color-prettylights-syntax-markup-deleted-bg: #ffebe9;
28+
--color-prettylights-syntax-markup-inserted-text: #116329;
29+
--color-prettylights-syntax-markup-inserted-bg: #dafbe1;
30+
--color-prettylights-syntax-markup-changed-text: #953800;
31+
--color-prettylights-syntax-markup-changed-bg: #ffd8b5;
32+
--color-prettylights-syntax-markup-ignored-text: #eaeef2;
33+
--color-prettylights-syntax-markup-ignored-bg: #0550ae;
34+
--color-prettylights-syntax-meta-diff-range: #8250df;
35+
--color-prettylights-syntax-brackethighlighter-angle: #57606a;
36+
--color-prettylights-syntax-sublimelinter-gutter-mark: #8c959f;
37+
--color-prettylights-syntax-constant-other-reference-link: #0a3069;
38+
--color-btn-text: #24292f;
39+
--color-btn-bg: #f4f2ef;
40+
--color-btn-border: rgb(31 35 40 / 15%);
41+
--color-btn-shadow: 0 1px 0 rgb(31 35 40 / 4%);
42+
--color-btn-inset-shadow: inset 0 1px 0 rgb(255 255 255 / 25%);
43+
--color-btn-hover-bg: #ebe7e2;
44+
--color-btn-hover-border: rgb(31 35 40 / 15%);
45+
--color-btn-active-bg: #e6e1dc;
46+
--color-btn-active-border: rgb(31 35 40 / 15%);
47+
--color-btn-selected-bg: #ece8e4;
48+
--color-btn-primary-text: #fff;
49+
--color-btn-primary-bg: #1f883d;
50+
--color-btn-primary-border: rgb(31 35 40 / 15%);
51+
--color-btn-primary-shadow: 0 1px 0 rgb(31 35 40 / 10%);
52+
--color-btn-primary-inset-shadow: inset 0 1px 0 rgb(255 255 255 / 3%);
53+
--color-btn-primary-hover-bg: #1a7f37;
54+
--color-btn-primary-hover-border: rgb(31 35 40 / 15%);
55+
--color-btn-primary-selected-bg: #176f31;
56+
--color-btn-primary-selected-shadow: inset 0 1px 0 rgb(0 45 17 / 20%);
57+
--color-btn-primary-disabled-text: rgb(255 255 255 / 80%);
58+
--color-btn-primary-disabled-bg: #94d3a2;
59+
--color-btn-primary-disabled-border: rgb(31 35 40 / 15%);
60+
--color-action-list-item-default-hover-bg: rgb(208 215 222 / 32%);
61+
--color-segmented-control-bg: #e8e2dc;
62+
--color-segmented-control-button-bg: #fbfaf8;
63+
--color-segmented-control-button-selected-border: #8c959f;
64+
--color-fg-default: #2a2622;
65+
--color-fg-muted: #6d635a;
66+
--color-fg-subtle: #7b726a;
67+
--color-canvas-default: #fbfaf8;
68+
--color-canvas-overlay: #ffffff;
69+
--color-canvas-inset: #f4f1ec;
70+
--color-canvas-subtle: #f7f4ef;
71+
--color-border-default: #d8d1c8;
72+
--color-border-muted: #e6e0d8;
73+
--color-neutral-muted: rgb(175 184 193 / 20%);
74+
--color-accent-fg: #0b66d0;
75+
--color-accent-emphasis: #0b66d0;
76+
--color-accent-muted: rgb(84 174 255 / 40%);
77+
--color-accent-subtle: #e3f1ff;
78+
--color-success-fg: #1a7f37;
79+
--color-attention-fg: #9a6700;
80+
--color-attention-muted: rgb(212 167 44 / 40%);
81+
--color-attention-subtle: #fff8c5;
82+
--color-danger-fg: #d1242f;
83+
--color-danger-muted: rgb(255 129 130 / 40%);
84+
--color-danger-subtle: #ffebe9;
85+
--color-primer-shadow-inset: inset 0 1px 0 rgb(208 215 222 / 20%);
86+
--color-scale-gray-1: #ece7e0;
87+
--color-scale-blue-1: #b6e3ff;
88+
--color-social-reaction-bg-hover: var(--color-scale-gray-1);
89+
--color-social-reaction-bg-reacted-hover: var(--color-scale-blue-1);
90+
}
91+
92+
main {
93+
color-scheme: light;
94+
}
95+
96+
main .pagination-loader-container {
97+
background-image: url("https://github.com/images/modules/pulls/progressive-disclosure-line.svg");
98+
}
99+
100+
main .gsc-loading-image {
101+
background-image: url("https://github.githubassets.com/images/mona-loading-default.gif");
102+
}
103+
104+
.gsc-reactions-count {
105+
font-weight: 600;
106+
}
107+
108+
.gsc-comment-box {
109+
border-radius: 10px;
110+
box-shadow: 0 10px 30px rgb(31 35 40 / 8%);
111+
}
112+
113+
.gsc-comment-box-textarea,
114+
.gsc-comment-box-tabs,
115+
.gsc-comment-box-bottom {
116+
background-color: var(--color-canvas-overlay);
117+
}
118+
119+
.gsc-comment-box-textarea:focus-within {
120+
border-color: var(--color-accent-emphasis);
121+
box-shadow: 0 0 0 3px rgb(9 105 218 / 12%);
122+
}

inject_comments.py

Lines changed: 97 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,63 @@
1111

1212
from pathlib import Path
1313

14+
LIGHT_THEME_FILE = "giscus-light.css"
15+
1416
# TODO: Update these values with your Giscus configuration from https://giscus.app
1517
GISCUS_SNIPPET = """
1618
<script>
1719
(function() {
20+
function getSiteTheme() {
21+
var root = document.documentElement;
22+
if (root.classList.contains('dark')) {
23+
return 'dark';
24+
}
25+
if (root.classList.contains('light')) {
26+
return 'light';
27+
}
28+
29+
var savedTheme = localStorage.getItem('myst:theme');
30+
if (savedTheme === 'dark' || savedTheme === 'light') {
31+
return savedTheme;
32+
}
33+
34+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
35+
}
36+
37+
function getSiteRootUrl() {
38+
var marker = '/blog/';
39+
var pathname = window.location.pathname;
40+
var markerIndex = pathname.indexOf(marker);
41+
var rootPath = markerIndex === -1 ? '/' : pathname.slice(0, markerIndex + 1);
42+
return window.location.origin + rootPath;
43+
}
44+
1845
function getGiscusTheme() {
19-
var theme = document.documentElement.getAttribute('data-theme');
20-
if (!theme) {
21-
theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
46+
if (getSiteTheme() === 'dark') {
47+
return 'dark';
2248
}
23-
return (theme === 'dark') ? 'dark' : 'light';
49+
return getSiteRootUrl() + 'giscus-light.css';
50+
}
51+
52+
function syncGiscusTheme() {
53+
var iframe = document.querySelector('iframe.giscus-frame');
54+
if (!iframe || !iframe.contentWindow) return false;
55+
56+
iframe.contentWindow.postMessage(
57+
{ giscus: { setConfig: { theme: getGiscusTheme() } } },
58+
'https://giscus.app'
59+
);
60+
return true;
61+
}
62+
63+
function waitForGiscusFrame() {
64+
var attempts = 0;
65+
var timer = setInterval(function() {
66+
attempts++;
67+
if (syncGiscusTheme() || attempts > 60) {
68+
clearInterval(timer);
69+
}
70+
}, 250);
2471
}
2572
2673
function initGiscus() {
@@ -39,11 +86,11 @@
3986
4087
var s = document.createElement('script');
4188
s.src = 'https://giscus.app/client.js';
42-
s.setAttribute('data-repo', 'username/repo'); // TODO: Update
43-
s.setAttribute('data-repo-id', 'R_XXXXXXXXXX'); // TODO: Update
89+
s.setAttribute('data-repo', 'opengeos/myst-cv-template'); // TODO: Update
90+
s.setAttribute('data-repo-id', 'R_kgDOR-orJg'); // TODO: Update
4491
s.setAttribute('data-category', 'General'); // TODO: Update
45-
s.setAttribute('data-category-id', 'DIC_XXXXXXXXXX'); // TODO: Update
46-
s.setAttribute('data-mapping', 'url');
92+
s.setAttribute('data-category-id', 'DIC_kwDOR-orJs4C6gKZ'); // TODO: Update
93+
s.setAttribute('data-mapping', 'pathname');
4794
s.setAttribute('data-strict', '0');
4895
s.setAttribute('data-reactions-enabled', '1');
4996
s.setAttribute('data-emit-metadata', '0');
@@ -53,37 +100,66 @@
53100
s.setAttribute('crossorigin', 'anonymous');
54101
s.async = true;
55102
container.appendChild(s);
103+
waitForGiscusFrame();
56104
return true;
57105
}
58106
59107
// Retry until React has finished rendering the article content
60-
var attempts = 0;
61-
var timer = setInterval(function() {
62-
attempts++;
63-
if (initGiscus() || attempts > 50) clearInterval(timer);
64-
}, 200);
108+
function tryInit() {
109+
var attempts = 0;
110+
var timer = setInterval(function() {
111+
attempts++;
112+
if (initGiscus() || attempts > 100) clearInterval(timer);
113+
}, 300);
114+
}
115+
tryInit();
116+
117+
// Re-initialize on SPA navigation (MyST book theme uses client-side routing)
118+
var lastUrl = location.href;
119+
var navObserver = new MutationObserver(function() {
120+
if (location.href !== lastUrl) {
121+
lastUrl = location.href;
122+
if (location.pathname.indexOf('/blog/') !== -1) {
123+
tryInit();
124+
}
125+
}
126+
});
127+
navObserver.observe(document.body, { childList: true, subtree: true });
65128
66129
// Update Giscus theme when the site theme toggles
67130
var observer = new MutationObserver(function() {
68-
var iframe = document.querySelector('iframe.giscus-frame');
69-
if (iframe) {
70-
iframe.contentWindow.postMessage(
71-
{ giscus: { setConfig: { theme: getGiscusTheme() } } },
72-
'https://giscus.app'
73-
);
74-
}
131+
syncGiscusTheme();
75132
});
76-
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
133+
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
77134
})();
78135
</script>
79136
"""
80137

81138

139+
def copy_theme_asset(build_dir: Path) -> None:
140+
"""Copy the custom light theme into the built site."""
141+
source = Path(__file__).parent / LIGHT_THEME_FILE
142+
target = build_dir / LIGHT_THEME_FILE
143+
144+
if not source.exists():
145+
print(f"Theme file not found: {source}")
146+
return
147+
148+
target.write_text(source.read_text(encoding="utf-8"), encoding="utf-8")
149+
print(f"Copied {LIGHT_THEME_FILE} to {target}")
150+
151+
82152
def main():
83153
"""Inject Giscus comments into blog post HTML files."""
84154
build_dir = Path(__file__).parent / "_build" / "html"
85155
blog_dir = build_dir / "blog"
86156

157+
if not build_dir.exists():
158+
print(f"No build directory found at {build_dir}")
159+
return
160+
161+
copy_theme_asset(build_dir)
162+
87163
if not blog_dir.exists():
88164
print(f"No blog directory found at {blog_dir}")
89165
return

0 commit comments

Comments
 (0)