da57ad1ac8
- Changed margin class from `my-6` to `mb-6` in ContentRows.svelte for consistent spacing. - Updated PostCard.svelte to use `$derived` for post properties, enhancing reactivity. - Refined DeadlineBannerBlock.svelte by removing unnecessary border classes and improving layout for better content alignment. - Modified Button.svelte to support rendering children directly, enhancing flexibility. - Added `tabindex="0"` to TabBar.svelte for improved accessibility. - Fixed textarea closing tag in Textarea.svelte for proper HTML structure. - Corrected span closing tag in Toggle.svelte for valid markup.
53 lines
1.3 KiB
Svelte
53 lines
1.3 KiB
Svelte
<script lang="ts">
|
|
/** @type {{ id: string; label: string }[]} */
|
|
let {
|
|
tabs = [],
|
|
selectedId = $bindable(''),
|
|
labelledBy = '',
|
|
} = $props();
|
|
|
|
$effect(() => {
|
|
if (tabs.length && !selectedId) selectedId = tabs[0].id;
|
|
});
|
|
|
|
function selectTab(id: string) {
|
|
selectedId = id;
|
|
}
|
|
|
|
function handleKeydown(e: KeyboardEvent) {
|
|
const idx = tabs.findIndex((t) => t.id === selectedId);
|
|
if (e.key === 'ArrowRight' && idx < tabs.length - 1) {
|
|
e.preventDefault();
|
|
selectedId = tabs[idx + 1].id;
|
|
} else if (e.key === 'ArrowLeft' && idx > 0) {
|
|
e.preventDefault();
|
|
selectedId = tabs[idx - 1].id;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<div
|
|
role="tablist"
|
|
aria-label={labelledBy || 'Tabs'}
|
|
class="flex h-12 border-b border-stein-200"
|
|
tabindex="0"
|
|
onkeydown={handleKeydown}
|
|
>
|
|
{#each tabs as tab}
|
|
<button
|
|
type="button"
|
|
role="tab"
|
|
aria-selected={selectedId === tab.id}
|
|
aria-controls="panel-{tab.id}"
|
|
id="tab-{tab.id}"
|
|
class="border-b-2 px-4 text-sm font-medium transition-colors {selectedId === tab.id
|
|
? 'border-wald-500 text-wald-600 font-semibold'
|
|
: 'border-transparent text-stein-500 hover:text-stein-700'}"
|
|
tabindex={selectedId === tab.id ? 0 : -1}
|
|
onclick={() => selectTab(tab.id)}
|
|
>
|
|
{tab.label}
|
|
</button>
|
|
{/each}
|
|
</div>
|