- Full implementation of tab bar next to logo in mobile client
- Customisation option in Tenant Make - Splitting all controls in the newly created tabs
This commit is contained in:
113
eveai_chat_client/static/assets/vue-components/MobileTabBar.vue
Normal file
113
eveai_chat_client/static/assets/vue-components/MobileTabBar.vue
Normal file
@@ -0,0 +1,113 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user