Skip to content

Commit 161af31

Browse files
committed
Widget responds to light/dark toggle
1 parent 34390f3 commit 161af31

1 file changed

Lines changed: 125 additions & 1 deletion

File tree

mastodon-timeline-setup.js

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,128 @@ const myTimeline = new MastodonTimeline.Init({
88
maxNbPostFetch: '10',
99
insistSearchContainer: true, // This helps with timing issues
1010
insistSearchContainerTime: '5000' // Wait up to 5 seconds for container
11-
});
11+
});
12+
13+
// Function to detect current Quarto theme
14+
function detectQuartoTheme() {
15+
// Method 1: Check for Quarto's theme class on html or body
16+
if (document.documentElement.getAttribute('data-bs-theme') === 'dark' ||
17+
document.body.classList.contains('quarto-dark') ||
18+
document.documentElement.classList.contains('quarto-dark')) {
19+
return 'dark';
20+
}
21+
22+
// Method 2: Check for dark mode in CSS custom properties
23+
const computedStyle = getComputedStyle(document.documentElement);
24+
const bgColor = computedStyle.getPropertyValue('--bs-body-bg') ||
25+
computedStyle.getPropertyValue('background-color');
26+
27+
// If background is dark, assume dark theme
28+
if (bgColor && (bgColor.includes('rgb(') || bgColor.includes('#'))) {
29+
// Simple heuristic: convert to grayscale and check brightness
30+
const isDark = isColorDark(bgColor);
31+
return isDark ? 'dark' : 'light';
32+
}
33+
34+
// Method 3: Check CSS media query preference
35+
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
36+
return 'dark';
37+
}
38+
39+
return 'light';
40+
}
41+
42+
// Helper function to determine if a color is dark
43+
function isColorDark(color) {
44+
// Convert color to RGB values
45+
let r, g, b;
46+
47+
if (color.startsWith('#')) {
48+
// Hex color
49+
const hex = color.slice(1);
50+
r = parseInt(hex.substr(0, 2), 16);
51+
g = parseInt(hex.substr(2, 2), 16);
52+
b = parseInt(hex.substr(4, 2), 16);
53+
} else if (color.startsWith('rgb')) {
54+
// RGB color
55+
const matches = color.match(/\d+/g);
56+
if (matches && matches.length >= 3) {
57+
r = parseInt(matches[0]);
58+
g = parseInt(matches[1]);
59+
b = parseInt(matches[2]);
60+
} else {
61+
return false; // Default to light if can't parse
62+
}
63+
} else {
64+
return false; // Unknown format, default to light
65+
}
66+
67+
// Calculate luminance
68+
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
69+
return luminance < 0.5; // Dark if luminance is less than 50%
70+
}
71+
72+
// Function to sync timeline theme with Quarto theme
73+
function syncTimelineTheme() {
74+
const currentTheme = detectQuartoTheme();
75+
myTimeline.mtColorTheme(currentTheme);
76+
}
77+
78+
// Set up theme synchronization
79+
function setupThemeSync() {
80+
// Initial sync
81+
syncTimelineTheme();
82+
83+
// Method 1: Watch for changes to data-bs-theme attribute (Bootstrap-based Quarto)
84+
if (document.documentElement.hasAttribute('data-bs-theme')) {
85+
const observer = new MutationObserver((mutations) => {
86+
mutations.forEach((mutation) => {
87+
if (mutation.type === 'attributes' &&
88+
mutation.attributeName === 'data-bs-theme') {
89+
syncTimelineTheme();
90+
}
91+
});
92+
});
93+
94+
observer.observe(document.documentElement, {
95+
attributes: true,
96+
attributeFilter: ['data-bs-theme']
97+
});
98+
}
99+
100+
// Method 2: Watch for class changes on body or html
101+
const classObserver = new MutationObserver((mutations) => {
102+
mutations.forEach((mutation) => {
103+
if (mutation.type === 'attributes' &&
104+
mutation.attributeName === 'class') {
105+
syncTimelineTheme();
106+
}
107+
});
108+
});
109+
110+
classObserver.observe(document.body, {
111+
attributes: true,
112+
attributeFilter: ['class']
113+
});
114+
115+
classObserver.observe(document.documentElement, {
116+
attributes: true,
117+
attributeFilter: ['class']
118+
});
119+
120+
// Method 3: Listen for custom events (if your Quarto site dispatches them)
121+
document.addEventListener('quartoThemeChanged', syncTimelineTheme);
122+
123+
// Method 4: Poll for changes (fallback method)
124+
let lastTheme = detectQuartoTheme();
125+
setInterval(() => {
126+
const currentTheme = detectQuartoTheme();
127+
if (currentTheme !== lastTheme) {
128+
syncTimelineTheme();
129+
lastTheme = currentTheme;
130+
}
131+
}, 1000); // Check every second
132+
}
133+
134+
// Initialize theme synchronization when the timeline is ready
135+
setTimeout(setupThemeSync, 1000);

0 commit comments

Comments
 (0)