mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Sync iframe forms with theme overrides
This commit is contained in:
1 parent
12f65cb694
commit
4d5de9f01d
6 files changed
+197
-196
No files matched your search
@@ -3,199 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>bitvid Whitelist Application Form</title>
|
||||
<script type="module">
|
||||
import { THEME_ACCENT_OVERRIDES } from "../../config/instance-config.js";
|
||||
|
||||
(() => {
|
||||
const VALID_THEMES = new Set(["light", "dark"]);
|
||||
const STORAGE_KEY = "bitvid:theme";
|
||||
const FALLBACK_THEME = "dark";
|
||||
const ACCENT_CSS_VARIABLES = Object.freeze({
|
||||
accent: "--color-accent",
|
||||
accentStrong: "--color-accent-strong",
|
||||
accentPressed: "--color-accent-pressed",
|
||||
});
|
||||
const ACCENT_TOKENS = Object.keys(ACCENT_CSS_VARIABLES);
|
||||
const { documentElement: root } = document;
|
||||
|
||||
if (!(root instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sanitizeConfigOverrides = (overrides) => {
|
||||
if (!overrides || typeof overrides !== "object") {
|
||||
return {};
|
||||
}
|
||||
|
||||
const sanitized = {};
|
||||
|
||||
Object.entries(overrides).forEach(([theme, themeOverrides]) => {
|
||||
if (!VALID_THEMES.has(theme) || typeof themeOverrides !== "object") {
|
||||
return;
|
||||
}
|
||||
|
||||
const normalized = {};
|
||||
|
||||
ACCENT_TOKENS.forEach((token) => {
|
||||
const value = themeOverrides[token];
|
||||
if (typeof value === "string") {
|
||||
const trimmed = value.trim();
|
||||
if (trimmed !== "") {
|
||||
normalized[token] = trimmed;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(normalized).length > 0) {
|
||||
sanitized[theme] = normalized;
|
||||
}
|
||||
});
|
||||
|
||||
return sanitized;
|
||||
};
|
||||
|
||||
const CONFIG_ACCENT_OVERRIDES = sanitizeConfigOverrides(
|
||||
THEME_ACCENT_OVERRIDES
|
||||
);
|
||||
|
||||
const normalizeTheme = (value) => {
|
||||
if (typeof value !== "string") {
|
||||
return null;
|
||||
}
|
||||
const normalized = value.trim().toLowerCase();
|
||||
if (normalized === "" || normalized === "default") {
|
||||
return FALLBACK_THEME;
|
||||
}
|
||||
return VALID_THEMES.has(normalized) ? normalized : null;
|
||||
};
|
||||
|
||||
const getParentRoot = () => {
|
||||
try {
|
||||
if (window.parent && window.parent !== window) {
|
||||
const parentDocument = window.parent.document;
|
||||
const parentRoot = parentDocument?.documentElement;
|
||||
return parentRoot instanceof HTMLElement ? parentRoot : null;
|
||||
}
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const readParentTheme = () => {
|
||||
const parentRoot = getParentRoot();
|
||||
if (!parentRoot) {
|
||||
return null;
|
||||
}
|
||||
return normalizeTheme(parentRoot.dataset?.theme);
|
||||
};
|
||||
|
||||
const readStoredTheme = () => {
|
||||
try {
|
||||
return normalizeTheme(window.localStorage.getItem(STORAGE_KEY));
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const applyTheme = (theme) => {
|
||||
if (theme && VALID_THEMES.has(theme)) {
|
||||
root.dataset.theme = theme;
|
||||
} else {
|
||||
root.removeAttribute("data-theme");
|
||||
}
|
||||
};
|
||||
|
||||
const readParentAccentOverrides = () => {
|
||||
const parentRoot = getParentRoot();
|
||||
if (!parentRoot) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const overrides = {};
|
||||
let hasOverride = false;
|
||||
|
||||
Object.values(ACCENT_CSS_VARIABLES).forEach((cssVariable) => {
|
||||
try {
|
||||
const value = parentRoot.style.getPropertyValue(cssVariable);
|
||||
if (typeof value === "string") {
|
||||
const trimmed = value.trim();
|
||||
if (trimmed !== "") {
|
||||
overrides[cssVariable] = trimmed;
|
||||
hasOverride = true;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
/* noop */
|
||||
}
|
||||
});
|
||||
|
||||
return hasOverride ? overrides : null;
|
||||
};
|
||||
|
||||
const applyAccentOverrides = (theme) => {
|
||||
const parentOverrides = readParentAccentOverrides();
|
||||
const configOverrides = CONFIG_ACCENT_OVERRIDES[theme] || null;
|
||||
|
||||
ACCENT_TOKENS.forEach((token) => {
|
||||
const cssVariable = ACCENT_CSS_VARIABLES[token];
|
||||
const parentValue = parentOverrides?.[cssVariable];
|
||||
const configValue = configOverrides?.[token];
|
||||
const nextValue = parentValue || configValue || "";
|
||||
|
||||
if (typeof nextValue === "string" && nextValue.trim() !== "") {
|
||||
root.style.setProperty(cssVariable, nextValue.trim());
|
||||
} else {
|
||||
root.style.removeProperty(cssVariable);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const syncTheme = () => {
|
||||
const resolvedTheme =
|
||||
readParentTheme() ?? readStoredTheme() ?? FALLBACK_THEME;
|
||||
applyTheme(resolvedTheme);
|
||||
applyAccentOverrides(resolvedTheme);
|
||||
};
|
||||
|
||||
syncTheme();
|
||||
|
||||
const parentRoot = getParentRoot();
|
||||
let observer;
|
||||
|
||||
if (parentRoot && typeof MutationObserver !== "undefined") {
|
||||
observer = new MutationObserver(syncTheme);
|
||||
observer.observe(parentRoot, {
|
||||
attributes: true,
|
||||
attributeFilter: ["data-theme", "style"],
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener("storage", (event) => {
|
||||
if (event?.key === STORAGE_KEY) {
|
||||
syncTheme();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener(
|
||||
"pageshow",
|
||||
() => {
|
||||
syncTheme();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
window.addEventListener(
|
||||
"beforeunload",
|
||||
() => {
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
})();
|
||||
</script>
|
||||
<script type="module" src="./theme-sync.js"></script>
|
||||
<!-- Link to your main stylesheet -->
|
||||
|
||||
<link rel="stylesheet" href="../../css/tailwind.generated.css" />
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>bitvid Bug Report Form</title>
|
||||
<script type="module" src="./theme-sync.js"></script>
|
||||
<!-- Link to your main stylesheet -->
|
||||
|
||||
<link rel="stylesheet" href="../../css/tailwind.generated.css" />
|
||||
<!-- Load nostr‑tools v2.10.4 -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js"></script>
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>bitvid Content Appeals Form</title>
|
||||
<script type="module" src="./theme-sync.js"></script>
|
||||
<!-- Link to your main stylesheet -->
|
||||
|
||||
<link rel="stylesheet" href="../../css/tailwind.generated.css" />
|
||||
<!-- Load nostr‑tools v2.10.4 -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js"></script>
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>bitvid General Feedback Form</title>
|
||||
<script type="module" src="./theme-sync.js"></script>
|
||||
<!-- Link to your main stylesheet -->
|
||||
|
||||
<link rel="stylesheet" href="../../css/tailwind.generated.css" />
|
||||
<!-- Load nostr‑tools v2.10.4 -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js"></script>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>bitvid Feature Request Form</title>
|
||||
<script type="module" src="./theme-sync.js"></script>
|
||||
<!-- Link to your main stylesheet -->
|
||||
<link rel="stylesheet" href="../../css/tailwind.generated.css" />
|
||||
<!-- Load nostr‑tools v2.10.4 -->
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
import { THEME_ACCENT_OVERRIDES } from "../../config/instance-config.js";
|
||||
|
||||
(() => {
|
||||
const VALID_THEMES = new Set(["light", "dark"]);
|
||||
const STORAGE_KEY = "bitvid:theme";
|
||||
const FALLBACK_THEME = "dark";
|
||||
const ACCENT_CSS_VARIABLES = Object.freeze({
|
||||
accent: "--color-accent",
|
||||
accentStrong: "--color-accent-strong",
|
||||
accentPressed: "--color-accent-pressed",
|
||||
});
|
||||
const ACCENT_TOKENS = Object.keys(ACCENT_CSS_VARIABLES);
|
||||
const { documentElement: root } = document;
|
||||
|
||||
if (!(root instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sanitizeConfigOverrides = (overrides) => {
|
||||
if (!overrides || typeof overrides !== "object") {
|
||||
return {};
|
||||
}
|
||||
|
||||
const sanitized = {};
|
||||
|
||||
Object.entries(overrides).forEach(([theme, themeOverrides]) => {
|
||||
if (!VALID_THEMES.has(theme) || typeof themeOverrides !== "object") {
|
||||
return;
|
||||
}
|
||||
|
||||
const normalized = {};
|
||||
|
||||
ACCENT_TOKENS.forEach((token) => {
|
||||
const value = themeOverrides[token];
|
||||
if (typeof value === "string") {
|
||||
const trimmed = value.trim();
|
||||
if (trimmed !== "") {
|
||||
normalized[token] = trimmed;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(normalized).length > 0) {
|
||||
sanitized[theme] = normalized;
|
||||
}
|
||||
});
|
||||
|
||||
return sanitized;
|
||||
};
|
||||
|
||||
const CONFIG_ACCENT_OVERRIDES = sanitizeConfigOverrides(
|
||||
THEME_ACCENT_OVERRIDES
|
||||
);
|
||||
|
||||
const normalizeTheme = (value) => {
|
||||
if (typeof value !== "string") {
|
||||
return null;
|
||||
}
|
||||
const normalized = value.trim().toLowerCase();
|
||||
if (normalized === "" || normalized === "default") {
|
||||
return FALLBACK_THEME;
|
||||
}
|
||||
return VALID_THEMES.has(normalized) ? normalized : null;
|
||||
};
|
||||
|
||||
const getParentRoot = () => {
|
||||
try {
|
||||
if (window.parent && window.parent !== window) {
|
||||
const parentDocument = window.parent.document;
|
||||
const parentRoot = parentDocument?.documentElement;
|
||||
return parentRoot instanceof HTMLElement ? parentRoot : null;
|
||||
}
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const readParentTheme = () => {
|
||||
const parentRoot = getParentRoot();
|
||||
if (!parentRoot) {
|
||||
return null;
|
||||
}
|
||||
return normalizeTheme(parentRoot.dataset?.theme);
|
||||
};
|
||||
|
||||
const readStoredTheme = () => {
|
||||
try {
|
||||
return normalizeTheme(window.localStorage.getItem(STORAGE_KEY));
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const applyTheme = (theme) => {
|
||||
if (theme && VALID_THEMES.has(theme)) {
|
||||
root.dataset.theme = theme;
|
||||
} else {
|
||||
root.removeAttribute("data-theme");
|
||||
}
|
||||
};
|
||||
|
||||
const readParentAccentOverrides = () => {
|
||||
const parentRoot = getParentRoot();
|
||||
if (!parentRoot) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const overrides = {};
|
||||
let hasOverride = false;
|
||||
|
||||
Object.values(ACCENT_CSS_VARIABLES).forEach((cssVariable) => {
|
||||
try {
|
||||
const value = parentRoot.style.getPropertyValue(cssVariable);
|
||||
if (typeof value === "string") {
|
||||
const trimmed = value.trim();
|
||||
if (trimmed !== "") {
|
||||
overrides[cssVariable] = trimmed;
|
||||
hasOverride = true;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
/* noop */
|
||||
}
|
||||
});
|
||||
|
||||
return hasOverride ? overrides : null;
|
||||
};
|
||||
|
||||
const applyAccentOverrides = (theme) => {
|
||||
const parentOverrides = readParentAccentOverrides();
|
||||
const configOverrides = CONFIG_ACCENT_OVERRIDES[theme] || null;
|
||||
|
||||
ACCENT_TOKENS.forEach((token) => {
|
||||
const cssVariable = ACCENT_CSS_VARIABLES[token];
|
||||
const parentValue = parentOverrides?.[cssVariable];
|
||||
const configValue = configOverrides?.[token];
|
||||
const nextValue = parentValue || configValue || "";
|
||||
|
||||
if (typeof nextValue === "string" && nextValue.trim() !== "") {
|
||||
root.style.setProperty(cssVariable, nextValue.trim());
|
||||
} else {
|
||||
root.style.removeProperty(cssVariable);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const syncTheme = () => {
|
||||
const resolvedTheme =
|
||||
readParentTheme() ?? readStoredTheme() ?? FALLBACK_THEME;
|
||||
applyTheme(resolvedTheme);
|
||||
applyAccentOverrides(resolvedTheme);
|
||||
};
|
||||
|
||||
syncTheme();
|
||||
|
||||
const parentRoot = getParentRoot();
|
||||
let observer;
|
||||
|
||||
if (parentRoot && typeof MutationObserver !== "undefined") {
|
||||
observer = new MutationObserver(syncTheme);
|
||||
observer.observe(parentRoot, {
|
||||
attributes: true,
|
||||
attributeFilter: ["data-theme", "style"],
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener("storage", (event) => {
|
||||
if (event?.key === STORAGE_KEY) {
|
||||
syncTheme();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener(
|
||||
"pageshow",
|
||||
() => {
|
||||
syncTheme();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
window.addEventListener(
|
||||
"beforeunload",
|
||||
() => {
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
})();
|
||||
|
||||
Reference in new issue
Block a user