fix(settings): fit long versions in the sidebar and keep side panels off the window edge (#1875)

* fix(settings): fit long versions in the sidebar and keep side panels off the window edge

The About item's version was flex-shrink: 0 beside a zero-basis label, so a
nightly build string squeezed "About" to nothing and overflowed the panel.
The label now has an auto basis and the version yields first, truncating
with an ellipsis and keeping the full string in its tooltip.

The context panel used height: 100% plus padding without a border-box reset,
so it ran 24px past its host and the footer item sat on the window edge.
The host is now a flex column and the panel fills it as a flex item, which
restores the bottom padding for every side panel variant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(settings): answer the GitHub releases check in the version layout E2E

The sidebar renders the version only after the releases request answers.
CI runners are rate-limited on api.github.com, so the tag never appeared
and the test failed on its first locator. Fulfil the request locally with
an older release so the version shows without an update badge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5.5 authored and GitHub committed 2026-10-10 21:49:57 +02:00
1 parent e1d4f00d93
commit 91e277e9ba
6 files changed
+83 -4

No files matched your search

+50
View File
@@ -229,6 +229,56 @@ test.describe('Settings', () => {
).toHaveAttribute('aria-checked', 'true');
});
test('@settings @web About keeps its label and clears the window bottom', async ({
page,
}) => {
// The sidebar shows the version only once the GitHub releases check
// answers; CI runners are often rate-limited there, so answer locally
// with an older release (no update badge replaces the version).
await page.route('**/repos/4gray/iptvnator/releases*', (route) =>
route.fulfill({
json: [{ created_at: '2020-01-01T00:00:00Z', name: '0.0.1' }],
})
);
await openSettings(page);
const about = page.locator(
'.settings-nav__footer [data-test-id="settings-section-about"]'
);
const version = about.locator('[data-test-id="settings-nav-version"]');
await expect(version).toBeVisible();
// A nightly build string is far wider than the default panel.
await version.evaluate((node) => {
node.textContent = '0.25.0-nightly.20261010.3937';
});
const layout = await about.evaluate((link) => {
const label = link.querySelector('.nav-item-label') as HTMLElement;
const tag = link.querySelector(
'[data-test-id="settings-nav-version"]'
) as HTMLElement;
const panel = link.closest('.context-panel') as HTMLElement;
const linkBox = link.getBoundingClientRect();
return {
labelClipped: label.scrollWidth > label.clientWidth,
versionClipped: tag.scrollWidth > tag.clientWidth,
linkOverflows: link.scrollWidth > link.clientWidth,
linkBottom: linkBox.bottom,
panelBottom: panel.getBoundingClientRect().bottom,
viewportHeight: window.innerHeight,
};
});
expect(layout.labelClipped).toBe(false);
expect(layout.versionClipped).toBe(true);
expect(layout.linkOverflows).toBe(false);
// The panel ends at the window edge, and its bottom padding keeps the
// footer item off it.
expect(layout.panelBottom).toBeLessThanOrEqual(layout.viewportHeight);
expect(
layout.viewportHeight - layout.linkBottom
).toBeGreaterThanOrEqual(12);
});
test('@settings @web Esc leaves settings like the header Back', async ({
page,
}) => {