mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 11:06:16 -08:00
UI-24 from the UI consistency audit.
- No-artwork slides paint their gradient in CSS from the slide hue: a light
tint in the light theme, unchanged near-black in the dark one. The dark
gradient under the light page-coloured scrim read as a grey slab.
- The side scrim holds 88% of the page colour up to the slide's right edge
(inset + min(560px, 55%)), so the end of a full slide no longer sits on
about 45%.
- Narrow layout (container <= 720px): a full-bleed 90% scrim behind the text
block, a scrim-coloured text shadow, and an entrance without a fade so
that scrim never flashes the art on a rotation.
- --hero-body is 85% of the heading colour (was 72%).
- Light --app-rating-color #a16207 -> #7a4a00: measured 3.36:1 on the chip
over artwork, now 5.10:1. The details pages share the chip and token.
- Buttons cap at the slide width and end long labels in an ellipsis.
- The page gets one visually hidden h1 ("Dashboard"); slide titles are h2.
- One live region outside the re-created slide announces slide changes;
progress bars are named and VOD ones read "N% watched"; dots are 24px.
dashboard-hero-legibility.e2e.ts replaces every image with a checkerboard
and measures each piece of slide text from the screen in both themes, wide
and narrow, for backdrop, poster, no-artwork and live slides. On master the
worst cases were 2.35:1 (body text) and 2.65:1 (pills).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
55 lines
1.9 KiB
TypeScript
55 lines
1.9 KiB
TypeScript
import type { Page } from '@playwright/test';
|
|
import { expect } from './electron-test-fixtures';
|
|
|
|
// Steps that put content on the dashboard: favourites from the Live TV list
|
|
// and from a detail page, and the way back from that detail page.
|
|
|
|
export async function goBackFromDetail(page: Page): Promise<void> {
|
|
// Return to the list: the header's Back is route-level in browse and
|
|
// watch alike (closing the player is the bar's own Close button).
|
|
const backButton = page.getByTestId('workspace-header-back');
|
|
|
|
await expect(backButton).toBeVisible({ timeout: 20000 });
|
|
try {
|
|
await backButton.click({ timeout: 5000 });
|
|
} catch {
|
|
await backButton.evaluate((button: HTMLButtonElement) =>
|
|
button.click()
|
|
);
|
|
}
|
|
}
|
|
|
|
// By accessible name, not class: the Xtream movie detail's favorite control is
|
|
// an icon-only button that carries its label in aria-label, while series and
|
|
// Stalker details still use the labeled variant. This matches both.
|
|
export async function addCurrentDetailToFavorites(page: Page): Promise<void> {
|
|
const addButton = page
|
|
.getByRole('button', { name: /add to favorites/i })
|
|
.first();
|
|
|
|
await expect(addButton).toBeVisible({ timeout: 20000 });
|
|
await addButton.click();
|
|
await expect(
|
|
page.getByRole('button', { name: /remove from favorites/i }).first()
|
|
).toBeVisible({
|
|
timeout: 20000,
|
|
});
|
|
}
|
|
|
|
export async function toggleFavoriteForChannel(
|
|
page: Page,
|
|
title: string
|
|
): Promise<void> {
|
|
const item = page
|
|
.locator('[data-test-id="channel-item"]')
|
|
.filter({ hasText: title })
|
|
.first();
|
|
|
|
await expect(item).toBeVisible({ timeout: 20000 });
|
|
await item.hover();
|
|
await item.locator('.favorite-button').first().click();
|
|
await expect(item.locator('.favorite-button mat-icon').first()).toHaveText(
|
|
/star/
|
|
);
|
|
}
|