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
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:
102
src/App.css
102
src/App.css
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user