owltide/components/Tabs.vue

91 lines
1.6 KiB
Vue
Raw Permalink Normal View History

<!--
SPDX-FileCopyrightText: © 2025 Hornwitser <code@hornwitser.no>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<section class="tabs">
<nav>
<div
v-for="tab in tabs"
class="tab"
:class="{ active: tab.id === activeTab }"
>
<div class="flap">
<h2>
<NuxtLink
:to="{ ...route, query: { ...route.query, tab: tab.id }}"
>
{{ tab.title }}
</NuxtLink>
</h2>
</div>
<div class="spacer"></div>
</div>
</nav>
<slot :name="activeTab">No content for {{ activeTab }}</slot>
</section>
</template>
<script lang="ts" setup>
const props = defineProps<{
tabs: { id: string, title: string }[],
default: string,
}>();
const route = useRoute();
const activeTab = computed({
get: () => queryToString(route.query.tab ?? props.default),
set: (value: string | undefined) => navigateTo({
path: route.path,
query: {
...route.query,
tab: value,
},
}),
});
</script>
<style scoped>
nav {
margin-block: 1rem 0.5rem;
display: flex;
flex-wrap: wrap;
row-gap: 0.5rem;
}
.tab {
display: flex;
flex-wrap: wrap;
}
.tab.active {
padding-block-start: 1px;
}
.tab:last-child {
flex-grow: 1;
}
.tab .spacer {
flex: 1 0 0.75rem;
}
.tab .flap,
.tab .spacer {
border-block-end: 1px solid color-mix(in srgb, CanvasText, Canvas 20%);
}
.tab.active .flap {
border-block-end: none;
}
.tab:not(.active) .flap h2 {
opacity: 0.7;
}
h2 {
border: 1px solid color-mix(in srgb, CanvasText, Canvas 20%);
border-start-start-radius: 0.4rem;
border-start-end-radius: 0.4rem;
border-block-end: none;
padding-inline: 0.5rem;
margin-block: 0;
font-size: 1.2rem;
padding-block: 0.3rem 0.1rem;
}
</style>