99puxwol5: Show native video controls on trending cards only after the first play

This commit is contained in:
2026-10-20 09:43:19 -06:00
parent 583e287af6
commit 7647d78550
2 changed files with 12 additions and 8 deletions
+9 -7
View File
@@ -17,11 +17,14 @@ interface Props {
* The trending card's 16:9 frame. Video answers play inline as a <video> with a
* poster; audio keeps its <audio> control under the frame; no url shows the
* thumbnail only. The glass chip, play button, views and kind label sit over
* the thumbnail and step aside while a video plays.
* the thumbnail and step aside once a video has started, and only then does the
* video show its native controls.
*/
export function MinnectMedia({ media, thumbnailUrl, question, who, pictureUrl, views = null }: Props) {
const [videoFailed, setVideoFailed] = useState(false);
const [playing, setPlaying] = useState(false);
// Native controls only after the first play, so the frame never shows our
// play button and the browser's controls at the same time.
const [started, setStarted] = useState(false);
const video = useRef<HTMLVideoElement | null>(null);
const audio = useRef<HTMLAudioElement | null>(null);
@@ -36,20 +39,19 @@ export function MinnectMedia({ media, thumbnailUrl, question, who, pictureUrl, v
return (
<>
<div className={`trend-media${playing ? " trend-media-playing" : ""}`}>
<div className={`trend-media${started ? " trend-media-playing" : ""}`}>
{isVideo ? (
<video
ref={video}
className="minnect-thumb minnect-video"
controls
controls={started}
playsInline
preload="none"
src={media.url}
poster={thumbnailUrl ?? undefined}
aria-label={`Play answer from ${who}`}
onPlay={() => setPlaying(true)}
onPause={() => setPlaying(false)}
onEnded={() => setPlaying(false)}
onClick={started ? undefined : play}
onPlay={() => setStarted(true)}
onError={() => setVideoFailed(true)}
/>
) : thumbnailUrl ? (
+3 -1
View File
@@ -57,7 +57,9 @@ describe("TrendingMinnectsRail", () => {
minnects: [minnect({ media: { kind: "video", url, duration: 9, waveform: null } })],
}));
expect(out).toContain("<video");
expect(out).toContain("controls");
// Before the first play only our play button shows, not the native controls too.
expect(out).not.toMatch(/<video[^>]*controls/);
expect(out).toContain('class="trend-play"');
expect(out).toContain("preload=\"none\"");
expect(out).toContain("X-Amz-Signature=abc");
expect(out).toContain('poster="https://x/t.jpg"');