114 lines
2.3 KiB
Vue
114 lines
2.3 KiB
Vue
<template>
|
|
<nav
|
|
class="mobile-tab-bar"
|
|
:class="{ 'mobile-tab-bar--header': placement === 'header' }"
|
|
>
|
|
<button
|
|
v-for="tab in tabs"
|
|
:key="tab.id"
|
|
type="button"
|
|
class="tab-button"
|
|
:class="{ 'is-active': tab.id === modelValue }"
|
|
@click="$emit('update:modelValue', tab.id)"
|
|
>
|
|
<span class="material-symbols-outlined" :class="`icon-${tab.iconName}`">
|
|
{{ tab.iconName }}
|
|
</span>
|
|
<span v-if="showLabels" class="tab-label">{{ tab.label }}</span>
|
|
</button>
|
|
</nav>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed, watch } from 'vue';
|
|
import { useIconManager } from '../js/composables/useIconManager.js';
|
|
|
|
const props = defineProps({
|
|
tabs: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
modelValue: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
placement: {
|
|
type: String,
|
|
default: 'bottom' // 'bottom' | 'header'
|
|
},
|
|
showLabels: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
});
|
|
|
|
defineEmits(['update:modelValue']);
|
|
|
|
const { loadIcons } = useIconManager();
|
|
|
|
const iconNames = computed(() => props.tabs.map(t => t.iconName).filter(Boolean));
|
|
|
|
watch(iconNames, (names) => {
|
|
if (names && names.length) {
|
|
loadIcons(names);
|
|
}
|
|
}, { immediate: true });
|
|
</script>
|
|
|
|
<style scoped>
|
|
.mobile-tab-bar {
|
|
display: flex;
|
|
flex-shrink: 0;
|
|
align-items: center;
|
|
justify-content: space-around;
|
|
padding: 6px 8px;
|
|
padding-bottom: calc(6px + var(--safe-bottom-inset, 0px));
|
|
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
|
background: var(--tab-background, #0a0a0a);
|
|
}
|
|
|
|
.mobile-tab-bar--header {
|
|
/* In de header geen extra safe-area padding en geen border-top */
|
|
padding: 4px 4px;
|
|
padding-bottom: 4px;
|
|
border-top: none;
|
|
}
|
|
|
|
.tab-button {
|
|
flex: 1 1 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 4px 0;
|
|
border: none;
|
|
background: transparent;
|
|
color: var(--tab-icon-inactive-color, rgba(240, 240, 240, 0.7));
|
|
font-size: 11px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.tab-button .material-symbols-outlined {
|
|
font-size: 22px;
|
|
line-height: 1;
|
|
}
|
|
|
|
.tab-button.is-active {
|
|
color: var(--tab-icon-active-color, #ffffff);
|
|
}
|
|
|
|
.tab-button.is-active .material-symbols-outlined {
|
|
font-variation-settings:
|
|
'FILL' 1,
|
|
'wght' 500,
|
|
'GRAD' 0,
|
|
'opsz' 24;
|
|
}
|
|
|
|
@media (min-width: 769px) {
|
|
.mobile-tab-bar {
|
|
display: none;
|
|
}
|
|
}
|
|
</style>
|