Slight UI refactor
This commit is contained in:
133
src/lib/components/SidebarTabs.svelte
Normal file
133
src/lib/components/SidebarTabs.svelte
Normal file
@@ -0,0 +1,133 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
export let activeTab: 'profiles' | 'triggers' | 'settings' = 'profiles';
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
tabChange: { tab: 'profiles' | 'triggers' | 'settings' }
|
||||
}>();
|
||||
|
||||
// Handle keyboard navigation for sidebar tabs
|
||||
function handleSidebarTabKeydown(event: KeyboardEvent) {
|
||||
// Define the tab order
|
||||
const tabs = ['profiles', 'triggers', 'settings'];
|
||||
const currentIndex = tabs.indexOf(activeTab);
|
||||
|
||||
switch (event.key) {
|
||||
case 'ArrowRight':
|
||||
case 'ArrowDown':
|
||||
// Move to next tab
|
||||
event.preventDefault();
|
||||
const nextIndex = (currentIndex + 1) % tabs.length;
|
||||
dispatch('tabChange', { tab: tabs[nextIndex] as any });
|
||||
document.getElementById(`tab-${tabs[nextIndex]}`)?.focus();
|
||||
break;
|
||||
|
||||
case 'ArrowLeft':
|
||||
case 'ArrowUp':
|
||||
// Move to previous tab
|
||||
event.preventDefault();
|
||||
const prevIndex = (currentIndex - 1 + tabs.length) % tabs.length;
|
||||
dispatch('tabChange', { tab: tabs[prevIndex] as any });
|
||||
document.getElementById(`tab-${tabs[prevIndex]}`)?.focus();
|
||||
break;
|
||||
|
||||
case 'Home':
|
||||
// Move to first tab
|
||||
event.preventDefault();
|
||||
dispatch('tabChange', { tab: tabs[0] as any });
|
||||
document.getElementById(`tab-${tabs[0]}`)?.focus();
|
||||
break;
|
||||
|
||||
case 'End':
|
||||
// Move to last tab
|
||||
event.preventDefault();
|
||||
dispatch('tabChange', { tab: tabs[tabs.length - 1] as any });
|
||||
document.getElementById(`tab-${tabs[tabs.length - 1]}`)?.focus();
|
||||
break;
|
||||
|
||||
case 'Enter':
|
||||
case ' ':
|
||||
// Activate current tab
|
||||
event.preventDefault();
|
||||
// The click handler will handle the tab change
|
||||
break;
|
||||
|
||||
default:
|
||||
// Let other keys function normally
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="sidebar-tabs" role="tablist" aria-label="Sidebar tabs">
|
||||
<button
|
||||
class="sidebar-tab"
|
||||
id="tab-profiles"
|
||||
role="tab"
|
||||
aria-controls="panel-profiles"
|
||||
aria-selected={activeTab === 'profiles'}
|
||||
class:active={activeTab === 'profiles'}
|
||||
tabindex={activeTab === 'profiles' ? "0" : "-1"}
|
||||
on:click={() => dispatch('tabChange', { tab: 'profiles' })}
|
||||
on:keydown={handleSidebarTabKeydown}>
|
||||
Profiles
|
||||
</button>
|
||||
<button
|
||||
class="sidebar-tab"
|
||||
id="tab-triggers"
|
||||
role="tab"
|
||||
aria-controls="panel-triggers"
|
||||
aria-selected={activeTab === 'triggers'}
|
||||
class:active={activeTab === 'triggers'}
|
||||
tabindex={activeTab === 'triggers' ? "0" : "-1"}
|
||||
on:click={() => dispatch('tabChange', { tab: 'triggers' })}
|
||||
on:keydown={handleSidebarTabKeydown}>
|
||||
Triggers
|
||||
</button>
|
||||
<button
|
||||
class="sidebar-tab"
|
||||
id="tab-settings"
|
||||
role="tab"
|
||||
aria-controls="panel-settings"
|
||||
aria-selected={activeTab === 'settings'}
|
||||
class:active={activeTab === 'settings'}
|
||||
tabindex={activeTab === 'settings' ? "0" : "-1"}
|
||||
on:click={() => dispatch('tabChange', { tab: 'settings' })}
|
||||
on:keydown={handleSidebarTabKeydown}>
|
||||
Settings
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sidebar-tabs {
|
||||
display: flex;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.sidebar-tab {
|
||||
flex: 1;
|
||||
padding: 0.5rem;
|
||||
text-align: center;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.sidebar-tab.active {
|
||||
color: var(--color-text);
|
||||
border-bottom: 2px solid var(--color-primary);
|
||||
}
|
||||
|
||||
.sidebar-tab:focus {
|
||||
outline: 2px solid var(--color-primary);
|
||||
outline-offset: -2px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.sidebar-tab:focus:not(:focus-visible) {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user