mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-15 17:30:13 +08:00
refactor: polish dashboard sidebar styles
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* Auto-generated MDI subset – 273 icons */
|
||||
/* Auto-generated MDI subset – 272 icons */
|
||||
/* Do not edit manually. Run: pnpm run subset-icons */
|
||||
|
||||
@font-face {
|
||||
@@ -404,10 +404,6 @@
|
||||
content: "\F0209";
|
||||
}
|
||||
|
||||
.mdi-eye-outline::before {
|
||||
content: "\F06D0";
|
||||
}
|
||||
|
||||
.mdi-eyedropper::before {
|
||||
content: "\F020A";
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -45,7 +45,7 @@ localStorage.setItem('uiTheme', uiTheme);
|
||||
const config: ConfigProps = {
|
||||
Sidebar_drawer: true,
|
||||
Customizer_drawer: false,
|
||||
mini_sidebar: false,
|
||||
mini_sidebar: true,
|
||||
fontTheme: 'Roboto',
|
||||
uiTheme,
|
||||
themeMode,
|
||||
|
||||
@@ -1066,7 +1066,7 @@ onMounted(async () => {
|
||||
icon
|
||||
rounded="sm"
|
||||
variant="flat"
|
||||
@click.stop="customizer.SET_MINI_SIDEBAR(!customizer.mini_sidebar)"
|
||||
@click.stop="customizer.SET_SIDEBAR_DRAWER"
|
||||
>
|
||||
<v-icon>mdi-menu</v-icon>
|
||||
</v-btn>
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
<script setup>
|
||||
import { useI18n } from '@/i18n/composables';
|
||||
import { useCustomizerStore } from '@/stores/customizer';
|
||||
import { computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const props = defineProps({ item: Object, level: Number });
|
||||
const props = defineProps({ item: Object, level: Number, rail: Boolean });
|
||||
const { t } = useI18n();
|
||||
const customizer = useCustomizerStore();
|
||||
const route = useRoute();
|
||||
|
||||
const itemStyle = computed(() => {
|
||||
const lvl = props.level ?? 0;
|
||||
const indent = customizer.mini_sidebar ? '0px' : `${lvl * 24}px`;
|
||||
const indent = props.rail ? '0px' : `${lvl * 24}px`;
|
||||
return { '--indent-padding': indent };
|
||||
});
|
||||
|
||||
@@ -33,9 +31,19 @@ const itemTitle = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-list-group v-if="item.children" :value="item.title" :class="{ 'group-bordered': customizer.mini_sidebar }">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-list-item v-bind="props" rounded class="mb-1" color="secondary" :prepend-icon="item.icon"
|
||||
<v-list-group v-if="item.children" :value="item.title" :class="{ 'rail-group': rail }">
|
||||
<template v-slot:activator="{ props: groupProps }">
|
||||
<v-tooltip v-if="rail" location="right" :text="itemTitle" open-delay="180">
|
||||
<template v-slot:activator="{ props: tooltipProps }">
|
||||
<v-list-item v-bind="{ ...groupProps, ...tooltipProps }" rounded class="mb-1" color="secondary"
|
||||
:prepend-icon="item.icon" :style="{ '--indent-padding': '0px' }" :aria-label="itemTitle">
|
||||
<v-list-item-title style="font-size: 14px; font-weight: 500; line-height: 1.2; word-break: break-word;">
|
||||
{{ itemTitle }}
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
<v-list-item v-else v-bind="groupProps" rounded class="mb-1" color="secondary" :prepend-icon="item.icon"
|
||||
:style="{ '--indent-padding': '0px' }">
|
||||
<v-list-item-title style="font-size: 14px; font-weight: 500; line-height: 1.2; word-break: break-word;">
|
||||
{{ itemTitle }}
|
||||
@@ -45,10 +53,33 @@ const itemTitle = computed(() => {
|
||||
|
||||
<!-- children -->
|
||||
<template v-for="(child, index) in item.children" :key="child.title || child.to || `child-${index}`">
|
||||
<NavItem :item="child" :level="(level || 0) + 1" />
|
||||
<NavItem :item="child" :level="(level || 0) + 1" :rail="rail" />
|
||||
</template>
|
||||
</v-list-group>
|
||||
|
||||
<v-tooltip v-else-if="rail" location="right" :text="itemTitle" open-delay="180">
|
||||
<template v-slot:activator="{ props: tooltipProps }">
|
||||
<v-list-item v-bind="tooltipProps" :to="item.type === 'external' ? '' : item.to"
|
||||
:href="item.type === 'external' ? item.to : ''" :active="isItemActive" rounded class="mb-1"
|
||||
color="secondary" :disabled="item.disabled" :target="item.type === 'external' ? '_blank' : ''"
|
||||
:style="itemStyle" :aria-label="itemTitle">
|
||||
<template v-slot:prepend>
|
||||
<v-icon v-if="item.icon" :size="item.iconSize" class="hide-menu" :icon="item.icon"></v-icon>
|
||||
</template>
|
||||
<v-list-item-title style="font-size: 14px;">{{ itemTitle }}</v-list-item-title>
|
||||
<v-list-item-subtitle v-if="item.subCaption" class="text-caption mt-n1 hide-menu">
|
||||
{{ item.subCaption }}
|
||||
</v-list-item-subtitle>
|
||||
<template v-slot:append v-if="item.chip">
|
||||
<v-chip :color="item.chipColor" class="sidebarchip hide-menu" :size="item.chipIcon ? 'small' : 'default'"
|
||||
:variant="item.chipVariant" :prepend-icon="item.chipIcon">
|
||||
{{ item.chip }}
|
||||
</v-chip>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
|
||||
<v-list-item v-else :to="item.type === 'external' ? '' : item.to" :href="item.type === 'external' ? item.to : ''"
|
||||
:active="isItemActive" rounded class="mb-1" color="secondary" :disabled="item.disabled"
|
||||
:target="item.type === 'external' ? '_blank' : ''" :style="itemStyle">
|
||||
@@ -69,10 +100,16 @@ const itemTitle = computed(() => {
|
||||
</template>
|
||||
|
||||
<style>
|
||||
/* 在折叠(mini)状态下,分组展开时给整个分组(母项+子项)加边框以便区分 */
|
||||
.group-bordered.v-list-group--open {
|
||||
border: 2px solid rgba(var(--v-theme-borderLight), 0.35);
|
||||
border-radius: 8px;
|
||||
background: rgba(var(--v-theme-borderLight), 0.04);
|
||||
.rail-group {
|
||||
border-radius: 12px;
|
||||
transition: background-color 0.18s ease;
|
||||
}
|
||||
|
||||
.rail-group.v-list-group--open {
|
||||
background: rgba(var(--v-theme-primary), 0.06);
|
||||
}
|
||||
|
||||
.rail-group.v-list-group--open > .v-list-group__items {
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -123,8 +123,11 @@ const dragHeaderBackground = computed(() => isDark.value ? themeColors.value.mcp
|
||||
const frameBorder = computed(() => `1px solid ${isDark.value ? (themeColors.value.borderLight || '#ccc') : '#ccc'}`);
|
||||
|
||||
const isMobile = window.innerWidth < 768;
|
||||
const isRailSidebar = !isMobile;
|
||||
if (isMobile) {
|
||||
customizer.Sidebar_drawer = false;
|
||||
} else {
|
||||
customizer.SET_MINI_SIDEBAR(true);
|
||||
}
|
||||
|
||||
const dragPos = ref({ left: '', top: '' });
|
||||
@@ -326,46 +329,64 @@ function openChangelogDialog() {
|
||||
app
|
||||
class="leftSidebar"
|
||||
:width="sidebarWidth"
|
||||
:rail="customizer.mini_sidebar"
|
||||
:rail="isRailSidebar"
|
||||
>
|
||||
<div class="sidebar-container">
|
||||
<v-list :class="['pa-4', 'listitem', 'flex-grow-1', { 'hidden-scrollbar': customizer.mini_sidebar }]" v-model:opened="openedItems" :open-strategy="'multiple'">
|
||||
<v-list :class="['pa-4', 'listitem', 'flex-grow-1', { 'hidden-scrollbar': isRailSidebar }]" v-model:opened="openedItems" :open-strategy="'multiple'">
|
||||
<template v-for="(item, i) in sidebarMenu" :key="item.title || item.to || `sidebar-item-${i}`">
|
||||
<NavItem :item="item" class="leftPadding" />
|
||||
<NavItem :item="item" class="leftPadding" :rail="isRailSidebar" />
|
||||
</template>
|
||||
</v-list>
|
||||
<div class="sidebar-footer" v-if="!customizer.mini_sidebar">
|
||||
<v-btn class="sidebar-footer-btn" size="small" variant="tonal" color="primary" to="/settings" prepend-icon="mdi-cog">
|
||||
{{ t('core.navigation.settings') }}
|
||||
<div class="sidebar-footer">
|
||||
<v-btn class="sidebar-footer-btn" :class="{ 'sidebar-footer-icon-btn': isRailSidebar }" :size="isRailSidebar ? 'default' : 'small'"
|
||||
:variant="isRailSidebar ? 'text' : 'tonal'" :color="isRailSidebar ? undefined : 'primary'" to="/settings"
|
||||
:prepend-icon="isRailSidebar ? undefined : 'mdi-cog'" :aria-label="t('core.navigation.settings')">
|
||||
<v-icon v-if="isRailSidebar" icon="mdi-cog" />
|
||||
<template v-else>{{ t('core.navigation.settings') }}</template>
|
||||
<v-tooltip v-if="isRailSidebar" activator="parent" location="right" :text="t('core.navigation.settings')" open-delay="180" />
|
||||
</v-btn>
|
||||
<v-btn class="sidebar-footer-btn" size="small" variant="text" prepend-icon="mdi-note-text-outline"
|
||||
@click="openChangelogDialog">
|
||||
{{ t('core.navigation.changelog') }}
|
||||
<v-btn class="sidebar-footer-btn" :class="{ 'sidebar-footer-icon-btn': isRailSidebar }" :size="isRailSidebar ? 'default' : 'small'"
|
||||
variant="text" :prepend-icon="isRailSidebar ? undefined : 'mdi-note-text-outline'"
|
||||
:aria-label="t('core.navigation.changelog')" @click="openChangelogDialog">
|
||||
<v-icon v-if="isRailSidebar" icon="mdi-note-text-outline" />
|
||||
<template v-else>{{ t('core.navigation.changelog') }}</template>
|
||||
<v-tooltip v-if="isRailSidebar" activator="parent" location="right" :text="t('core.navigation.changelog')" open-delay="180" />
|
||||
</v-btn>
|
||||
<v-btn class="sidebar-footer-btn" size="small" variant="text" prepend-icon="mdi-book-open-variant"
|
||||
@click="toggleIframe">
|
||||
{{ t('core.navigation.documentation') }}
|
||||
<v-btn class="sidebar-footer-btn" :class="{ 'sidebar-footer-icon-btn': isRailSidebar }" :size="isRailSidebar ? 'default' : 'small'"
|
||||
variant="text" :prepend-icon="isRailSidebar ? undefined : 'mdi-book-open-variant'"
|
||||
:aria-label="t('core.navigation.documentation')" @click="toggleIframe">
|
||||
<v-icon v-if="isRailSidebar" icon="mdi-book-open-variant" />
|
||||
<template v-else>{{ t('core.navigation.documentation') }}</template>
|
||||
<v-tooltip v-if="isRailSidebar" activator="parent" location="right" :text="t('core.navigation.documentation')" open-delay="180" />
|
||||
</v-btn>
|
||||
<v-btn class="sidebar-footer-btn" size="small" variant="text" prepend-icon="mdi-frequently-asked-questions"
|
||||
@click="openFaqLink">
|
||||
{{ t('core.navigation.faq') }}
|
||||
<v-btn class="sidebar-footer-btn" :class="{ 'sidebar-footer-icon-btn': isRailSidebar }" :size="isRailSidebar ? 'default' : 'small'"
|
||||
variant="text" :prepend-icon="isRailSidebar ? undefined : 'mdi-frequently-asked-questions'"
|
||||
:aria-label="t('core.navigation.faq')" @click="openFaqLink">
|
||||
<v-icon v-if="isRailSidebar" icon="mdi-frequently-asked-questions" />
|
||||
<template v-else>{{ t('core.navigation.faq') }}</template>
|
||||
<v-tooltip v-if="isRailSidebar" activator="parent" location="right" :text="t('core.navigation.faq')" open-delay="180" />
|
||||
</v-btn>
|
||||
<v-btn class="sidebar-footer-btn" size="small" variant="text" prepend-icon="mdi-github"
|
||||
<v-btn class="sidebar-footer-btn" :class="{ 'sidebar-footer-icon-btn': isRailSidebar }" :size="isRailSidebar ? 'default' : 'small'"
|
||||
variant="text" :prepend-icon="isRailSidebar ? undefined : 'mdi-github'" :aria-label="t('core.navigation.github')"
|
||||
@click="openIframeLink('https://github.com/AstrBotDevs/AstrBot')">
|
||||
{{ t('core.navigation.github') }}
|
||||
<v-chip
|
||||
v-if="starCount"
|
||||
size="x-small"
|
||||
variant="outlined"
|
||||
class="ml-2"
|
||||
style="font-weight: normal;"
|
||||
>{{ formatNumber(starCount) }}</v-chip>
|
||||
<v-icon v-if="isRailSidebar" icon="mdi-github" />
|
||||
<template v-else>
|
||||
{{ t('core.navigation.github') }}
|
||||
<v-chip
|
||||
v-if="starCount"
|
||||
size="x-small"
|
||||
variant="outlined"
|
||||
class="ml-2"
|
||||
style="font-weight: normal;"
|
||||
>{{ formatNumber(starCount) }}</v-chip>
|
||||
</template>
|
||||
<v-tooltip v-if="isRailSidebar" activator="parent" location="right" :text="t('core.navigation.github')" open-delay="180" />
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="!customizer.mini_sidebar && customizer.Sidebar_drawer"
|
||||
v-if="!isRailSidebar && !isMobile && customizer.Sidebar_drawer"
|
||||
class="sidebar-resize-handle"
|
||||
@mousedown="startSidebarResize"
|
||||
:class="{ 'resizing': isResizing }"
|
||||
|
||||
@@ -65,6 +65,101 @@
|
||||
.leftPadding {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.listitem {
|
||||
padding: 10px !important;
|
||||
|
||||
.v-list-group__items .v-list-item,
|
||||
.v-list-item {
|
||||
width: 56px;
|
||||
min-width: 56px;
|
||||
max-width: 56px;
|
||||
min-height: 50px;
|
||||
margin-bottom: 8px !important;
|
||||
margin-inline: auto;
|
||||
padding-inline: 0 !important;
|
||||
grid-template-areas: "prepend" !important;
|
||||
grid-template-columns: 1fr !important;
|
||||
justify-content: center;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.rail-group {
|
||||
width: 56px;
|
||||
margin-bottom: 8px;
|
||||
margin-inline: auto;
|
||||
padding: 4px 0 2px;
|
||||
|
||||
.v-list-item {
|
||||
width: 56px;
|
||||
min-width: 56px;
|
||||
max-width: 56px;
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.v-list-item__prepend {
|
||||
grid-area: prepend;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: 0 !important;
|
||||
justify-content: center;
|
||||
margin-inline-end: 0;
|
||||
|
||||
.v-icon {
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.v-list-item__spacer,
|
||||
.v-list-item__append,
|
||||
.v-list-item__content {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
width: 100%;
|
||||
padding: 12px 10px 18px !important;
|
||||
gap: 8px;
|
||||
|
||||
.sidebar-footer-icon-btn {
|
||||
width: 56px !important;
|
||||
min-width: 56px !important;
|
||||
max-width: 56px !important;
|
||||
height: 52px !important;
|
||||
border-radius: 14px !important;
|
||||
color: rgba(var(--v-theme-on-surface), 0.82);
|
||||
margin-bottom: 0 !important;
|
||||
padding: 0 !important;
|
||||
justify-content: center !important;
|
||||
text-align: center;
|
||||
transition:
|
||||
background-color 0.18s ease,
|
||||
color 0.18s ease;
|
||||
|
||||
.v-btn__content {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.v-icon {
|
||||
font-size: 22px;
|
||||
margin: 0 !important;
|
||||
opacity: 0.98;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.v-btn--active {
|
||||
color: rgb(var(--v-theme-primary));
|
||||
background: rgba(var(--v-theme-primary), 0.09);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (min-width: 1170px) {
|
||||
.mini-sidebar {
|
||||
@@ -122,3 +217,16 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-navigation-drawer--rail.leftSidebar {
|
||||
.sidebar-container .sidebar-footer {
|
||||
.sidebar-footer-btn.sidebar-footer-icon-btn {
|
||||
justify-content: center !important;
|
||||
text-align: center;
|
||||
|
||||
.v-btn__content {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user