mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-08-05 12:07:22 -04:00
82 lines
2.5 KiB
Vue
82 lines
2.5 KiB
Vue
<script setup lang="ts">
|
|
import useHash from '~/composables/useHash.ts';
|
|
|
|
const props = defineProps<{
|
|
tabs: (string | undefined)[];
|
|
pills?: boolean;
|
|
showheaders?: boolean;
|
|
navclass?: string;
|
|
anchors?: boolean;
|
|
}>();
|
|
|
|
const { handleHash, setHash } = useHash();
|
|
|
|
const visibleTabs = computed(() => props.tabs.filter((x) => x !== undefined));
|
|
const activeTab = ref(visibleTabs.value[0]);
|
|
|
|
watch(activeTab, () => {
|
|
if (!props.anchors) {
|
|
return;
|
|
}
|
|
setHash('', activeTab.value);
|
|
});
|
|
|
|
onMounted(() => {
|
|
if (!props.anchors) {
|
|
return;
|
|
}
|
|
|
|
handleHash('', (hash) => {
|
|
if (!visibleTabs.value.includes(hash)) {
|
|
return;
|
|
}
|
|
activeTab.value = hash;
|
|
}, false);
|
|
});
|
|
|
|
const tablist = useTemplateRef('tablist');
|
|
const tabKeydown = (event: KeyboardEvent) => {
|
|
const activeIndex = visibleTabs.value.indexOf(activeTab.value);
|
|
if (activeIndex === -1) {
|
|
return;
|
|
}
|
|
|
|
if ((event.key === 'ArrowUp' || event.key === 'ArrowLeft') &&
|
|
activeIndex > 0) {
|
|
activeTab.value = visibleTabs.value[activeIndex - 1];
|
|
(tablist.value?.children[activeIndex - 1].firstElementChild as HTMLButtonElement | undefined)?.focus();
|
|
} else if ((event.key === 'ArrowDown' || event.key === 'ArrowRight') &&
|
|
activeIndex < visibleTabs.value.length - 1) {
|
|
activeTab.value = visibleTabs.value[activeIndex + 1];
|
|
(tablist.value?.children[activeIndex + 1].firstElementChild as HTMLButtonElement | undefined)?.focus();
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<ul ref="tablist" :class="['nav', pills ? 'nav-pills' : 'nav-tabs', navclass]" role="tablist">
|
|
<li v-for="tab in visibleTabs" :key="tab" class="nav-item" role="tab">
|
|
<button
|
|
type="button"
|
|
:tabindex="activeTab === tab ? 0 : -1"
|
|
:class="['nav-link', activeTab === tab ? 'active' : '']"
|
|
:aria-selected="activeTab === tab"
|
|
@click="activeTab = tab"
|
|
@keydown="tabKeydown"
|
|
>
|
|
<slot :name="`${tab}-header`"></slot>
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
<div class="card" role="tabpanel">
|
|
<div class="card-body">
|
|
<h3 v-if="showheaders" class="h4 mb-3">
|
|
<slot :name="`${activeTab}-header`"></slot>
|
|
</h3>
|
|
<slot :name="activeTab"></slot>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|