From 5317c63158ddac63453bebc012b26ea452f032cb Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Thu, 23 Oct 2025 16:04:25 -0400 Subject: [PATCH] Add compact variant for video cards --- css/tailwind.source.css | 28 +++++++++ js/ui/components/VideoCard.js | 115 +++++++++++++++++++++++++--------- 2 files changed, 114 insertions(+), 29 deletions(-) diff --git a/css/tailwind.source.css b/css/tailwind.source.css index d7739ee4..3795fb0f 100644 --- a/css/tailwind.source.css +++ b/css/tailwind.source.css @@ -960,6 +960,34 @@ z-index: 1; } + .card--compact { + @apply flex flex-row items-stretch gap-md; + } + + .card--compact .video-card__media { + @apply block w-40 shrink-0 overflow-hidden rounded-lg sm:w-56; + } + + .card--compact .video-card__content { + @apply flex min-w-0 flex-1 flex-col gap-sm p-md; + } + + .card--compact .video-card__title { + @apply text-base font-semibold leading-snug; + } + + .card--compact .video-card__author-name { + @apply text-xs; + } + + .card--compact .video-card__meta { + @apply mt-0 flex items-center gap-2 text-2xs text-muted-strong; + } + + .card--compact .video-card__meta .view-count-text { + @apply text-2xs; + } + .card:hover, .card:focus-within { --video-card-lift-translate-y: -0.35rem; diff --git a/js/ui/components/VideoCard.js b/js/ui/components/VideoCard.js index cbf5001c..8e882d2e 100644 --- a/js/ui/components/VideoCard.js +++ b/js/ui/components/VideoCard.js @@ -20,6 +20,7 @@ export class VideoCard { helpers = {}, assets = {}, state = {}, + variant = "default", ensureGlobalMoreMenuHandlers, onRequestCloseAllMenus, nsfwContext = null, @@ -85,6 +86,12 @@ export class VideoCard { this.designSystem = normalizeDesignSystemContext(designSystem); + const normalizedVariant = + typeof variant === "string" && variant.trim().toLowerCase() === "compact" + ? "compact" + : "default"; + this.variant = normalizedVariant; + this.nsfwContext = { isNsfw: Boolean(nsfwContext?.isNsfw), allowNsfw: nsfwContext?.allowNsfw !== false, @@ -324,8 +331,14 @@ export class VideoCard { build() { const doc = this.document; + const isCompact = this.variant === "compact"; + const cardClassNames = ["card"]; + if (isCompact) { + cardClassNames.push("card--compact"); + } + const root = this.createElement("div", { - classNames: ["card"] + classNames: cardClassNames, }); this.root = root; @@ -343,15 +356,22 @@ export class VideoCard { this.applySourceDatasets(); this.applyModerationDatasets(); + const anchorClassNames = [ + "block", + "cursor-pointer", + "relative", + "group", + "overflow-hidden", + "video-card__media", + ]; + if (isCompact) { + anchorClassNames.push("rounded-lg", "flex-shrink-0"); + } else { + anchorClassNames.push("rounded-t-lg"); + } + const anchor = this.createElement("a", { - classNames: [ - "block", - "cursor-pointer", - "relative", - "group", - "rounded-t-lg", - "overflow-hidden" - ], + classNames: anchorClassNames, attrs: { href: this.shareUrl } @@ -360,33 +380,48 @@ export class VideoCard { this.anchorEl = anchor; const ratio = this.createElement("div", { - classNames: ["ratio-16-9"] + classNames: ["ratio-16-9", "video-card__media-ratio"], }); const thumbnail = this.buildThumbnail(); ratio.appendChild(thumbnail); anchor.appendChild(ratio); + const contentClassNames = [ + "video-card__content", + "p-md", + "bv-stack", + "bv-stack--tight", + ]; + if (isCompact) { + contentClassNames.push("flex-1"); + } + const content = this.createElement("div", { - classNames: ["p-md", "bv-stack", "bv-stack--tight"] + classNames: contentClassNames, }); this.contentEl = content; + const titleClassNames = [ + "video-card__title", + isCompact ? "text-base" : "text-lg", + isCompact ? "font-semibold" : "font-bold", + "text-text", + "line-clamp-2", + "cursor-pointer", + ]; + if (isCompact) { + titleClassNames.push("leading-snug"); + } + const title = this.createElement("h3", { - classNames: [ - "video-card__title", - "text-lg", - "font-bold", - "text-text", - "line-clamp-2", - "cursor-pointer" - ], + classNames: titleClassNames, textContent: this.video.title }); title.dataset.videoId = this.video.id; this.titleEl = title; const header = this.createElement("div", { - classNames: ["flex", "items-center", "justify-between"] + classNames: ["flex", "items-center", "justify-between"], }); const authorSection = this.buildAuthorSection(); @@ -642,8 +677,13 @@ export class VideoCard { } buildAuthorSection() { + const isCompact = this.variant === "compact"; const wrapper = this.createElement("div", { - classNames: ["flex", "items-center", "space-x-3"] + classNames: [ + "flex", + "items-center", + isCompact ? "space-x-2" : "space-x-3", + ], }); const avatarWrapper = this.createElement("div", { @@ -683,8 +723,14 @@ export class VideoCard { const authorMeta = this.createElement("div", { classNames: ["min-w-0"] }); const authorName = this.createElement("p", { - classNames: ["text-sm", "text-muted", "author-name", "cursor-pointer"], - textContent: "Loading name..." + classNames: [ + isCompact ? "text-xs" : "text-sm", + "text-muted", + "author-name", + "cursor-pointer", + "video-card__author-name", + ], + textContent: "Loading name...", }); if (this.video.pubkey) { authorName.dataset.pubkey = this.video.pubkey; @@ -694,10 +740,11 @@ export class VideoCard { classNames: [ "flex", "items-center", - "text-xs", + isCompact ? "gap-2" : "mt-1", + isCompact ? "text-2xs" : "text-xs", "text-muted-strong", - "mt-1" - ] + "video-card__meta", + ], }); const timeEl = this.createElement("span", { @@ -707,8 +754,13 @@ export class VideoCard { this.timestampEl = timeEl; if (this.pointerInfo && this.pointerInfo.key) { + const dotClassNames = ["text-muted-strong"]; + if (!isCompact) { + dotClassNames.push("mx-1"); + } + const dot = this.createElement("span", { - classNames: ["mx-1", "text-muted-strong"], + classNames: dotClassNames, textContent: "•" }); dot.setAttribute("aria-hidden", "true"); @@ -851,9 +903,10 @@ export class VideoCard { } buildBadgesContainer() { + const isCompact = this.variant === "compact"; const pieces = []; - if (this.playbackUrl) { + if (!isCompact && this.playbackUrl) { const badge = this.createElement("span", { classNames: ["badge", "url-health-badge"] }); @@ -864,7 +917,7 @@ export class VideoCard { pieces.push(badge); } - if (this.magnetSupported && this.magnetProvided) { + if (!isCompact && this.magnetSupported && this.magnetProvided) { const badge = this.createElement("span", { classNames: ["badge", "torrent-health-badge"] }); @@ -1904,6 +1957,10 @@ export class VideoCard { } buildDiscussionCount() { + if (this.variant === "compact") { + return null; + } + if (this.video.enableComments === false) { return null; }