From 4855bc7c8de2adeae4aa6d70de48803716a82398 Mon Sep 17 00:00:00 2001 From: timmy Date: Tue, 25 Aug 2026 10:08:55 +0000 Subject: [PATCH] feat: contain mobile Search focus through Preview (Closes #1390) --- frontend/dashboard.js | 16 ++- frontend/index.html | 3 +- frontend/mobile-search-modal.js | 83 +++++++++++++ frontend/service-worker.js | 1 + src/frontend_bundle.py | 2 +- .../test_mobile_search_preview_navigation.py | 59 ++++++++++ tests/test_mobile_search_modal.py | 110 ++++++++++++++++++ tests/test_service_worker.py | 1 + 8 files changed, 270 insertions(+), 5 deletions(-) create mode 100644 frontend/mobile-search-modal.js create mode 100644 tests/test_mobile_search_modal.py diff --git a/frontend/dashboard.js b/frontend/dashboard.js index 5721d4b..f9d00cf 100644 --- a/frontend/dashboard.js +++ b/frontend/dashboard.js @@ -5855,6 +5855,7 @@ mediaQuery: window.matchMedia('(max-width: 600px)'), schedule: callback => requestAnimationFrame(callback), }); + const searchModal = createMobileSearchModal({document}); function closeSearchPreview(navigate = true) { if (searchPreviewReturnKind === 'following') { searchPreview.close(); @@ -5870,7 +5871,7 @@ qs('#cmd-palette').classList.add('open'); qs('#cmd-input').setAttribute('aria-expanded', 'true'); renderCommands(qs('#cmd-input').value); - qs('#cmd-input').focus(); + searchModal.transition(qs('#cmd-palette'), { initialFocus:qs('#cmd-input') }); } const next = searchPreview.next; async function openPreviewWorkInMyWork(detail) { @@ -5892,6 +5893,7 @@ mobileSearchViewport.rememberScroll(); searchPreviewReturnKind = 'search'; searchPreview.open(item.result).catch(() => {}); + searchModal.transition(qs('#search-preview'), { initialFocus:qs('#close-search-preview') }); taskOverlayHistory.open('search-preview', { query:qs('#cmd-input').value, scope:currentSearchScope(), preview:item.result, }); @@ -5938,7 +5940,10 @@ mobileSearchViewport.open(); mobileSearchViewport.restoreScroll(); qs('#cmd-input').setAttribute('aria-expanded', 'true'); - qs('#cmd-input').focus(); + searchModal.activate(qs('#cmd-palette'), { + opener:document.activeElement, + initialFocus:qs('#cmd-input'), + }); commandSelection = -1; renderCommands(qs('#cmd-input').value); } @@ -5957,6 +5962,7 @@ else { searchPreview.close(); mobileSearchViewport.close(); + searchModal.deactivate(); } searchPreviewReturnKind = null; } @@ -5964,7 +5970,7 @@ qs('#cmd-palette').classList.remove('open'); qs('#cmd-input').setAttribute('aria-expanded', 'false'); mobileSearchViewport.close(); - qs('#open-palette').focus(); + searchModal.deactivate(); } if (previous === 'plan-today-preview' && kind !== 'plan-today-preview') { if (addPlanPreviewOnReturn && addPlanPreviewOverride) planTodayPreview.close({ add:true, override:true }); @@ -5992,6 +5998,10 @@ if (detail?.scope) applySearchScope(detail.scope); if (detail?.query !== undefined) qs('#cmd-input').value = detail.query; searchPreviewReturnKind = 'search'; + searchModal.activate(qs('#search-preview'), { + opener:document.activeElement, + initialFocus:qs('#close-search-preview'), + }); searchPreview.open(detail.preview).catch(() => taskOverlayHistory.close()); } if (kind === 'plan-today' && previous !== 'plan-today' && previous !== 'plan-today-preview') openPlanToday(planTodayTrigger, false); diff --git a/frontend/index.html b/frontend/index.html index efc1207..93a80ff 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -780,7 +780,7 @@ -