Add design system feature flag and runtime integration

This commit is contained in:
thePR0M3TH3AN committed 2025-10-11 16:11:43 -04:00
1 parent 8288824872
commit 8265f9e2de
42 files changed
+359 -23

No files matched your search

+1 -1
View File
@@ -10,7 +10,7 @@
<!-- Include Tailwind CSS -->
<link href="css/tailwind.generated.css" rel="stylesheet" />
</head>
<body class="bg-surface text-text">
<body class="bg-surface text-text" data-ds="legacy">
<!-- Application Form Modal -->
<div
id="nostrFormModal"
+1
View File
@@ -11,6 +11,7 @@
aria-modal="true"
aria-labelledby="bugFixModalTitle"
aria-describedby="bugFixModalDescription"
data-ds="legacy"
>
<div class="bv-modal-backdrop" data-dismiss></div>
+1
View File
@@ -8,6 +8,7 @@
aria-modal="true"
aria-labelledby="contentAppealsModalTitle"
aria-describedby="contentAppealsModalDescription"
data-ds="legacy"
>
<div class="bv-modal-backdrop" data-dismiss></div>
+1
View File
@@ -6,6 +6,7 @@
aria-modal="true"
aria-labelledby="disclaimerModalTitle"
aria-describedby="disclaimerModalDescription"
data-ds="legacy"
>
<div class="bv-modal-backdrop" data-dismiss></div>
+1
View File
@@ -5,6 +5,7 @@
role="dialog"
aria-modal="true"
tabindex="-1"
data-ds="legacy"
>
<div id="editVideoModalOverlay" class="bv-modal-backdrop"></div>
+1
View File
@@ -8,6 +8,7 @@
aria-modal="true"
aria-labelledby="featureRequestModalTitle"
aria-describedby="featureRequestModalDescription"
data-ds="legacy"
>
<div class="bv-modal-backdrop" data-dismiss></div>
+1
View File
@@ -12,6 +12,7 @@
aria-modal="true"
aria-labelledby="generalFeedbackModalTitle"
aria-describedby="generalFeedbackModalDescription"
data-ds="legacy"
>
<div class="bv-modal-backdrop" data-dismiss></div>
@@ -11,7 +11,7 @@
<!-- Load nostr‑tools v2.10.4 -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js"></script>
</head>
<body>
<body data-ds="legacy">
<div class="container">
<div class="form-container">
<p>
@@ -11,7 +11,7 @@
<!-- Load nostr‑tools v2.10.4 -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js"></script>
</head>
<body>
<body data-ds="legacy">
<div class="container">
<div class="form-container">
<p>
@@ -11,7 +11,7 @@
<!-- Load nostr‑tools v2.10.4 -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js"></script>
</head>
<body>
<body data-ds="legacy">
<div class="container">
<div class="form-container">
<p>
@@ -11,7 +11,7 @@
<!-- Load nostr‑tools v2.10.4 -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js"></script>
</head>
<body>
<body data-ds="legacy">
<div class="container">
<div class="form-container">
<p>
@@ -10,7 +10,7 @@
<!-- Load nostr‑tools v2.10.4 -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js"></script>
</head>
<body>
<body data-ds="legacy">
<div class="container">
<div class="form-container">
<p>
+1
View File
@@ -5,6 +5,7 @@
aria-modal="true"
aria-labelledby="loginModalTitle"
aria-describedby="loginModalDescription"
data-ds="legacy"
>
<div class="bv-modal-backdrop" data-dismiss></div>
+1
View File
@@ -6,6 +6,7 @@
aria-modal="true"
aria-labelledby="profileModalTitle"
tabindex="-1"
data-ds="legacy"
>
<div class="bv-modal-backdrop"></div>
+1
View File
@@ -6,6 +6,7 @@
aria-modal="true"
aria-labelledby="revertModalTitle"
aria-describedby="revertModalSubtitle"
data-ds="legacy"
>
<div
id="revertVideoModalOverlay"
+1
View File
@@ -7,6 +7,7 @@
id="sidebar"
class="fade-in fade-in-delay-100 sidebar-collapsed"
data-state="collapsed"
data-ds="legacy"
>
<div class="sidebar__inner">
<div class="sidebar-scroll">
+1
View File
@@ -6,6 +6,7 @@
aria-modal="true"
aria-labelledby="uploadModalTitle"
aria-describedby="uploadModalDescription"
data-ds="legacy"
>
<div class="bv-modal-backdrop" data-dismiss></div>
+7 -1
View File
@@ -1,5 +1,11 @@
<!-- components/video-modal.html -->
<div id="playerModal" class="bv-modal hidden" role="dialog" aria-modal="true">
<div
id="playerModal"
class="bv-modal hidden"
role="dialog"
aria-modal="true"
data-ds="legacy"
>
<div class="bv-modal-backdrop" data-dismiss></div>
<div class="bv-modal__panel" tabindex="-1">
<div class="player-modal__container video-modal__container">
+9
View File
@@ -0,0 +1,9 @@
# Deployment Notes
## FEATURE_DESIGN_SYSTEM rollout
- **Default:** `false` (legacy styling). The flag lives in `js/constants.js` and is exposed through `window.__BITVID_RUNTIME_FLAGS__` at runtime.
- **Enable for canaries:** Before deploying a canary, run `window.__BITVID_RUNTIME_FLAGS__.FEATURE_DESIGN_SYSTEM = true` (or call `setFeatureDesignSystemEnabled(true)`) in the browser console. The change propagates immediately, flipping every `[data-ds]` container to `data-ds="new"` so controllers can hydrate the updated primitives.
- **Disable / rollback:** Set the flag back to `false` via the runtime object or redeploy with the default configuration. All root containers revert to `data-ds="legacy"`, forcing controllers and templates to stay on the existing class list.
- **Template contract:** Every layout, view, and partial now includes `data-ds` on the root element. Keep this attribute intact when editing HTML so the runtime can swap modes without re-rendering.
- **Controllers:** UI controllers receive a `designSystem` context in their constructors. Call `context.isNew()` before attaching new components or classes, and lean on `context.getMode()` when logging or telemetry need to differentiate between legacy and new renders.
+8
View File
@@ -2,6 +2,14 @@
bitvid's visual language is now powered by Tailwind utilities backed by our design tokens. This document lists the primitives available via `css/tailwind.source.css`, how they behave across states, and when to mix them with Tailwind utilities.
## Feature Flag Rollout
The new design system ships behind the `FEATURE_DESIGN_SYSTEM` runtime flag defined in `js/constants.js`. Deployments should keep the flag disabled (`false`) until the new primitives are ready for broad adoption.
- **Default state:** `FEATURE_DESIGN_SYSTEM` is `false`, so templates render with `data-ds="legacy"` on root containers.
- **Runtime toggle:** Set `window.__BITVID_RUNTIME_FLAGS__.FEATURE_DESIGN_SYSTEM = true` (or call `setFeatureDesignSystemEnabled(true)`) to opt into the new primitives. The entrypoint automatically updates every `[data-ds]` container to `data-ds="new"` and notifies controllers.
- **DOM contract:** Templates and partials must include `data-ds` on their root elements. Controllers should rely on the `designSystem` context (see `js/designSystem.js`) before attaching classes or behaviors that only exist in the new system.
## Theme System
The default experience renders the production dark palette. Pages and embeds can opt into alternates by setting the `data-theme` attribute on the `<html>` (or any ancestor that wraps the component). `data-theme="light"` promotes the light tokens defined in `css/tokens.css`, swapping surface, panel, border, muted, and overlay colors while keeping semantic accents consistent. Omit the attribute or set it back to `default` to inherit the dark baseline. Reserve additional theme keys (for example, `data-theme="contrast"`) for upcoming accessibility palettes—the same hook will activate them once their tokens land.
+1 -1
View File
@@ -59,7 +59,7 @@
<link href="css/style.css?v=2024.10.29" rel="stylesheet" />
<link href="css/markdown.css?v=2024.10.29" rel="stylesheet" />
</head>
<body class="sidebar-collapsed">
<body class="sidebar-collapsed" data-ds="legacy">
<!--
SIDEBAR CONTAINER:
The <aside id="sidebar"> inside handles visibility.
+43
View File
@@ -84,6 +84,10 @@ import {
applyRootTimestampToVideosMap,
syncActiveVideoRootTimestamp,
} from "./utils/videoTimestamps.js";
import {
getDesignSystemMode as readDesignSystemMode,
subscribeToDesignSystemChanges,
} from "./designSystem.js";
import {
getPubkey as getStoredPubkey,
setPubkey as setStoredPubkey,
@@ -182,6 +186,21 @@ class Application {
this.watchHistoryTelemetry = null;
this.authEventUnsubscribes = [];
this.unsubscribeFromNostrService = null;
this.unsubscribeFromDesignSystem = null;
this.designSystemMode = readDesignSystemMode();
this.designSystemContext = {
getMode: () => this.getDesignSystemMode(),
isNew: () => this.isDesignSystemNew(),
};
this.unsubscribeFromDesignSystem = subscribeToDesignSystemChanges(
({ mode }) => {
if (typeof mode === "string" && mode) {
this.designSystemMode = mode;
} else {
this.designSystemMode = readDesignSystemMode();
}
}
);
this.videoModalReadyPromise = null;
this.boundUploadSubmitHandler = null;
this.boundEditModalSubmitHandler = null;
@@ -287,6 +306,7 @@ class Application {
this.dropWatchHistoryMetadata(pointerKey),
getActivePubkey: () =>
typeof this.pubkey === "string" && this.pubkey ? this.pubkey : "",
designSystem: this.designSystemContext,
});
this.watchHistoryTelemetry = new WatchHistoryTelemetry({
@@ -549,6 +569,7 @@ class Application {
services: profileModalServices,
state: profileModalState,
callbacks: profileModalCallbacks,
designSystem: this.designSystemContext,
});
} else {
console.warn(
@@ -677,6 +698,7 @@ class Application {
? navigator.clipboard
: null,
isDevMode,
designSystem: this.designSystemContext,
callbacks: {
getCurrentVideo: () => this.currentVideo,
getCurrentUserNpub: () => this.getCurrentUserNpub(),
@@ -857,6 +879,7 @@ class Application {
getLoadingMarkup: (message) => getSidebarLoadingMarkup(message),
},
allowNsfw: ALLOW_NSFW_CONTENT === true,
designSystem: this.designSystemContext,
};
this.videoListView =
(typeof ui.videoListView === "function"
@@ -1302,6 +1325,14 @@ class Application {
return this.lastModalTrigger;
}
getDesignSystemMode() {
return this.designSystemMode === "new" ? "new" : "legacy";
}
isDesignSystemNew() {
return this.getDesignSystemMode() === "new";
}
/**
* Show the modal and set the "Please stand by" poster on the video.
*/
@@ -6595,6 +6626,18 @@ class Application {
this.teardownModalViewCountSubscription();
this.videoModalReadyPromise = null;
if (typeof this.unsubscribeFromDesignSystem === "function") {
try {
this.unsubscribeFromDesignSystem();
} catch (error) {
console.warn(
"[Application] Failed to unsubscribe design system listener:",
error
);
}
this.unsubscribeFromDesignSystem = null;
}
if (this.watchHistoryTelemetry) {
try {
this.watchHistoryTelemetry.destroy();
+77
View File
@@ -4,6 +4,7 @@ const DEFAULT_FLAGS = Object.freeze({
VIEW_FILTER_INCLUDE_LEGACY_VIDEO: false,
FEATURE_WATCH_HISTORY_V2: false,
FEATURE_PUBLISH_NIP71: false,
FEATURE_DESIGN_SYSTEM: false,
WSS_TRACKERS: Object.freeze([
"wss://tracker.openwebtorrent.com",
"wss://tracker.fastcast.nz",
@@ -12,8 +13,48 @@ const DEFAULT_FLAGS = Object.freeze({
]),
});
export const DESIGN_SYSTEM_EVENT_NAME = "bitvid:design-system-flag-change";
const globalScope = typeof globalThis === "object" && globalThis ? globalThis : undefined;
function dispatchDesignSystemFlagChange(enabled) {
if (
!globalScope ||
typeof globalScope.dispatchEvent !== "function" ||
(typeof globalScope.CustomEvent !== "function" &&
typeof globalScope.Event !== "function")
) {
return;
}
let event;
if (typeof globalScope.CustomEvent === "function") {
event = new globalScope.CustomEvent(DESIGN_SYSTEM_EVENT_NAME, {
detail: { enabled: enabled === true },
});
} else {
event = new globalScope.Event(DESIGN_SYSTEM_EVENT_NAME);
try {
Object.defineProperty(event, "detail", {
configurable: true,
enumerable: true,
writable: true,
value: { enabled: enabled === true },
});
} catch (error) {
// Older browsers may not allow redefining detail; ignore.
}
}
try {
globalScope.dispatchEvent(event);
} catch (error) {
if (typeof console !== "undefined" && console && console.warn) {
console.warn("[design-system] Failed to dispatch flag change event:", error);
}
}
}
const runtimeFlags = (() => {
if (globalScope && typeof globalScope.__BITVID_RUNTIME_FLAGS__ === "object") {
return globalScope.__BITVID_RUNTIME_FLAGS__;
@@ -25,6 +66,7 @@ const runtimeFlags = (() => {
DEFAULT_FLAGS.VIEW_FILTER_INCLUDE_LEGACY_VIDEO,
FEATURE_WATCH_HISTORY_V2: DEFAULT_FLAGS.FEATURE_WATCH_HISTORY_V2,
FEATURE_PUBLISH_NIP71: DEFAULT_FLAGS.FEATURE_PUBLISH_NIP71,
FEATURE_DESIGN_SYSTEM: DEFAULT_FLAGS.FEATURE_DESIGN_SYSTEM,
WSS_TRACKERS: [...DEFAULT_FLAGS.WSS_TRACKERS],
};
if (globalScope) {
@@ -115,6 +157,11 @@ export let FEATURE_PUBLISH_NIP71 = coerceBoolean(
DEFAULT_FLAGS.FEATURE_PUBLISH_NIP71
);
export let FEATURE_DESIGN_SYSTEM = coerceBoolean(
runtimeFlags.FEATURE_DESIGN_SYSTEM,
DEFAULT_FLAGS.FEATURE_DESIGN_SYSTEM
);
export let WSS_TRACKERS = freezeTrackers(
sanitizeTrackerList(runtimeFlags.WSS_TRACKERS)
);
@@ -183,6 +230,25 @@ Object.defineProperty(runtimeFlags, "FEATURE_PUBLISH_NIP71", {
},
});
Object.defineProperty(runtimeFlags, "FEATURE_DESIGN_SYSTEM", {
configurable: true,
enumerable: true,
get() {
return FEATURE_DESIGN_SYSTEM;
},
set(next) {
const previous = FEATURE_DESIGN_SYSTEM === true;
FEATURE_DESIGN_SYSTEM = coerceBoolean(
next,
DEFAULT_FLAGS.FEATURE_DESIGN_SYSTEM
);
const current = FEATURE_DESIGN_SYSTEM === true;
if (previous !== current) {
dispatchDesignSystemFlagChange(current);
}
},
});
Object.defineProperty(runtimeFlags, "WSS_TRACKERS", {
configurable: true,
enumerable: true,
@@ -200,6 +266,7 @@ runtimeFlags.ACCEPT_LEGACY_V1 = ACCEPT_LEGACY_V1;
runtimeFlags.VIEW_FILTER_INCLUDE_LEGACY_VIDEO = VIEW_FILTER_INCLUDE_LEGACY_VIDEO;
runtimeFlags.FEATURE_WATCH_HISTORY_V2 = FEATURE_WATCH_HISTORY_V2;
runtimeFlags.FEATURE_PUBLISH_NIP71 = FEATURE_PUBLISH_NIP71;
runtimeFlags.FEATURE_DESIGN_SYSTEM = FEATURE_DESIGN_SYSTEM;
runtimeFlags.WSS_TRACKERS = WSS_TRACKERS;
export function setUrlFirstEnabled(next) {
@@ -221,6 +288,10 @@ export function getWatchHistoryV2Enabled() {
return FEATURE_WATCH_HISTORY_V2 === true;
}
export function getFeatureDesignSystemEnabled() {
return FEATURE_DESIGN_SYSTEM === true;
}
export function setWssTrackers(next) {
runtimeFlags.WSS_TRACKERS = next;
return WSS_TRACKERS;
@@ -233,6 +304,7 @@ export function resetRuntimeFlags() {
DEFAULT_FLAGS.VIEW_FILTER_INCLUDE_LEGACY_VIDEO
);
setWatchHistoryV2Enabled(DEFAULT_FLAGS.FEATURE_WATCH_HISTORY_V2);
setFeatureDesignSystemEnabled(DEFAULT_FLAGS.FEATURE_DESIGN_SYSTEM);
setWssTrackers(DEFAULT_FLAGS.WSS_TRACKERS);
}
@@ -243,3 +315,8 @@ export function setWatchHistoryV2Enabled(next) {
return FEATURE_WATCH_HISTORY_V2;
}
export function setFeatureDesignSystemEnabled(next) {
runtimeFlags.FEATURE_DESIGN_SYSTEM = next;
return FEATURE_DESIGN_SYSTEM;
}
+136
View File
@@ -0,0 +1,136 @@
import {
DESIGN_SYSTEM_EVENT_NAME,
getFeatureDesignSystemEnabled,
} from "./constants.js";
const LEGACY_MODE = "legacy";
const NEW_MODE = "new";
const FALLBACK_CONTEXT = Object.freeze({
getMode: () => LEGACY_MODE,
isNew: () => false,
});
function normalizeMode(mode) {
return mode === NEW_MODE ? NEW_MODE : LEGACY_MODE;
}
export function getDesignSystemMode() {
return normalizeMode(getFeatureDesignSystemEnabled() ? NEW_MODE : LEGACY_MODE);
}
export function isDesignSystemNew() {
return getFeatureDesignSystemEnabled() === true;
}
export function normalizeDesignSystemContext(candidate) {
if (!candidate || typeof candidate !== "object") {
return FALLBACK_CONTEXT;
}
const resolvedGetMode =
typeof candidate.getMode === "function"
? candidate.getMode
: FALLBACK_CONTEXT.getMode;
const resolvedIsNew =
typeof candidate.isNew === "function"
? candidate.isNew
: () => normalizeMode(resolvedGetMode()) === NEW_MODE;
return {
getMode: resolvedGetMode,
isNew: resolvedIsNew,
};
}
export function applyDesignSystemAttributes(root = null) {
if (typeof document === "undefined" || !document) {
return getDesignSystemMode();
}
const mode = getDesignSystemMode();
const enqueueTargets = (source) => {
const targets = [];
if (!source) {
return targets;
}
const pushIfEligible = (element) => {
if (!element || element.nodeType !== 1) {
return;
}
if (element === document.body || element.hasAttribute("data-ds")) {
targets.push(element);
}
};
if (source === document) {
pushIfEligible(document.body);
if (typeof document.querySelectorAll === "function") {
document
.querySelectorAll("[data-ds]")
.forEach((element) => pushIfEligible(element));
}
return targets;
}
if (source.nodeType === 1) {
pushIfEligible(source);
if (typeof source.querySelectorAll === "function") {
source
.querySelectorAll("[data-ds]")
.forEach((element) => pushIfEligible(element));
}
return targets;
}
if (source.nodeType === 11 && typeof source.querySelectorAll === "function") {
source
.querySelectorAll("[data-ds]")
.forEach((element) => pushIfEligible(element));
}
return targets;
};
const targets = enqueueTargets(root || document);
targets.forEach((element) => {
try {
element.setAttribute("data-ds", mode);
} catch (error) {
if (typeof console !== "undefined" && console && console.warn) {
console.warn("[design-system] Failed to set data-ds attribute:", error);
}
}
});
return mode;
}
export function subscribeToDesignSystemChanges(listener) {
if (typeof window !== "object" || window === null) {
return () => {};
}
if (typeof listener !== "function") {
return () => {};
}
const handler = (event) => {
listener({
mode: getDesignSystemMode(),
event,
});
};
window.addEventListener(DESIGN_SYSTEM_EVENT_NAME, handler);
return () => {
window.removeEventListener(DESIGN_SYSTEM_EVENT_NAME, handler);
};
}
export { DESIGN_SYSTEM_EVENT_NAME };
+23 -2
View File
@@ -8,6 +8,10 @@ import { setApplication, setApplicationReady } from "./applicationContext.js";
import nostrService from "./services/nostrService.js";
import r2Service from "./services/r2Service.js";
import { loadView, viewInitRegistry } from "./viewManager.js";
import {
applyDesignSystemAttributes,
subscribeToDesignSystemChanges,
} from "./designSystem.js";
import {
prepareStaticModal,
openStaticModal,
@@ -16,6 +20,11 @@ import {
validateInstanceConfig();
applyDesignSystemAttributes();
subscribeToDesignSystemChanges(() => {
applyDesignSystemAttributes();
});
let application = null;
let applicationReadyPromise = Promise.resolve();
@@ -136,6 +145,10 @@ async function loadModal(url) {
document
.getElementById("modalContainer")
.insertAdjacentHTML("beforeend", sanitizedHtml);
const modalContainer = document.getElementById("modalContainer");
if (modalContainer) {
applyDesignSystemAttributes(modalContainer);
}
console.log(url, "loaded");
} catch (err) {
console.error(err);
@@ -146,7 +159,11 @@ async function loadModal(url) {
async function loadSidebar(url, containerId) {
try {
const html = await fetchPartial(url);
document.getElementById(containerId).innerHTML = html;
const container = document.getElementById(containerId);
if (container) {
container.innerHTML = html;
applyDesignSystemAttributes(container);
}
console.log(url, "loaded into", containerId);
} catch (err) {
console.error(err);
@@ -157,7 +174,11 @@ async function loadSidebar(url, containerId) {
async function loadDisclaimer(url, containerId) {
try {
const html = await fetchPartial(url);
document.getElementById(containerId).insertAdjacentHTML("beforeend", html);
const container = document.getElementById(containerId);
if (container) {
container.insertAdjacentHTML("beforeend", html);
applyDesignSystemAttributes(container);
}
console.log(url, "disclaimer loaded into", containerId);
} catch (err) {
console.error(err);
+6 -1
View File
@@ -1,3 +1,5 @@
import { normalizeDesignSystemContext } from "../../designSystem.js";
export class VideoCard {
constructor({
document: doc,
@@ -16,7 +18,8 @@ export class VideoCard {
state = {},
ensureGlobalMoreMenuHandlers,
onRequestCloseAllMenus,
nsfwContext = null
nsfwContext = null,
designSystem = null,
} = {}) {
if (!doc) {
throw new Error("VideoCard requires a document reference.");
@@ -76,6 +79,8 @@ export class VideoCard {
? onRequestCloseAllMenus
: null;
this.designSystem = normalizeDesignSystemContext(designSystem);
this.nsfwContext = {
isNsfw: Boolean(nsfwContext?.isNsfw),
allowNsfw: nsfwContext?.allowNsfw !== false,
+4
View File
@@ -1,3 +1,5 @@
import { normalizeDesignSystemContext } from "../designSystem.js";
export default class MoreMenuController {
constructor(options = {}) {
const {
@@ -8,6 +10,7 @@ export default class MoreMenuController {
clipboard = typeof navigator !== "undefined" ? navigator.clipboard : null,
isDevMode = false,
callbacks = {},
designSystem = null,
} = options;
this.document = doc;
@@ -16,6 +19,7 @@ export default class MoreMenuController {
this.subscriptions = subscriptions;
this.clipboard = clipboard;
this.isDevMode = Boolean(isDevMode);
this.designSystem = normalizeDesignSystemContext(designSystem);
this.callbacks = {
getCurrentVideo: callbacks.getCurrentVideo || (() => null),
+3
View File
@@ -5,6 +5,7 @@ import {
BITVID_WEBSITE_URL as CONFIG_BITVID_WEBSITE_URL,
MAX_WALLET_DEFAULT_ZAP as CONFIG_MAX_WALLET_DEFAULT_ZAP,
} from "../config.js";
import { normalizeDesignSystemContext } from "../designSystem.js";
const noop = () => {};
@@ -528,6 +529,7 @@ export class ProfileModalController {
services = {},
state = {},
constants: providedConstants = {},
designSystem = null,
} = options;
this.modalContainer = modalContainer;
@@ -537,6 +539,7 @@ export class ProfileModalController {
this.showError = showError;
this.showSuccess = showSuccess;
this.showStatus = showStatus;
this.designSystem = normalizeDesignSystemContext(designSystem);
const resolvedMaxWalletDefaultZap =
typeof providedConstants.MAX_WALLET_DEFAULT_ZAP === "number" &&
+4
View File
@@ -3,6 +3,7 @@ import {
subscribeToVideoViewCount,
unsubscribeFromVideoViewCount,
} from "../../viewCounter.js";
import { normalizeDesignSystemContext } from "../../designSystem.js";
const EMPTY_VIDEO_LIST_SIGNATURE = "__EMPTY__";
@@ -20,6 +21,7 @@ export class VideoListView {
utils = {},
renderers = {},
allowNsfw = true,
designSystem = null,
} = options;
this.document = doc;
@@ -165,6 +167,7 @@ export class VideoListView {
};
this.allowNsfw = allowNsfw !== false;
this.designSystem = normalizeDesignSystemContext(designSystem);
this.emitter = typeof EventTarget !== "undefined" ? new EventTarget() : null;
this._boundClickHandler = this.handleContainerClick.bind(this);
@@ -425,6 +428,7 @@ export class VideoListView {
formatters: {
formatTimeAgo: this.formatters.formatTimeAgo,
},
designSystem: this.designSystem,
});
videoCard.onPlay = ({ event: domEvent, video: cardVideo }) => {
+3
View File
@@ -3,6 +3,7 @@ import {
normalizePointerInput,
pointerKey as derivePointerKey,
} from "../nostr.js";
import { normalizeDesignSystemContext } from "../designSystem.js";
const noop = () => {};
@@ -38,6 +39,7 @@ export default class WatchHistoryController {
showSuccess,
dropWatchHistoryMetadata,
getActivePubkey,
designSystem,
} = {}) {
this.watchHistoryService = watchHistoryService || null;
this.nostrClient = nostrClient || null;
@@ -49,6 +51,7 @@ export default class WatchHistoryController {
: noop;
this.getActivePubkey =
typeof getActivePubkey === "function" ? getActivePubkey : () => "";
this.designSystem = normalizeDesignSystemContext(designSystem);
}
buildPointerFromDataset(dataset = {}) {
+7 -1
View File
@@ -3,6 +3,7 @@ import { initChannelProfileView } from "./channelProfile.js";
import { subscriptions } from "./subscriptions.js";
import { getApplication } from "./applicationContext.js";
import { ASSET_VERSION } from "../config/asset-version.js";
import { applyDesignSystemAttributes } from "./designSystem.js";
const TRACKING_SCRIPT_PATTERN = /(?:^|\/)tracking\.js(?:$|\?)/;
@@ -37,6 +38,7 @@ export async function loadView(viewUrl) {
const container = document.getElementById("viewContainer");
container.innerHTML = doc.body.innerHTML;
applyDesignSystemAttributes(container);
// Copy and execute any inline scripts
const scriptTags = doc.querySelectorAll("script");
@@ -63,7 +65,11 @@ export async function loadView(viewUrl) {
</article>
</div>
`;
document.getElementById("viewContainer").innerHTML = fallbackMarkup;
const fallbackContainer = document.getElementById("viewContainer");
if (fallbackContainer) {
fallbackContainer.innerHTML = fallbackMarkup;
applyDesignSystemAttributes(fallbackContainer);
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
<!-- views/about.html -->
<section class="bv-stack" aria-labelledby="aboutHeading">
<section class="bv-stack" data-ds="legacy" aria-labelledby="aboutHeading">
<article class="card p-lg">
<div class="bv-stack bv-stack--tight">
<h2 id="aboutHeading" class="text-2xl font-semibold text-text-strong">
+1 -1
View File
@@ -1,4 +1,4 @@
<section class="channel-profile-container">
<section class="channel-profile-container" data-ds="legacy">
<!-- Modified banner wrapper for taller, rounded style -->
<div class="profile-banner relative mb-6 rounded-lg shadow-lg">
<!-- Increase the default height classes -->
+1 -1
View File
@@ -1,5 +1,5 @@
<!-- views/community-guidelines.html -->
<section class="bv-stack" aria-labelledby="communityGuidelinesHeading">
<section class="bv-stack" data-ds="legacy" aria-labelledby="communityGuidelinesHeading">
<article class="card p-lg">
<div class="bv-stack bv-stack--tight">
<h2
+1 -1
View File
@@ -1,5 +1,5 @@
<!-- views/explore.html -->
<section>
<section data-ds="legacy">
<h2 class="mb-4 text-xl text-text-strong">Explore</h2>
<p class="text-muted-strong">Coming Soon...</p>
</section>
+1 -1
View File
@@ -1,5 +1,5 @@
<!-- views/getting-started.html -->
<section class="bv-stack" aria-labelledby="gettingStartedHeading">
<section class="bv-stack" data-ds="legacy" aria-labelledby="gettingStartedHeading">
<article class="card p-lg">
<div class="bv-stack bv-stack--tight">
<h2
+1 -1
View File
@@ -1,5 +1,5 @@
<!-- views/history.html -->
<section id="watchHistoryView" class="bv-stack">
<section id="watchHistoryView" class="bv-stack" data-ds="legacy">
<div class="bv-stack bv-stack--tight">
<div
class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between"
+1 -1
View File
@@ -1,5 +1,5 @@
<!-- views/ipns.html -->
<section class="bv-stack" aria-labelledby="ipnsHeading">
<section class="bv-stack" data-ds="legacy" aria-labelledby="ipnsHeading">
<article class="card p-lg">
<div class="bv-stack bv-stack--tight">
<h2 id="ipnsHeading" class="text-2xl font-semibold text-text-strong">
+1 -1
View File
@@ -1,5 +1,5 @@
<!-- views/links.html -->
<section class="bv-stack" aria-labelledby="linksHeading">
<section class="bv-stack" data-ds="legacy" aria-labelledby="linksHeading">
<article class="card p-lg">
<div class="bv-stack bv-stack--tight">
<h2 id="linksHeading" class="text-2xl font-semibold text-text-strong">
+1 -1
View File
@@ -1,5 +1,5 @@
<!-- views/most-recent-videos.html -->
<section>
<section data-ds="legacy">
<!-- You can have a heading if you want -->
<h2 class="mb-4 text-xl text-text-strong">Most Recent Videos</h2>
+1 -1
View File
@@ -1,5 +1,5 @@
<!-- views/roadmap.html -->
<section class="bv-stack" aria-labelledby="roadmapHeading">
<section class="bv-stack" data-ds="legacy" aria-labelledby="roadmapHeading">
<article class="card p-lg">
<div class="bv-stack bv-stack--tight">
<h2 id="roadmapHeading" class="text-2xl font-semibold text-text-strong">
+1 -1
View File
@@ -1,5 +1,5 @@
<!-- views/subscriptions.html -->
<section>
<section data-ds="legacy">
<h2 class="mb-4 text-xl">Subscriptions</h2>
<div id="subscriptionsVideoList" class="bv-grid-video">
<div class="sidebar-loading-wrapper" role="status" aria-live="polite">