185 lines
6.3 KiB
Vue
185 lines
6.3 KiB
Vue
<template>
|
|
<v-col class="d-flex align-center bg-surface pr-2 pl-2 pl-m-3 py-1">
|
|
<v-btn v-if="isMobile" icon="mdi-menu" size="small" variant="text" @click="emit('toggle-drawer')"></v-btn>
|
|
|
|
<div v-if="features.showSearch" class="search-input-wrapper">
|
|
<v-text-field
|
|
v-model="searchValueModel" :aria-label="searchConfig.label" class="search-input" density="compact"
|
|
hide-details :placeholder="searchConfig.placeholder" variant="outlined"
|
|
@keyup.enter="triggerSearch">
|
|
<template v-if="!isMobile" #prepend-inner>
|
|
<v-icon size="small">mdi-magnify</v-icon>
|
|
</template>
|
|
<template #append-inner>
|
|
<v-btn :aria-label="searchConfig.label" color="primary" size="small" variant="text" @click="triggerSearch">
|
|
開始搜尋
|
|
</v-btn>
|
|
</template>
|
|
</v-text-field>
|
|
</div>
|
|
|
|
<div v-if="features.showToolbarActions" class="top-actions">
|
|
<slot name="actions">
|
|
|
|
<!-- 通知 -->
|
|
<v-tooltip location="bottom" :text="toolbarActions.notificationsLabel">
|
|
<template #activator="{ props }">
|
|
<v-btn
|
|
v-bind="props" :aria-label="toolbarActions.notificationsLabel" icon size="small" variant="text"
|
|
@click="emit('action', 'notifications')">
|
|
<v-badge
|
|
v-if="toolbarCounts.notifications" color="error" :content="toolbarCounts.notifications"
|
|
offset-x="4" offset-y="-2">
|
|
<v-icon>mdi-bell-outline</v-icon>
|
|
</v-badge>
|
|
<v-icon v-else>mdi-bell-outline</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
</v-tooltip>
|
|
|
|
<!-- 訊息 -->
|
|
<v-tooltip location="bottom" :text="toolbarActions.messagesLabel">
|
|
<template #activator="{ props }">
|
|
<v-btn
|
|
v-bind="props" :aria-label="toolbarActions.messagesLabel" icon size="small" variant="text"
|
|
@click="emit('action', 'messages')">
|
|
<v-badge
|
|
v-if="toolbarCounts.messages" color="warning" :content="toolbarCounts.messages" offset-x="4"
|
|
offset-y="-2">
|
|
<v-icon>mdi-message-text-outline</v-icon>
|
|
</v-badge>
|
|
<v-icon v-else>mdi-message-text-outline</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
</v-tooltip>
|
|
|
|
<!-- 說明 -->
|
|
<v-tooltip v-if="false" location="bottom" :text="toolbarActions.helpLabel">
|
|
<template #activator="{ props }">
|
|
<v-btn
|
|
v-bind="props" :aria-label="toolbarActions.helpLabel" icon size="small" variant="text"
|
|
@click="emit('action', 'help')">
|
|
<v-icon>mdi-help</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
</v-tooltip>
|
|
|
|
<!-- 設定 -->
|
|
<v-menu :close-on-content-click="false" location="bottom end">
|
|
<template #activator="{ props: menuProps }">
|
|
<v-tooltip location="bottom" :text="toolbarActions.settingsLabel">
|
|
<template #activator="{ props: tooltipProps }">
|
|
<v-btn
|
|
v-bind="{ ...menuProps, ...tooltipProps }" :aria-label="toolbarActions.settingsLabel" icon size="small"
|
|
variant="text">
|
|
<v-icon>mdi-cog-outline</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
</v-tooltip>
|
|
</template>
|
|
<v-list density="compact" width="180">
|
|
<v-list-subheader class="text-subtitle-1 py-2">顯示設定</v-list-subheader>
|
|
<v-list-item>
|
|
<v-switch v-model="showFavoritesBarModel" color="primary" density="comfortable" hide-details>
|
|
<template #label>
|
|
<span class="text-body-2" style="width: 8ch;">常用功能</span>
|
|
</template>
|
|
</v-switch>
|
|
</v-list-item>
|
|
<v-list-item>
|
|
<v-switch v-model="showBreadcrumbBarModel" color="primary" density="comfortable" hide-details>
|
|
<template #label>
|
|
<span class="text-body-2" style="width: 8ch;">路徑</span>
|
|
</template>
|
|
</v-switch>
|
|
</v-list-item>
|
|
</v-list>
|
|
</v-menu>
|
|
|
|
<!-- 登出 -->
|
|
<v-tooltip location="bottom" :text="logoutLabel">
|
|
<template #activator="{ props }">
|
|
<v-btn v-bind="props" :aria-label="logoutLabel" icon size="small" variant="text" @click="emit('logout')">
|
|
<v-icon>mdi-logout</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
</v-tooltip>
|
|
|
|
<v-tooltip v-if="features.showThemeToggle" location="bottom" :text="themeToggleLabel">
|
|
<template #activator="{ props }">
|
|
<v-btn v-bind="props" :aria-label="themeToggleLabel" icon variant="text" @click="emit('toggle-theme')">
|
|
<v-icon>mdi-palette-outline</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
</v-tooltip>
|
|
</slot>
|
|
</div>
|
|
</v-col>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed } from 'vue'
|
|
|
|
const props = defineProps({
|
|
isMobile: { type: Boolean, default: false },
|
|
features: { type: Object, default: () => ({}) },
|
|
searchValue: { type: String, default: '' },
|
|
searchConfig: { type: Object, default: () => ({}) },
|
|
toolbarActions: { type: Object, default: () => ({}) },
|
|
toolbarCounts: { type: Object, default: () => ({}) },
|
|
logoutLabel: { type: String, default: '' },
|
|
themeToggleLabel: { type: String, default: '' },
|
|
showFavoritesBar: { type: Boolean, default: true },
|
|
showBreadcrumbBar: { type: Boolean, default: true },
|
|
})
|
|
|
|
const emit = defineEmits([
|
|
'toggle-drawer',
|
|
'update:searchValue',
|
|
'search',
|
|
'action',
|
|
'logout',
|
|
'toggle-theme',
|
|
'update:showFavoritesBar',
|
|
'update:showBreadcrumbBar',
|
|
])
|
|
|
|
const searchValueModel = computed({
|
|
get: () => props.searchValue,
|
|
set: (value) => emit('update:searchValue', value),
|
|
})
|
|
|
|
const showFavoritesBarModel = computed({
|
|
get: () => props.showFavoritesBar,
|
|
set: (value) => emit('update:showFavoritesBar', value),
|
|
})
|
|
|
|
const showBreadcrumbBarModel = computed({
|
|
get: () => props.showBreadcrumbBar,
|
|
set: (value) => emit('update:showBreadcrumbBar', value),
|
|
})
|
|
|
|
function triggerSearch () {
|
|
emit('search')
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.search-input-wrapper {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
:deep(.search-input-wrapper .v-field--appended) {
|
|
padding-inline-end: 4px;
|
|
}
|
|
|
|
.top-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
</style>
|