v3: play and open stop competing on a card — list thumbs carry a quiet corner ▶ badge that grows a touch on card hover and a touch more (with a soft dim) on the thumb itself, while the title's "open" cue stands down; link-out thumbs show ↗, compact audio gets its ▶; journal image cards move ▶ to a top-corner badge that settles while the title or vote is hovered; nyt image-card headlines stay white on hover instead of going ink-on-scrim
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 40s

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
khannurien
2026-09-19 21:25:40 +00:00
parent 5205097bb6
commit e2ed493bdd
4 changed files with 125 additions and 3 deletions

View File

@@ -3663,11 +3663,86 @@ body.has-player .chat-fab {
}
.dump-card-preview .rich-content-compact {
position: relative;
width: 100%;
height: 100%;
justify-content: center;
}
/* ── Two targets, one card ──
The card opens the dump page; a playable (or source-linked) thumbnail does
its own thing. Only one of them may look armed at a time: over the thumb
the card's "open" cue (the accent title) stands down and the thumb's own
dim and badge take over. At rest the thumb carries only a small corner
badge, so it reads as "playable" without claiming the whole card. */
.dump-card-inner:has(.dump-card-preview :is(button, a):hover) .dump-card-title {
color: var(--color-text);
}
.dump-card-preview .rich-content-play-overlay,
.rich-content-open-overlay {
position: absolute;
inset: auto auto 5px 5px;
z-index: 1;
width: 22px;
height: 22px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.6);
color: #fff;
font-size: var(--text-xs);
line-height: 1;
pointer-events: none;
transition:
background var(--dur-base) ease,
opacity var(--dur-base) ease,
transform var(--dur-base) ease;
}
/* The badge never moves: card hover grows it a touch; hovering the thumb
itself grows it a touch more while a soft dim fades in behind it. */
.dump-card-inner:hover .dump-card-preview .rich-content-play-overlay {
transform: scale(1.1);
}
.dump-card-preview .rich-content-thumbnail-btn::after,
.dump-card-preview .rich-content-compact::after {
content: "";
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.2);
opacity: 0;
pointer-events: none;
transition: opacity var(--dur-base) ease;
}
/* A link out has nothing to badge at rest — the ↗ only appears on hover. */
.rich-content-open-overlay {
opacity: 0;
}
.dump-card-preview .rich-content-thumbnail-btn:is(:hover, :focus-visible)::after,
.dump-card-preview .rich-content-compact:is(:hover, :focus-visible)::after {
opacity: 1;
}
.dump-card-preview .rich-content-thumbnail-btn:is(:hover, :focus-visible)
.rich-content-play-overlay,
.rich-content-compact:is(:hover, :focus-visible) .rich-content-open-overlay {
transform: scale(1.2);
background: rgba(0, 0, 0, 0.8);
opacity: 1;
}
/* The one playing keeps its badge lit, in the accent, showing ⏸. */
.dump-card-preview .rich-content-thumbnail-btn.is-playing
.rich-content-play-overlay {
background: var(--color-accent);
color: var(--color-on-accent);
}
.dump-card-preview .rich-content-compact-thumbnail {
width: 100%;
height: 100%;
@@ -5421,13 +5496,36 @@ body.has-player .chat-fab {
/* The play affordance is decorative — clicks fall through to the card, which
plays the embed. This keeps the hit target from being covered by the text
overlay on smaller card sizes. */
overlay on smaller card sizes.
Here the card *is* the play button and only the title opens the dump. The
badge sits in the top corner, clear of the text on every card size, and
speaks the list view's language: card hover wakes it a touch, and it
settles back while the pointer is on the title or the vote. */
.journal-card--image .rich-content-play-overlay {
pointer-events: none;
inset: 0.6rem 0.6rem auto auto;
width: 28px;
height: 28px;
border-radius: 50%;
background: rgba(0, 0, 0, 0.6);
/* Keeps it findable on black letterbox bars. */
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.3);
font-size: var(--text-xs);
line-height: 1;
transition:
background var(--dur-base) ease,
transform var(--dur-base) ease;
}
.journal-card--image:hover .rich-content-play-overlay {
background: rgba(0, 0, 0, 0.5);
transform: scale(1.15);
background: rgba(0, 0, 0, 0.75);
}
.journal-card--image:has(.journal-card-title:hover, .journal-card-vote:hover)
.rich-content-play-overlay {
transform: none;
background: rgba(0, 0, 0, 0.6);
}
.journal-card--image .journal-card-overlay {

View File

@@ -208,9 +208,12 @@ export default function FilePreview(
e.stopPropagation();
play(filePlayerItem(dump, fileUrl, mime, token));
}}
aria-label="Play"
>
<VideoThumb src={thumbUrl} fallback={mimeIcon(mime)} />
<span className="rich-content-play-overlay">▶</span>
<span className="rich-content-play-overlay" aria-hidden="true">
▶
</span>
</button>
);
}
@@ -226,6 +229,7 @@ export default function FilePreview(
e.stopPropagation();
play(filePlayerItem(dump, fileUrl, mime, token));
}}
aria-label="Play"
>
{thumbOverride
? <VideoThumb src={thumbOverride} fallback={mimeIcon(mime)} />
@@ -234,6 +238,9 @@ export default function FilePreview(
{mimeIcon(mime)}
</span>
)}
<span className="rich-content-play-overlay" aria-hidden="true">
▶
</span>
</button>
);
}

View File

@@ -96,8 +96,14 @@ export default function RichContentCard(
rel="noopener noreferrer"
className="rich-content-compact"
onClick={(e) => e.stopPropagation()}
aria-label={richContent.siteName
? `Open on ${richContent.siteName}`
: "Open source"}
>
{thumbnail}
<span className="rich-content-open-overlay" aria-hidden="true">
↗
</span>
</a>
);
}

View File

@@ -129,6 +129,17 @@
text-decoration: underline;
text-underline-offset: 2px;
}
/* …except over a photo, where the headline is white on a dark scrim: ink
there goes black-on-black in the light scheme. */
[data-style="nyt"] .journal-card--image .journal-card-title:hover {
color: #fff;
}
/* Over a playable thumb the card's "open" cue stands down (see App.css). */
[data-style="nyt"]
.dump-card-inner:has(.dump-card-preview :is(button, a):hover)
.dump-card-title {
text-decoration: none;
}
/* ── Kickers — section labels & badges in spaced capitals ───────── */
[data-style="nyt"] .comment-section-title,