diff --git a/css/tailwind.source.css b/css/tailwind.source.css index eb908430..3332a09d 100644 --- a/css/tailwind.source.css +++ b/css/tailwind.source.css @@ -2085,82 +2085,24 @@ } .player-modal__similar-card { - --player-modal-similar-thumb: clamp( - 11rem, - calc(var(--video-modal-secondary-min, 320px) * 0.62), - 17rem - ); - --player-modal-similar-gap: clamp(var(--space-4xs), 0.65vw, var(--space-2xs)); - --player-modal-similar-padding: clamp( - var(--space-4xs), - 0.7vw, - var(--space-sm) - ); - position: relative; - display: grid; - grid-template-columns: var(--player-modal-similar-thumb) minmax(0, 1fr); - align-items: stretch; - gap: var(--player-modal-similar-gap); - padding: var(--player-modal-similar-padding); - width: 100%; - min-width: 0; - transform: translate3d(0, var(--video-card-lift-translate-y, 0), 0); - } - - .player-modal__similar-card::before { - content: ""; - position: absolute; - inset: 0; - z-index: 0; - opacity: var(--video-card-backdrop-opacity, 0); - background-image: var( - --similar-card-thumb-url, - var(--video-card-thumb-url, none) - ); - background-position: center; - background-repeat: no-repeat; - background-size: cover; - transform: translate3d( - 0, - var(--video-card-backdrop-translate-y, 0), - 0 - ) - scale(var(--video-card-backdrop-scale, 1)); - filter: blur(var(--video-card-backdrop-blur, 0)); - transition: - opacity var(--motion-duration-base) var(--motion-ease-in-out), - transform var(--motion-duration-base) var(--motion-ease-in-out), - filter var(--motion-duration-base) var(--motion-ease-in-out); - pointer-events: none; - will-change: opacity, transform, filter; - } - - .player-modal__similar-card > * { - position: relative; - z-index: 1; + @apply focus-ring relative flex w-full min-w-0 items-start gap-3 rounded-xl p-2 transition duration-base ease-out; } .player-modal__similar-card:hover, .player-modal__similar-card:focus-within { - --video-card-backdrop-opacity: 0.425; - --video-card-backdrop-translate-y: 0.15rem; - --video-card-backdrop-scale: 1.12; - --video-card-backdrop-blur: 24px; + background-color: var(--surface-panel-hover); } .player-modal__similar-card-media { - display: block; - position: relative; - inline-size: var(--player-modal-similar-thumb); - block-size: 100%; - max-inline-size: clamp( - calc(var(--space-2xl-plus) * 1.1), - 28vw, - calc(var(--space-2xl-plus) * 2.1) - ); - border-radius: var(--radius-lg); - overflow: hidden; - isolation: isolate; + @apply relative block shrink-0 overflow-hidden rounded-lg bg-surface-alt; + width: 168px; + aspect-ratio: 16 / 9; + } + + @media (max-width: theme("screens.sm")) { + .player-modal__similar-card-media { + width: 140px; + } } .player-modal__similar-card-media img { @@ -2172,97 +2114,45 @@ } .player-modal__similar-card-content { - display: flex; - flex-direction: column; - gap: clamp(var(--space-4xs), 0.6vw, var(--space-2xs)); - min-width: 0; + @apply flex min-w-0 flex-1 flex-col gap-1; } .player-modal__similar-card-title { + @apply text-sm font-semibold leading-snug text-text transition-colors duration-base ease-out; display: -webkit-box; - margin: 0; - font-size: clamp(var(--font-size-sm), 1.05vw, var(--font-size-base)); - font-weight: 600; - line-height: 1.35; - color: var(--color-text); - text-decoration: none; - overflow: hidden; -webkit-line-clamp: 2; -webkit-box-orient: vertical; - transition: color var(--motion-duration-base) var(--motion-ease-in-out); + overflow: hidden; } - .player-modal__similar-card-title:hover, + .player-modal__similar-card:hover .player-modal__similar-card-title, .player-modal__similar-card-title:focus-visible { - color: var(--color-accent); + color: var(--color-accent-strong); } .player-modal__similar-card-author { - display: flex; - align-items: center; - column-gap: clamp(var(--space-5xs), 0.6vw, var(--space-3xs)); - font-size: var(--font-size-xs); - color: var(--color-text-muted); - min-width: 0; - } - - .player-modal__similar-card-avatar { - flex: 0 0 auto; - display: block; - inline-size: clamp(2.5rem, 0.8vw + 2.1rem, 3rem); - block-size: clamp(2.5rem, 0.8vw + 2.1rem, 3rem); - border-radius: var(--radius-full); - overflow: hidden; - background-color: var(--color-surface-alt); - box-shadow: 0 0 0 1px - color-mix(in srgb, var(--color-border-strong) 65%, transparent); - } - - .player-modal__similar-card-avatar-img { - display: block; - width: 100%; - height: 100%; - object-fit: cover; + @apply flex items-center min-w-0; } .player-modal__similar-card-author-meta { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: clamp(var(--space-6xs), 0.35vw, var(--space-5xs)); - min-width: 0; + @apply flex min-w-0 flex-col; } .player-modal__similar-card-author-name { - font-weight: 500; - color: var(--color-text); - min-width: 0; + @apply truncate text-xs font-medium text-muted transition-colors duration-base ease-out; } + .player-modal__similar-card:hover .player-modal__similar-card-author-name { + @apply text-text-strong; + } + + /* Hidden for now to match cleaner modern look, but kept in DOM if needed */ .player-modal__similar-card-author-npub { - display: inline-flex; - align-items: center; - padding-inline: var(--space-6xs); - border-radius: var(--radius-full); - font-family: var(--font-family-mono); - font-size: var(--font-size-2xs); - line-height: 1.2; - color: var(--color-muted-strong); - background-color: color-mix( - in srgb, - var(--color-surface-alt) 80%, - transparent - ); + display: none; } .player-modal__similar-card-meta { - display: flex; - align-items: center; - flex-wrap: wrap; - gap: clamp(var(--space-5xs), 0.5vw, var(--space-4xs)); - font-size: var(--font-size-2xs); - color: var(--color-muted-strong); - min-width: 0; + @apply flex flex-wrap items-center gap-1 text-2xs text-muted-strong; } .player-modal__similar-card-timestamp { @@ -2270,8 +2160,7 @@ } .player-modal__similar-card-separator { - color: inherit; - opacity: 0.8; + @apply text-muted opacity-60; } .player-modal__similar-card-views { diff --git a/js/ui/components/SimilarContentCard.js b/js/ui/components/SimilarContentCard.js index 8cdb6be8..66c615a9 100644 --- a/js/ui/components/SimilarContentCard.js +++ b/js/ui/components/SimilarContentCard.js @@ -310,8 +310,9 @@ export class SimilarContentCard { } build() { + // Modified: Ensure 'group' class for hover effects const root = this.document.createElement("article"); - root.classList.add("player-modal__similar-card", "card"); + root.classList.add("player-modal__similar-card", "card", "group"); root.dataset.component = "similar-content-card"; root.dataset.index = String(this.index); if (this.video.id) { @@ -361,6 +362,9 @@ export class SimilarContentCard { img.alt = this.video.title || ""; img.dataset.videoThumbnail = "true"; + // Modified: Add transition classes for hover zoom + img.classList.add("transition-transform", "duration-300", "ease-out", "group-hover:scale-105"); + const rawThumbnail = typeof this.video.thumbnail === "string" ? this.video.thumbnail.trim() @@ -465,6 +469,7 @@ export class SimilarContentCard { titleLink.title = this.video.title || "Untitled"; titleLink.style.minWidth = "0"; + // Modified order: Title -> Author -> Meta const authorStack = this.buildAuthorStack(); const metaRow = this.buildMetaRow(); @@ -486,6 +491,24 @@ export class SimilarContentCard { wrapper.classList.add("player-modal__similar-card-author"); wrapper.style.minWidth = "0"; + const textWrapper = this.document.createElement("span"); + textWrapper.classList.add("player-modal__similar-card-author-meta"); + textWrapper.style.minWidth = "0"; + + const nameEl = this.document.createElement("span"); + nameEl.classList.add("author-name", "player-modal__similar-card-author-name"); + textWrapper.appendChild(nameEl); + + // Removed npubEl appending here to simplify visual noise in compact card + // but keeping element reference if needed for logic + const npubEl = this.document.createElement("span"); + npubEl.classList.add("author-npub", "player-modal__similar-card-author-npub"); + // textWrapper.appendChild(npubEl); + + // Reordered: Content -> Meta (Avatar logic removed from stack to clean up UI, + // or kept minimal if desired. For now, we keep structure but can style via CSS order if needed) + + // Actually, keeping the avatar structure but CSS will handle sizing/layout const avatarWrapper = this.document.createElement("span"); avatarWrapper.classList.add("player-modal__similar-card-avatar"); @@ -496,21 +519,29 @@ export class SimilarContentCard { avatarImg.alt = ""; avatarWrapper.appendChild(avatarImg); - const textWrapper = this.document.createElement("span"); - textWrapper.classList.add("player-modal__similar-card-author-meta"); - textWrapper.style.minWidth = "0"; - - const nameEl = this.document.createElement("span"); - nameEl.classList.add("author-name", "player-modal__similar-card-author-name"); - textWrapper.appendChild(nameEl); - - const npubEl = this.document.createElement("span"); - npubEl.classList.add("author-npub", "player-modal__similar-card-author-npub"); - textWrapper.appendChild(npubEl); - - wrapper.appendChild(avatarWrapper); + // Append avatar then text wrapper.appendChild(textWrapper); + // Note: To match modern style, we might want text first or no avatar. + // But let's keep avatar for now but maybe hide it via CSS if needed, + // or just show name. + // Let's re-append avatar if we want it visible + // wrapper.appendChild(avatarWrapper); + + // Let's stick to the previous logical structure but rely on CSS flex order or just + // simplified HTML order: + // [Name] + // [Meta] + + // Cleaning up: We want Title -> Name -> Meta + // This wrapper is for the "Author" line. + + // Let's clear wrapper and re-append in clean order + while (wrapper.firstChild) { wrapper.removeChild(wrapper.firstChild); } + + wrapper.appendChild(textWrapper); + + // We preserve refs this.avatarEl = avatarImg; this.authorNameEl = nameEl; this.authorNpubEl = npubEl; @@ -525,6 +556,24 @@ export class SimilarContentCard { row.classList.add("player-modal__similar-card-meta"); row.style.minWidth = "0"; + // Reordered: Views -> Separator -> Time + + const viewEl = this.document.createElement("span"); + viewEl.classList.add("player-modal__similar-card-views", "view-count-text"); + viewEl.dataset.viewCount = ""; + viewEl.textContent = "– views"; + if (this.pointerInfo?.key) { + viewEl.dataset.viewPointer = this.pointerInfo.key; + } + row.appendChild(viewEl); + this.viewCountEl = viewEl; + + const separator = this.document.createElement("span"); + separator.classList.add("player-modal__similar-card-separator"); + separator.setAttribute("aria-hidden", "true"); + separator.textContent = "•"; + row.appendChild(separator); + const timeEl = this.document.createElement("time"); timeEl.classList.add("player-modal__similar-card-timestamp"); if (this.postedAt !== null) { @@ -540,25 +589,6 @@ export class SimilarContentCard { row.appendChild(timeEl); this.timeEl = timeEl; - const shouldShowViews = Boolean(this.pointerInfo?.key); - if (shouldShowViews) { - const separator = this.document.createElement("span"); - separator.classList.add("player-modal__similar-card-separator"); - separator.setAttribute("aria-hidden", "true"); - separator.textContent = "•"; - row.appendChild(separator); - } - - const viewEl = this.document.createElement("span"); - viewEl.classList.add("player-modal__similar-card-views", "view-count-text"); - viewEl.dataset.viewCount = ""; - viewEl.textContent = "– views"; - if (this.pointerInfo?.key) { - viewEl.dataset.viewPointer = this.pointerInfo.key; - } - row.appendChild(viewEl); - this.viewCountEl = viewEl; - return row; }