diff --git a/messages/de.json b/messages/de.json
index 6173dea8..203b7f11 100644
--- a/messages/de.json
+++ b/messages/de.json
@@ -25,6 +25,7 @@
"sidebar_expand": "Seitenleiste ausklappen",
"sidebar_collapse": "Seitenleiste einklappen",
"sidebar_collapse_label": "Einklappen",
+ "skip_to_content": "Zum Hauptinhalt springen",
"header_open_nav": "Navigation öffnen",
"header_close_nav": "Navigation schließen",
"header_user_menu": "Benutzermenü",
diff --git a/messages/en.json b/messages/en.json
index b9216ce0..b9770c86 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -25,6 +25,7 @@
"sidebar_expand": "Expand sidebar",
"sidebar_collapse": "Collapse sidebar",
"sidebar_collapse_label": "Collapse",
+ "skip_to_content": "Skip to main content",
"header_open_nav": "Open navigation",
"header_close_nav": "Close navigation",
"header_user_menu": "User menu",
diff --git a/src/lib/components/layout/sidebar/Sidebar.svelte b/src/lib/components/layout/sidebar/Sidebar.svelte
index 8b517ace..80935e6e 100644
--- a/src/lib/components/layout/sidebar/Sidebar.svelte
+++ b/src/lib/components/layout/sidebar/Sidebar.svelte
@@ -5,6 +5,7 @@
import type { Component } from 'svelte';
import IconChevronLeft from 'virtual:icons/material-symbols/chevron-left';
import IconChevronRight from 'virtual:icons/material-symbols/chevron-right';
+ import { MediaQuery } from 'svelte/reactivity';
import type { NavItem } from '$lib/types/navigation.js';
import { getNavSections } from './nav-items.js';
@@ -20,6 +21,10 @@
const sections = $derived(getNavSections({ storageBrowserEnabled }));
+ // make mobile navbar not focusable if its hidden
+ const isDesktop = new MediaQuery('min-width: 64rem', true);
+ const hiddenFromUser = $derived(!isDesktop.current && !mobileOpen);
+
function isActive(href: string): boolean {
if (href === '/') return page.url.pathname === '/';
return page.url.pathname.startsWith(href);
@@ -40,8 +45,35 @@
}
let sidebarEl: HTMLElement | undefined = $state();
+
+ $effect(() => {
+ if (isDesktop.current || !mobileOpen || !sidebarEl) return;
+ sidebarEl.focus();
+ });
+
+ function handleWindowKeydown(event: KeyboardEvent) {
+ if (isDesktop.current || !mobileOpen) return;
+
+ if (event.key === 'Escape') {
+ event.preventDefault();
+ mobileOpen = false;
+ }
+ }
+
+ // Tabbing off either end of the open panel would land on the page behind the
+ // backdrop, so send focus back to the top of the panel instead.
+ function handleFocusOut(event: FocusEvent) {
+ if (isDesktop.current || !mobileOpen) return;
+
+ const next = event.relatedTarget as Node | null;
+ if (next && sidebarEl?.contains(next)) return;
+
+ sidebarEl?.focus();
+ }
+
+
403
+{m.storage_connections_subtitle()}
{#if !loaded} diff --git a/src/routes/(app)/storage/connections/[id]/edit/+page.svelte b/src/routes/(app)/storage/connections/[id]/edit/+page.svelte index e09ebb98..86c19127 100644 --- a/src/routes/(app)/storage/connections/[id]/edit/+page.svelte +++ b/src/routes/(app)/storage/connections/[id]/edit/+page.svelte @@ -157,7 +157,7 @@