Skip to content

Commit f846fca

Browse files
authored
fix dark/light mode disclaimer footer bug (#90)
* fix dark/light mode disclaimer footer bug * remove extraneous GPT comments
1 parent 5615ca8 commit f846fca

1 file changed

Lines changed: 52 additions & 25 deletions

File tree

public/custom.js

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,45 +17,72 @@
1717
`.trim();
1818

1919
const WATERMARK_SELECTOR = 'a.watermark';
20-
const APPLIED_ATTR = 'data-custom-watermark';
20+
const STYLE_ID = 'custom-watermark-style';
21+
const SIBLING_ATTR = 'data-custom-watermark-sibling';
2122

22-
function replaceFooterContents(root = document) {
23+
function injectStyles() {
24+
if (document.getElementById(STYLE_ID)) return;
25+
26+
const style = document.createElement('style');
27+
style.id = STYLE_ID;
28+
style.textContent = `
29+
a.watermark {
30+
display: none !important;
31+
}
32+
`;
33+
document.head.appendChild(style);
34+
}
35+
36+
function ensureSiblingAfterWatermark(el) {
37+
if (!(el instanceof HTMLElement)) return;
38+
39+
// If the immediate next sibling is our disclaimer, update it; otherwise, insert one.
40+
const nextEl = el.nextElementSibling;
41+
if (nextEl && nextEl.getAttribute(SIBLING_ATTR) === '1') {
42+
if (nextEl.innerHTML.trim() !== CUSTOM_FOOTER_HTML) {
43+
nextEl.innerHTML = CUSTOM_FOOTER_HTML;
44+
}
45+
return;
46+
}
47+
48+
const container = document.createElement('div');
49+
container.setAttribute(SIBLING_ATTR, '1');
50+
container.style.margin = '0';
51+
container.style.pointerEvents = 'auto';
52+
container.setAttribute('aria-live', 'polite');
53+
container.innerHTML = CUSTOM_FOOTER_HTML;
54+
55+
// Insert directly after the watermark anchor
56+
el.insertAdjacentElement('afterend', container);
57+
}
58+
59+
function applyAll(root = document) {
2360
const nodes = root instanceof Element
2461
? root.querySelectorAll(WATERMARK_SELECTOR)
2562
: document.querySelectorAll(WATERMARK_SELECTOR);
2663

27-
nodes.forEach((el) => {
28-
if (!(el instanceof HTMLElement)) return;
29-
if (el.getAttribute(APPLIED_ATTR) === '1') return;
30-
31-
el.innerHTML = CUSTOM_FOOTER_HTML;
32-
33-
// disable the link behaviour
34-
el.removeAttribute('href');
35-
el.removeAttribute('target');
36-
el.style.pointerEvents = 'none';
64+
nodes.forEach((el) => ensureSiblingAfterWatermark(el));
65+
}
3766

38-
el.setAttribute(APPLIED_ATTR, '1');
39-
});
67+
function init() {
68+
injectStyles();
69+
applyAll(document);
4070
}
4171

42-
// Initial run (in case the element is already present).
4372
if (document.readyState === 'loading') {
44-
document.addEventListener('DOMContentLoaded', () => replaceFooterContents(document));
73+
document.addEventListener('DOMContentLoaded', init);
4574
} else {
46-
replaceFooterContents(document);
75+
init();
4776
}
4877

49-
// Re-apply on future UI updates (SPA re-renders).
78+
// Re-apply on future UI updates
5079
const mo = new MutationObserver((mutations) => {
5180
for (const m of mutations) {
52-
for (const node of m.addedNodes) {
53-
if (node instanceof Element) {
54-
// If the watermark itself is added or its parent subtree changes, update.
55-
if (node.matches?.(WATERMARK_SELECTOR) || node.querySelector?.(WATERMARK_SELECTOR)) {
56-
replaceFooterContents(node);
57-
}
58-
}
81+
if (m.type === 'childList') {
82+
// Re-ensure CSS and siblings if the UI changes.
83+
if (!document.getElementById(STYLE_ID)) injectStyles();
84+
applyAll(document);
85+
break;
5986
}
6087
}
6188
});

0 commit comments

Comments
 (0)