feat(design): players on touch and the C5 control set, restart on the card (E28 S3f2)
Plex player: a finger's tap on the picture only shows or hides the controls, the hide timer starts with playback, a double-tap on a side third skips 10 s, the seek bar is a 2.75rem touch-none hit area with its head shown on touch. The row is play/pause, Back by position, Next only with a next item, mute, time, tracks, a fixed ⋯ (settings, media info, stats, shortcuts, download) and fullscreen; Stop, Restart and the ±10 s buttons are gone. A started card shows the video card's Continue + Restart pair (one shared MediaResumeButtons, beside the picture's button), and its menu lists the restart; the player opens that item at 0 (fromStart). YouTube modal: the description opens from an ⓘ, the queue arrows sit inside the screen.
This commit is contained in:
@@ -166,6 +166,57 @@ describe("PlexPosterCard with a next episode", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// C5: a started item's picture offers Continue and Restart (the video card's pair) instead of a Play;
|
||||
// they sit beside the picture's own button, never inside it.
|
||||
describe("a started Plex card", () => {
|
||||
const started: PlexCard = {
|
||||
...movie("in_progress"),
|
||||
position_seconds: 600,
|
||||
duration_seconds: 6000,
|
||||
};
|
||||
|
||||
it("shows Continue + Restart, not the Play, and each does its own thing", () => {
|
||||
const onOpen = vi.fn();
|
||||
const onRestart = vi.fn();
|
||||
const { container } = render(
|
||||
<PlexPosterCard card={started} onOpen={onOpen} onRestart={onRestart} />,
|
||||
);
|
||||
const picture = screen.getByRole("button", { name: "M" });
|
||||
expect(picture.querySelector(".reveal-hover.inset-0 svg")).toBeNull();
|
||||
const cont = screen.getByRole("button", { name: "card.continue" });
|
||||
const restart = screen.getByRole("button", { name: "card.restart" });
|
||||
expect(picture.contains(cont) || picture.contains(restart)).toBe(false);
|
||||
fireEvent.click(restart);
|
||||
expect(onRestart).toHaveBeenCalledTimes(1);
|
||||
expect(onOpen).not.toHaveBeenCalled();
|
||||
fireEvent.click(cont);
|
||||
expect(onOpen).toHaveBeenCalledTimes(1);
|
||||
// Mouse only: on touch the tap continues and the "…" has the restart.
|
||||
expect(cont.closest(".reveal-hover")).not.toBeNull();
|
||||
expect(container.querySelector(".flex-col.reveal-hover")).not.toBeNull(); // a poster stacks
|
||||
});
|
||||
|
||||
it("an episode's landscape picture keeps the pair side by side", () => {
|
||||
const { container } = render(
|
||||
<EpisodeCard
|
||||
ep={{ ...episode("in_progress"), position_seconds: 60, duration_seconds: 1200 }}
|
||||
onPlay={vi.fn()}
|
||||
onRestart={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByRole("button", { name: "card.restart" })).toBeTruthy();
|
||||
expect(container.querySelector(".flex-col.reveal-hover")).toBeNull();
|
||||
});
|
||||
|
||||
it("a not-started or watched card keeps the one Play", () => {
|
||||
render(<PlexPosterCard card={movie("watched")} onOpen={vi.fn()} onRestart={vi.fn()} />);
|
||||
expect(screen.queryByRole("button", { name: "card.restart" })).toBeNull();
|
||||
expect(
|
||||
screen.getByRole("button", { name: "M" }).querySelector(".reveal-hover.inset-0 svg"),
|
||||
).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("SeasonCard a11y", () => {
|
||||
it("names the watched-toggle and the add-season button", () => {
|
||||
render(<SeasonCard se={season()} onOpen={vi.fn()} onToggleWatched={vi.fn()} onAdd={vi.fn()} />);
|
||||
|
||||
Reference in New Issue
Block a user