Enhance AppLauncherOverlay and navigation logic for improved user experience

- Added functionality to close the overlay and return focus to the launcher when the Escape key is pressed inside an iframe.
- Implemented message handling to close the app launcher from the parent window.
- Updated navigation logic in useControllerNav to improve focus management when navigating between sidebar and main content.
- Enhanced Dashboard and Settings views with data attributes for better controller navigation support.
This commit is contained in:
Dorian
2026-02-18 11:29:05 +00:00
parent 473c58894c
commit d0312c6721
5 changed files with 51 additions and 7 deletions
+24 -4
View File
@@ -266,10 +266,25 @@ export function useControllerNav(containerRef?: { value: HTMLElement | null }) {
const mainEls = getElementsInZone('main')
const hasZones = sidebarEls.length > 0 && mainEls.length > 0
// Right: from sidebar → main (on App Store/My Apps, go straight to first app container)
// Right: from sidebar → main
// - On Apps/Marketplace: go to first app container
// - On Cloud: go to first folder (Pictures)
// - On Network (server): go to Services container
// - On Web5: go to Networking Profits container
// - On Settings: go to Change Password container
// - Otherwise: go to top right (App Switcher)
const mainZone = document.querySelector('[data-controller-zone="main"]')
const isAppsOrMarketplace = /^\/dashboard\/(apps|marketplace)(\/|$)/.test(route.path)
const isCloud = /^\/dashboard\/cloud(\/|$)/.test(route.path)
const isNetwork = /^\/dashboard\/server(\/|$)/.test(route.path)
const isWeb5 = /^\/dashboard\/web5(\/|$)/.test(route.path)
const isSettings = /^\/dashboard\/settings(\/|$)/.test(route.path)
const firstAppContainer = mainZone?.querySelector<HTMLElement>('[data-controller-container]')
const firstMain = firstAppContainer ?? mainEls[0]
const topRightEntry = mainZone?.querySelector<HTMLElement>('[data-controller-main-entry]')
const firstFocusableInTopRight = topRightEntry ? getFocusableElements(topRightEntry)[0] : null
const firstMain = ((isAppsOrMarketplace || isCloud || isNetwork || isWeb5 || isSettings) && firstAppContainer)
? firstAppContainer
: (firstFocusableInTopRight ?? mainEls[0])
if (e.key === 'ArrowRight' && hasZones && isInZone(activeEl, 'sidebar') && firstMain) {
playNavSound('move')
firstMain.focus()
@@ -323,12 +338,17 @@ export function useControllerNav(containerRef?: { value: HTMLElement | null }) {
}
}
// Sidebar: linear up/down
// Sidebar: linear up/down with wrap (Home+Up→Logout, Logout+Down→Home)
if (isInZone(activeEl, 'sidebar')) {
const idx = sidebarEls.indexOf(activeEl)
if (idx >= 0) {
const isDown = e.key === 'ArrowDown'
const nextIdx = isDown ? Math.min(idx + 1, sidebarEls.length - 1) : Math.max(idx - 1, 0)
let nextIdx: number
if (isDown) {
nextIdx = idx >= sidebarEls.length - 1 ? 0 : idx + 1
} else {
nextIdx = idx <= 0 ? sidebarEls.length - 1 : idx - 1
}
const next = sidebarEls[nextIdx]
if (next && next !== activeEl) {
playNavSound('move')