diff --git a/src/App.css b/src/App.css index a7eca11b..92399a30 100644 --- a/src/App.css +++ b/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 { diff --git a/src/components/FilePreview.tsx b/src/components/FilePreview.tsx index bc405b94..132ffbd8 100644 --- a/src/components/FilePreview.tsx +++ b/src/components/FilePreview.tsx @@ -208,9 +208,12 @@ export default function FilePreview( e.stopPropagation(); play(filePlayerItem(dump, fileUrl, mime, token)); }} + aria-label="Play" > - ▶ + ); } @@ -226,6 +229,7 @@ export default function FilePreview( e.stopPropagation(); play(filePlayerItem(dump, fileUrl, mime, token)); }} + aria-label="Play" > {thumbOverride ? @@ -234,6 +238,9 @@ export default function FilePreview( {mimeIcon(mime)} )} + ); } diff --git a/src/components/RichContentCard.tsx b/src/components/RichContentCard.tsx index bd3229f7..9b3fc5d9 100644 --- a/src/components/RichContentCard.tsx +++ b/src/components/RichContentCard.tsx @@ -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} + ); } diff --git a/src/themes/nyt.css b/src/themes/nyt.css index a9677edf..819fab07 100644 --- a/src/themes/nyt.css +++ b/src/themes/nyt.css @@ -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,