mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Add configurable theme accent overrides
This commit is contained in:
1 parent
a73ea983cc
commit
c97a25077d
4 files changed
+111
No files matched your search
@@ -182,6 +182,10 @@ artifacts.
|
||||
the fee at `0` to pass through every satoshi.
|
||||
- Populate `DEFAULT_RELAY_URLS_OVERRIDE` with WSS URLs to replace the bundled
|
||||
relay bootstrap list. Keep it empty to stick with the upstream defaults.
|
||||
- Customize `THEME_ACCENT_OVERRIDES` with `#RRGGBB` hex strings when you want
|
||||
light or dark mode to use different accent, accent-strong, or
|
||||
accent-pressed colors. Leave the values `null` to inherit the defaults from
|
||||
`css/tokens.css`.
|
||||
- **`js/config.js`**:
|
||||
- Re-exports `isDevMode` (derived from `IS_DEV_MODE`) for modules, publishes
|
||||
`window.__BITVID_DEV_MODE__`, and centralizes the global configuration
|
||||
|
||||
@@ -125,6 +125,28 @@ export const DEFAULT_WHITELIST_MODE_ENABLED = true;
|
||||
*/
|
||||
export const ALLOW_NSFW_CONTENT = false;
|
||||
|
||||
/**
|
||||
* Optional theme accent overrides for light and dark mode.
|
||||
*
|
||||
* Operators can provide hex color strings (e.g., `"#2563eb"`) to customize the
|
||||
* accent tokens without editing the generated CSS bundle. Leave values as
|
||||
* `null` to keep the upstream defaults defined in `css/tokens.css`. Each theme
|
||||
* accepts overrides for the base accent color as well as the stronger and
|
||||
* pressed states used for hover/active presentations.
|
||||
*/
|
||||
export const THEME_ACCENT_OVERRIDES = Object.freeze({
|
||||
light: Object.freeze({
|
||||
accent: null,
|
||||
accentStrong: null,
|
||||
accentPressed: null,
|
||||
}),
|
||||
dark: Object.freeze({
|
||||
accent: null,
|
||||
accentStrong: null,
|
||||
accentPressed: null,
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
* Nostr kind used when persisting watch history events.
|
||||
*
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
ADMIN_SUPER_NPUB,
|
||||
PLATFORM_FEE_PERCENT,
|
||||
PLATFORM_LUD16_OVERRIDE,
|
||||
THEME_ACCENT_OVERRIDES,
|
||||
} from "./instance-config.js";
|
||||
|
||||
function assertSuperAdminConfigured(value) {
|
||||
@@ -56,6 +57,50 @@ function getPlatformLud16Override(value) {
|
||||
return value.trim();
|
||||
}
|
||||
|
||||
const ACCENT_HEX_PATTERN = /^#(?:[0-9a-fA-F]{6})$/;
|
||||
|
||||
function assertThemeAccentOverrides(overrides) {
|
||||
const source =
|
||||
overrides && typeof overrides === "object"
|
||||
? overrides
|
||||
: THEME_ACCENT_OVERRIDES;
|
||||
|
||||
const allowedThemes = new Set(["light", "dark"]);
|
||||
const allowedTokens = ["accent", "accentStrong", "accentPressed"];
|
||||
|
||||
Object.entries(source).forEach(([theme, themeOverrides]) => {
|
||||
if (!allowedThemes.has(theme) || themeOverrides == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof themeOverrides !== "object") {
|
||||
throw new Error(
|
||||
`THEME_ACCENT_OVERRIDES.${theme} must be an object with accent overrides.`
|
||||
);
|
||||
}
|
||||
|
||||
allowedTokens.forEach((token) => {
|
||||
const rawValue = themeOverrides[token];
|
||||
if (rawValue == null || rawValue === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof rawValue !== "string") {
|
||||
throw new Error(
|
||||
`THEME_ACCENT_OVERRIDES.${theme}.${token} must be a hex string (e.g., '#2563eb').`
|
||||
);
|
||||
}
|
||||
|
||||
const trimmed = rawValue.trim();
|
||||
if (!ACCENT_HEX_PATTERN.test(trimmed)) {
|
||||
throw new Error(
|
||||
`THEME_ACCENT_OVERRIDES.${theme}.${token} must be a #RRGGBB hex color.`
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function resolveConfig(overrides = {}) {
|
||||
return {
|
||||
adminSuperNpub:
|
||||
@@ -64,6 +109,8 @@ function resolveConfig(overrides = {}) {
|
||||
overrides.PLATFORM_FEE_PERCENT ?? PLATFORM_FEE_PERCENT,
|
||||
platformLud16Override:
|
||||
overrides.PLATFORM_LUD16_OVERRIDE ?? PLATFORM_LUD16_OVERRIDE,
|
||||
themeAccentOverrides:
|
||||
overrides.THEME_ACCENT_OVERRIDES ?? THEME_ACCENT_OVERRIDES,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -82,4 +129,6 @@ export function validateInstanceConfig(overrides) {
|
||||
"PLATFORM_FEE_PERCENT is positive but PLATFORM_LUD16_OVERRIDE is empty. Set PLATFORM_LUD16_OVERRIDE to the Lightning address that should receive the platform's split, or publish a lud16 value on the Super Admin profile so bitvid can route platform fees."
|
||||
);
|
||||
}
|
||||
|
||||
assertThemeAccentOverrides(config.themeAccentOverrides);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { THEME_ACCENT_OVERRIDES } from "../config/instance-config.js";
|
||||
import { userLogger } from "./utils/logger.js";
|
||||
const STORAGE_KEY = "bitvid:theme";
|
||||
const FALLBACK_THEME = "dark";
|
||||
@@ -13,6 +14,12 @@ const TOGGLE_SELECTORS = [
|
||||
"#themeToggle",
|
||||
];
|
||||
|
||||
const ACCENT_CSS_VARIABLES = Object.freeze({
|
||||
accent: "--color-accent",
|
||||
accentStrong: "--color-accent-strong",
|
||||
accentPressed: "--color-accent-pressed",
|
||||
});
|
||||
|
||||
const boundToggles = new WeakSet();
|
||||
const registeredToggles = new Set();
|
||||
let currentTheme = null;
|
||||
@@ -70,6 +77,34 @@ const getRootElement = () => {
|
||||
return null;
|
||||
};
|
||||
|
||||
const normalizeAccentValue = (value) =>
|
||||
typeof value === "string" ? value.trim() : "";
|
||||
|
||||
const applyAccentOverrides = (root, theme) => {
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
|
||||
const themeOverrides =
|
||||
THEME_ACCENT_OVERRIDES &&
|
||||
typeof THEME_ACCENT_OVERRIDES === "object" &&
|
||||
THEME_ACCENT_OVERRIDES[theme] &&
|
||||
typeof THEME_ACCENT_OVERRIDES[theme] === "object"
|
||||
? THEME_ACCENT_OVERRIDES[theme]
|
||||
: null;
|
||||
|
||||
Object.entries(ACCENT_CSS_VARIABLES).forEach(([token, cssVariable]) => {
|
||||
const overrideValue = themeOverrides ? themeOverrides[token] : null;
|
||||
const normalized = normalizeAccentValue(overrideValue);
|
||||
|
||||
if (normalized) {
|
||||
root.style.setProperty(cssVariable, normalized);
|
||||
} else {
|
||||
root.style.removeProperty(cssVariable);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const updateThemeColorMeta = (theme) => {
|
||||
if (!isBrowser()) {
|
||||
return;
|
||||
@@ -202,6 +237,7 @@ const applyTheme = (theme, { persist = true } = {}) => {
|
||||
const root = getRootElement();
|
||||
if (root) {
|
||||
root.dataset.theme = normalized;
|
||||
applyAccentOverrides(root, normalized);
|
||||
}
|
||||
|
||||
if (persist) {
|
||||
|
||||
Reference in new issue
Block a user