Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions desktop/src/shared/styles/globals/video-review.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@
The review dialog uses the shadcn "neutral" dark palette regardless of
the app theme. Applied together with `.dark` on the portal root; this
block is intentionally unlayered so it overrides the layered theme vars. */
.video-review-controls {
transition: opacity 150ms cubic-bezier(0.23, 1, 0.32, 1);
}

@media (hover: hover) and (pointer: fine) {
.video-review-media-surface .video-review-controls {
pointer-events: none;
opacity: 0;
}

.video-review-media-surface:hover .video-review-controls,
.video-review-media-surface:has(:focus-visible) .video-review-controls {
pointer-events: auto;
opacity: 1;
}
}

@media (prefers-reduced-motion: reduce) {
.video-review-controls {
transition: none;
}
}

.video-review-theme {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
Expand Down
4 changes: 2 additions & 2 deletions desktop/src/shared/ui/VideoPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1697,7 +1697,7 @@ function VideoReviewDialog({
ref={videoAreaRef}
>
<div
className="relative isolate flex max-h-full min-w-0 max-w-full items-center justify-center"
className="video-review-media-surface relative isolate flex max-h-full min-w-0 max-w-full items-center justify-center"
style={fittedVideoStyle}
>
<VideoGlow videoRef={videoRef} />
Expand Down Expand Up @@ -1764,7 +1764,7 @@ function VideoReviewDialog({
visible={!hasVisibleFrame}
/>
</div>
<div className="absolute inset-x-2 bottom-2 z-20 sm:inset-x-4 sm:bottom-3">
<div className="video-review-controls absolute inset-x-2 bottom-2 z-20 sm:inset-x-4 sm:bottom-3">
<div className="relative isolate flex items-center gap-2 rounded-xl px-2 py-1.5">
<GlassSurface />
<button
Expand Down
61 changes: 61 additions & 0 deletions desktop/tests/e2e/video-attachment.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,67 @@ test("inline video hover reveals a timeline without a second play control", asyn
.toBe(true);
});

test("expanded video controls fade with the video hover boundary", async ({
page,
}) => {
await installVideoReviewHarness(page);

await page.goto("/");
await page.getByTestId("channel-general").click();
await expect(page.getByTestId("chat-title")).toHaveText("general");
await waitForMockLiveSubscription(page, "general");

await emitMockMessage(page, "general", `![video](${VIDEO_URL})`, {
extraTags: [
[
"imeta",
`url ${VIDEO_URL}`,
"m video/mp4",
`x ${VIDEO_SHA}`,
"size 987654",
"dim 160x80",
"duration 12.5",
`image ${POSTER_DATA_URL}`,
"filename launch-demo.mp4",
],
],
});

await page.getByRole("button", { name: "Open video review" }).last().click();

const dialog = page.getByTestId("video-review-dialog");
const mediaSurface = dialog.locator(".video-review-media-surface");
const controls = dialog.locator(".video-review-controls");
await expect(mediaSurface).toBeVisible();

await dialog.getByTestId("video-review-comments-panel").hover();
const restingControlsBox = await controls.boundingBox();
expect(restingControlsBox).not.toBeNull();
await expect(controls).toHaveCSS("opacity", "0");

await mediaSurface.hover();
await expect(controls).toHaveCSS("opacity", "1");
const hoveredControlsBox = await controls.boundingBox();
expect(hoveredControlsBox).not.toBeNull();
expect(
Math.abs((hoveredControlsBox?.y ?? 0) - (restingControlsBox?.y ?? 0)),
).toBeLessThan(0.5);
await expect(controls).toHaveCSS("transition-property", "opacity");
await expect(controls).toHaveCSS("transition-duration", "0.15s");

const playButton = controls.getByRole("button", { name: /review video$/ });
await playButton.click();
await expect(playButton).toBeFocused();
await dialog.getByTestId("video-review-comments-panel").hover();
await expect(controls).toHaveCSS("opacity", "0");

await page.keyboard.press("Tab");
await expect(controls).toHaveCSS("opacity", "1");

await page.emulateMedia({ reducedMotion: "reduce" });
await expect(controls).toHaveCSS("transition-property", "none");
});

test("video replies in threads open the review comments view", async ({
page,
}) => {
Expand Down
Loading