mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-14 21:26:15 -08:00
feat(switcher): rebuild the playlist switcher as an overlay popover
The switcher's mat-menu becomes a CDK connected overlay (app-playlist-switcher-panel), 440px wide, with a dimmed, blurred backdrop; only its list scrolls and row menus open above it. - Header with the source count, Add playlist and All sources. - Search by name or host, autofocused; the type filter is one segmented control (All / M3U / Xtream / Stalker with counts) instead of three checkboxes, remembered between openings (the old checkbox setting is migrated). The search is no longer kept between openings. - "Recent" (the three most recently opened, kept across restarts) above "All" in the Sources page order, as compact source rows: the current one tinted with a check. Each row's ⋯ menu holds Refresh, Playlist info, Account info, Check again and Remove (with Undo); the footer's info, account and add actions moved there and to the header. - Keyboard: a listbox driven by aria-activedescendant from the search field. Arrow keys move and wrap, Enter opens, Shift+F10 opens the row's menu, Escape closes and returns focus to the trigger. Hints in the footer. - Deleting from a row menu moves focus to the toast's Undo, since the row (and its focus) left the page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
106414c118
commit
9feab4f83b
49 files changed
+1987
-1813
No files matched your search
@@ -80,7 +80,7 @@ export async function importPlaylist(page: Page): Promise<string> {
|
||||
.getByRole('button', { name: 'Add playlist', exact: true })
|
||||
.click(),
|
||||
]);
|
||||
await expect(page.getByText('1 channels')).toBeVisible();
|
||||
await expect(page.getByText('1 channel', { exact: false })).toBeVisible();
|
||||
return page.url();
|
||||
}
|
||||
|
||||
|
||||
@@ -182,12 +182,15 @@ test('@stalker account info dialog shows subscription facts from the portal', as
|
||||
}) => {
|
||||
await addStalkerPortal(page);
|
||||
|
||||
// Open the header playlist switcher and its "Account info" entry for
|
||||
// the active stalker portal.
|
||||
await page.locator('.playlist-switcher-trigger').click();
|
||||
// Open the header playlist switcher and the "Account info" entry in the
|
||||
// active stalker portal's row menu.
|
||||
await page.locator('[data-test-id="playlist-switcher-trigger"]').click();
|
||||
await page
|
||||
.locator('.context-action-item', { hasText: 'Account info' })
|
||||
.locator(
|
||||
'app-playlist-switcher-panel [role="option"][aria-current="true"] .source-row__more'
|
||||
)
|
||||
.click();
|
||||
await page.getByRole('menuitem', { name: 'Account info' }).click();
|
||||
|
||||
const dialog = page.locator('mat-dialog-container');
|
||||
await expect(dialog).toBeVisible();
|
||||
|
||||
@@ -61,18 +61,15 @@ async function openPlaylistDetailsDialog(page: Page, title: string) {
|
||||
await playlistSettingsButton.click();
|
||||
} else {
|
||||
await page
|
||||
.locator('app-playlist-switcher .playlist-switcher-trigger')
|
||||
.locator('[data-test-id="playlist-switcher-trigger"]')
|
||||
.click();
|
||||
|
||||
const switcherMenu = page.getByRole('menu').filter({ hasText: title });
|
||||
const sourceRow = switcherMenu
|
||||
.locator('.playlist-item')
|
||||
const sourceRow = page
|
||||
.locator('app-playlist-switcher-panel [role="option"]')
|
||||
.filter({ hasText: title })
|
||||
.first();
|
||||
await expect(sourceRow).toBeVisible();
|
||||
await sourceRow
|
||||
.getByRole('button', { name: 'Playlist actions' })
|
||||
.click();
|
||||
await sourceRow.locator('.source-row__more').click();
|
||||
await page.getByRole('menuitem', { name: 'Playlist info' }).click();
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user