From 79518014a6d51b5e9eda2642a5ec9e1cd1bb6695 Mon Sep 17 00:00:00 2001 From: SandObserver <260779319+SandObserver@users.noreply.github.com> Date: Sun, 25 Oct 2026 21:21:22 -0400 Subject: [PATCH] Fix home screen swipe, folder motion, search and RTL labels --- e2e/rtl-mirroring.spec.js | 40 ++++ ui/admin/index.html | 6 +- ui/css/admin.css | 5 +- ui/css/dashboard.css | 82 ++++--- ui/css/tokens.css | 6 +- ui/index.html | 6 +- ui/js/admin-app-form.js | 10 +- ui/js/admin-auth.js | 4 +- ui/js/admin-color-control.js | 6 +- ui/js/admin-drag.js | 2 +- ui/js/admin-list.js | 8 +- ui/js/admin-settings.js | 8 +- ui/js/admin-shared.js | 2 +- ui/js/admin-widget-form.js | 8 +- ui/js/admin.js | 20 +- ui/js/background.js | 2 +- ui/js/dashboard-logic.js | 47 ++++ ui/js/dashboard.js | 55 ++--- ui/js/fluid-hover.js | 5 +- ui/js/label-contrast.js | 4 +- ui/js/listbox.js | 4 +- ui/js/spotlight.js | 24 +- ui/js/ui.js | 277 ++++++++++++++++++------ ui/js/utils.js | 113 ++++++---- ui/js/widget-config-form.js | 8 +- ui/test/contrast.test.mjs | 8 +- ui/test/dashboard-localisation.test.mjs | 11 +- ui/test/dashboard-logic.test.mjs | 78 +++++++ ui/test/empty-dashboard.test.mjs | 20 +- ui/test/fluid-hover.test.mjs | 34 +++ ui/test/folder-overlay.test.mjs | 50 +++++ ui/test/live-region.test.mjs | 9 +- ui/test/motion-preferences.test.mjs | 55 ++++- ui/test/pagination.test.mjs | 80 ++++++- ui/test/rtl-logical-properties.test.mjs | 4 +- ui/test/scrolls-sideways.test.mjs | 20 +- ui/test/tile-press.test.mjs | 68 ++++++ ui/test/user-text-direction.test.mjs | 37 +++- ui/widgets/upnext/index.html | 2 +- 39 files changed, 975 insertions(+), 253 deletions(-) create mode 100644 ui/test/tile-press.test.mjs diff --git a/e2e/rtl-mirroring.spec.js b/e2e/rtl-mirroring.spec.js index 84e0a7f0..128838e6 100644 --- a/e2e/rtl-mirroring.spec.js +++ b/e2e/rtl-mirroring.spec.js @@ -63,3 +63,43 @@ test('a row title and its subtitle share a leading edge', async ({ page, request const gap = Math.abs(name - meta); expect(gap, `the title and its subtitle start ${Math.round(gap)}px apart`).toBeLessThan(8); }); + +/* A tile name takes the direction of its own script, whatever the page's. The + localisation clipping check skips anything with an ellipsis, so a name cut + from the wrong end passes there. WebKit reports a clipped first glyph inside + the box, so the computed direction is the check that holds in both engines. */ +for (const language of ['en', 'fa']) { + test(`a long tile name keeps its start on a ${language} dashboard`, async ({ page, request }) => { + const names = [ + ['fa', 'مدیریت سرورهای خانگی و پشتیبانگیری خودکار شبانه', 'rtl'], + ['en', 'Benachrichtigungseinstellungen Verwaltung', 'ltr'], + ]; + await seedConfig(request, { + items: names.map(([id, label]) => app(id, label)), + settings: { language, showLabels: { desktop: true } }, + }); + await dismissSetupPrompt(request); + await page.goto('/'); + for (const [id, label, dir] of names) { + const tile = page.locator(`#pages .icon[data-tile-name="${label}"] .ilabel`); + await tile.waitFor({ state: 'visible' }); + const seen = await tile.evaluate(el => { + const walk = document.createTreeWalker(el, NodeFilter.SHOW_TEXT); + const text = /** @type {Text} */ (walk.nextNode()); + const range = document.createRange(); + range.setStart(text, 0); + range.setEnd(text, 1); + const glyph = range.getBoundingClientRect(); + const box = el.getBoundingClientRect(); + return { + dir: getComputedStyle(el).direction, + cut: el.scrollWidth > el.clientWidth, + inside: glyph.left >= box.left - 1 && glyph.right <= box.right + 1, + }; + }); + expect(seen.cut, `${id}: the name is not long enough to be cut`).toBe(true); + expect(seen.dir, `${id}: the label follows the page, not its text`).toBe(dir); + expect(seen.inside, `${id}: the first letter is cut off`).toBe(true); + } + }); +} diff --git a/ui/admin/index.html b/ui/admin/index.html index 0d5fd484..1917e3fb 100644 --- a/ui/admin/index.html +++ b/ui/admin/index.html @@ -10,8 +10,8 @@