mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-09 17:36:15 -08:00
fix(epg): keep loading shimmer visible in both themes
This commit is contained in:
1 parent
28ece6f514
commit
edebe0c019
4 files changed
+78
-4
No files matched your search
@@ -24,6 +24,7 @@ import {
|
||||
applyTheme,
|
||||
expectTextContrast,
|
||||
expectThemeSurface,
|
||||
expectSkeletonContrast,
|
||||
} from './theme-contrast';
|
||||
|
||||
const epgCredentials = {
|
||||
@@ -182,6 +183,32 @@ test('@epg @xtream @electron opens the programme dialog from a timeline block an
|
||||
guide.locator('[data-when="now"] .desc').first()
|
||||
);
|
||||
}
|
||||
// Keep a fresh channel's EPG IPC pending so the real list loading
|
||||
// template stays mounted through both theme changes.
|
||||
await app.electronApp.evaluate(({ ipcMain }) => {
|
||||
ipcMain.removeHandler('XTREAM_REQUEST');
|
||||
ipcMain.handle(
|
||||
'XTREAM_REQUEST',
|
||||
() =>
|
||||
new Promise(() => {
|
||||
// Released when this isolated Electron test app closes.
|
||||
})
|
||||
);
|
||||
});
|
||||
await app.mainWindow
|
||||
.locator('[data-test-id="channel-item"]')
|
||||
.nth(1)
|
||||
.click();
|
||||
const skeleton = guide.locator('.sk-time').first();
|
||||
await expect(skeleton).toBeVisible();
|
||||
for (const theme of ['light', 'dark'] as const) {
|
||||
await applyTheme(app.mainWindow, theme);
|
||||
await expectSkeletonContrast(skeleton, guide);
|
||||
await expectSkeletonContrast(
|
||||
guide.locator('.sk-title').first(),
|
||||
guide
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
await closeElectronApp(app);
|
||||
}
|
||||
|
||||
@@ -153,3 +153,48 @@ export async function expectOverlayContrastOnWhite(
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** Skeletons are decorative, but their faintest gradient stop must remain
|
||||
* distinguishable from the guide's background in either theme. */
|
||||
export async function expectSkeletonContrast(
|
||||
skeleton: Locator,
|
||||
guide: Locator
|
||||
) {
|
||||
const background = await guide.evaluate((element) =>
|
||||
getComputedStyle(element)
|
||||
.backgroundColor.match(/[\d.]+/g)!
|
||||
.slice(0, 3)
|
||||
.map(Number)
|
||||
);
|
||||
const { data, info } = await sharp(
|
||||
await skeleton.screenshot({ animations: 'disabled' })
|
||||
)
|
||||
.removeAlpha()
|
||||
.raw()
|
||||
.toBuffer({ resolveWithObject: true });
|
||||
const luminance = (rgb: number[]) =>
|
||||
rgb
|
||||
.map((value) => {
|
||||
const s = value / 255;
|
||||
return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
||||
})
|
||||
.reduce(
|
||||
(sum, value, index) =>
|
||||
sum + value * [0.2126, 0.7152, 0.0722][index],
|
||||
0
|
||||
);
|
||||
const bg = luminance(background);
|
||||
// Middle row avoids the rounded transparent corners.
|
||||
for (let x = 8; x < info.width - 8; x++) {
|
||||
const offset =
|
||||
(Math.floor(info.height / 2) * info.width + x) * info.channels;
|
||||
const fg = luminance([
|
||||
data[offset],
|
||||
data[offset + 1],
|
||||
data[offset + 2],
|
||||
]);
|
||||
expect(
|
||||
(Math.max(fg, bg) + 0.05) / (Math.min(fg, bg) + 0.05)
|
||||
).toBeGreaterThanOrEqual(1.3);
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,9 @@ EPG timeline, list, empty states and programme details use the library-local
|
||||
selection and live accents. Text pairs with the actual surface in both themes;
|
||||
current/playing titles must not force white onto a light selection tint.
|
||||
Past programme text remains readable without reducing opacity on the whole
|
||||
card. Theme changes resolve through CSS on the mounted components immediately.
|
||||
card. List loading shimmer uses translucent primary text stops so placeholders
|
||||
remain visible on either theme’s content surface. Theme changes resolve through
|
||||
CSS on the mounted components immediately.
|
||||
|
||||
Electron E2E measures app-panel foreground/background contrast (including
|
||||
translucency, ancestor opacity and the timeline’s sibling progress fill),
|
||||
|
||||
@@ -402,9 +402,9 @@
|
||||
border-radius: 6px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(255, 255, 255, 0.06),
|
||||
rgba(255, 255, 255, 0.12),
|
||||
rgba(255, 255, 255, 0.06)
|
||||
color-mix(in srgb, $text-primary 18%, transparent),
|
||||
color-mix(in srgb, $text-primary 28%, transparent),
|
||||
color-mix(in srgb, $text-primary 18%, transparent)
|
||||
);
|
||||
background-size: 200% 100%;
|
||||
animation: epg-list-shimmer 1.4s linear infinite;
|
||||
|
||||
Reference in new issue
Block a user