mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-20 15:23:50 +02:00
replace navmenu
This commit is contained in:
@@ -1,241 +1,210 @@
|
||||
<template>
|
||||
<div class="x-menu-container nav-menu-container" :class="{ 'is-collapsed': isCollapsed }">
|
||||
<template v-if="navLayoutReady">
|
||||
<div class="nav-menu-body mt-5">
|
||||
<div v-if="pendingVRCXUpdate || pendingVRCXInstall" class="pending-update">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="hover:bg-transparent"
|
||||
style="font-size: 19px; height: 36px; margin: 10px"
|
||||
@click="showVRCXUpdateDialog">
|
||||
<span class="relative inline-flex items-center justify-center">
|
||||
<i class="ri-arrow-down-circle-line text-muted-foreground text-[20px]"></i>
|
||||
<span class="absolute top-0.5 -right-1 h-1.5 w-1.5 rounded-full bg-red-500"></span>
|
||||
</span>
|
||||
<span v-if="!isCollapsed" class="text-[13px] text-muted-foreground">{{
|
||||
t('nav_menu.update_available')
|
||||
}}</span>
|
||||
</Button>
|
||||
</div>
|
||||
<Sidebar side="left" variant="sidebar" collapsible="icon">
|
||||
<SidebarContent class="pt-4">
|
||||
<div v-if="navLayoutReady" class="px-2">
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem v-if="pendingVRCXUpdate || pendingVRCXInstall">
|
||||
<SidebarMenuButton
|
||||
:tooltip="t('nav_menu.update_available')"
|
||||
variant="default"
|
||||
@click="showVRCXUpdateDialog">
|
||||
<span class="relative inline-flex size-6 items-center justify-center">
|
||||
<i class="ri-arrow-down-circle-line text-muted-foreground text-[20px]"></i>
|
||||
<span class="absolute top-0.5 -right-1 h-1.5 w-1.5 rounded-full bg-red-500"></span>
|
||||
</span>
|
||||
<span v-show="!isCollapsed" class="text-[13px] text-muted-foreground">{{
|
||||
t('nav_menu.update_available')
|
||||
}}</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</div>
|
||||
|
||||
<el-menu ref="navMenuRef" class="nav-menu" :collapse="isCollapsed" :collapse-transition="false">
|
||||
<template v-for="item in menuItems" :key="item.index">
|
||||
<el-menu-item
|
||||
v-if="!item.children?.length"
|
||||
:index="item.index"
|
||||
:class="{ notify: isNavItemNotified(item) }"
|
||||
@click="handleMenuItemClick(item)">
|
||||
<i :class="item.icon"></i>
|
||||
<template #title>
|
||||
<span>{{ item.titleIsCustom ? item.title : t(item.title || '') }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
<el-sub-menu v-else :index="item.index">
|
||||
<template #title>
|
||||
<div :class="{ notify: isNavItemNotified(item) }">
|
||||
<i :class="item.icon"></i>
|
||||
<SidebarGroup>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu v-if="navLayoutReady">
|
||||
<template v-for="item in menuItems" :key="item.index">
|
||||
<SidebarMenuItem v-if="!item.children?.length">
|
||||
<SidebarMenuButton
|
||||
:is-active="activeMenuIndex === item.index"
|
||||
:tooltip="item.titleIsCustom ? item.title : t(item.title || '')"
|
||||
:class="isNavItemNotified(item) ? 'notify' : undefined"
|
||||
@click="handleMenuItemClick(item)">
|
||||
<i
|
||||
:class="item.icon"
|
||||
class="inline-flex size-6 items-center justify-center text-[19px]" />
|
||||
<span v-show="!isCollapsed">{{
|
||||
item.titleIsCustom ? item.title : t(item.title || '')
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-menu-item
|
||||
v-for="entry in item.children"
|
||||
:key="entry.index"
|
||||
:index="entry.index"
|
||||
class="pl-9!"
|
||||
:class="{ notify: isEntryNotified(entry) }"
|
||||
@click="handleSubmenuClick(entry, item.index)">
|
||||
<i v-show="entry.icon" :class="entry.icon"></i>
|
||||
<template #title>
|
||||
<span>{{ t(entry.label) }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</el-sub-menu>
|
||||
</template>
|
||||
</el-menu>
|
||||
</div>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
|
||||
<div class="nav-menu-container-bottom mb-4">
|
||||
<el-popover
|
||||
v-model:visible="supportMenuVisible"
|
||||
placement="right"
|
||||
trigger="click"
|
||||
popper-style="padding:4px;border-radius:8px;"
|
||||
:offset="-10"
|
||||
:show-arrow="false"
|
||||
:width="200"
|
||||
:hide-after="0">
|
||||
<div class="nav-menu-support nav-menu-settings">
|
||||
<div class="nav-menu-support__section">
|
||||
<button type="button" class="nav-menu-settings__item" @click="showChangeLogDialog">
|
||||
<span>{{ t('nav_menu.whats_new') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<Separator />
|
||||
<div class="nav-menu-support__section">
|
||||
<span class="nav-menu-support__title">{{ t('nav_menu.resources') }}</span>
|
||||
<button type="button" class="nav-menu-settings__item" @click="handleSupportLink('wiki')">
|
||||
<span>{{ t('nav_menu.wiki') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<Separator />
|
||||
<div class="nav-menu-support__section">
|
||||
<span class="nav-menu-support__title">{{ t('nav_menu.get_help') }}</span>
|
||||
<button type="button" class="nav-menu-settings__item" @click="handleSupportLink('github')">
|
||||
<span>{{ t('nav_menu.github') }}</span>
|
||||
</button>
|
||||
<button type="button" class="nav-menu-settings__item" @click="handleSupportLink('discord')">
|
||||
<span>{{ t('nav_menu.discord') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<template #reference>
|
||||
<div>
|
||||
<TooltipWrapper
|
||||
:delay-duration="150"
|
||||
:content="t('nav_tooltip.help_support')"
|
||||
side="right"
|
||||
:disabled="!isCollapsed">
|
||||
<div class="bottom-button">
|
||||
<i class="ri-question-line"></i>
|
||||
<span v-show="!isCollapsed" class="bottom-button__label">{{
|
||||
t('nav_tooltip.help_support')
|
||||
}}</span>
|
||||
</div>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
</template>
|
||||
</el-popover>
|
||||
|
||||
<el-popover
|
||||
v-model:visible="settingsMenuVisible"
|
||||
placement="right"
|
||||
trigger="click"
|
||||
popper-style="padding:4px;border-radius:8px;"
|
||||
:offset="6"
|
||||
:show-arrow="false"
|
||||
:width="200"
|
||||
:hide-after="0">
|
||||
<div class="nav-menu-settings">
|
||||
<div class="nav-menu-settings__header">
|
||||
<img class="nav-menu-settings__logo" :src="vrcxLogo" alt="VRCX" @click="openGithub" />
|
||||
<div class="nav-menu-settings__meta">
|
||||
<span class="nav-menu-settings__title" @click="openGithub"
|
||||
>VRCX
|
||||
<i class="ri-heart-3-fill nav-menu-settings__heart"></i>
|
||||
</span>
|
||||
<span class="nav-menu-settings__version">{{ version }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
<button type="button" class="nav-menu-settings__item" @click="handleSettingsClick">
|
||||
<span>{{ t('nav_tooltip.settings') }}</span>
|
||||
</button>
|
||||
<button type="button" class="nav-menu-settings__item" @click="handleOpenCustomNavDialog">
|
||||
<span>{{ t('nav_menu.custom_nav.header') }}</span>
|
||||
</button>
|
||||
<el-popover
|
||||
v-model:visible="themeMenuVisible"
|
||||
placement="right-start"
|
||||
trigger="hover"
|
||||
popper-style="padding:4px;border-radius:8px;"
|
||||
:offset="8"
|
||||
:width="200"
|
||||
:hide-after="0">
|
||||
<div class="nav-menu-theme">
|
||||
<button
|
||||
v-for="theme in themes"
|
||||
:key="theme"
|
||||
type="button"
|
||||
class="nav-menu-theme__item"
|
||||
:class="{ 'is-active': themeMode === theme }"
|
||||
@click="handleThemeSelect(theme)">
|
||||
<span class="nav-menu-theme__label">{{ themeDisplayName(theme) }}</span>
|
||||
<span v-if="themeMode === theme" class="nav-menu-theme__check">✓</span>
|
||||
</button>
|
||||
|
||||
<Separator />
|
||||
|
||||
<el-popover
|
||||
v-model:visible="themeColorMenuVisible"
|
||||
placement="right-start"
|
||||
trigger="hover"
|
||||
popper-style="padding:4px;border-radius:8px;"
|
||||
:offset="8"
|
||||
:width="200"
|
||||
:show-arrow="false"
|
||||
:hide-after="0"
|
||||
:teleported="false">
|
||||
<div class="nav-menu-theme nav-menu-theme--colors">
|
||||
<button
|
||||
v-for="color in colorFamilies"
|
||||
:key="color.name"
|
||||
type="button"
|
||||
class="nav-menu-theme__item"
|
||||
:class="{ 'is-active': currentPrimary === color.base }"
|
||||
:disabled="isApplyingPrimaryColor"
|
||||
@click="handleThemeColorSelect(color)">
|
||||
<span class="nav-menu-theme__label nav-menu-theme__label--swatch">
|
||||
<span
|
||||
class="nav-menu-theme__swatch"
|
||||
:style="{ backgroundColor: color.base }"></span>
|
||||
<span class="nav-menu-theme__label-text">{{ color.name }}</span>
|
||||
</span>
|
||||
<span v-if="currentPrimary === color.base" class="nav-menu-theme__check">
|
||||
✓
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<template #reference>
|
||||
<button type="button" class="nav-menu-theme__item" @click.prevent>
|
||||
<span class="nav-menu-theme__label">{{
|
||||
t('view.settings.appearance.theme_color.header')
|
||||
}}</span>
|
||||
<span class="nav-menu-settings__arrow">›</span>
|
||||
</button>
|
||||
<SidebarMenuItem v-else>
|
||||
<Collapsible
|
||||
class="group/collapsible"
|
||||
:default-open="activeMenuIndex && item.children?.some((e) => e.index === activeMenuIndex)">
|
||||
<template #default="{ open }">
|
||||
<CollapsibleTrigger as-child>
|
||||
<SidebarMenuButton
|
||||
:is-active="item.children?.some((e) => e.index === activeMenuIndex)"
|
||||
:tooltip="item.titleIsCustom ? item.title : t(item.title || '')"
|
||||
:class="isNavItemNotified(item) ? 'notify' : undefined">
|
||||
<i
|
||||
:class="item.icon"
|
||||
class="inline-flex size-6 items-center justify-center text-[19px]" />
|
||||
<span v-show="!isCollapsed">{{
|
||||
item.titleIsCustom ? item.title : t(item.title || '')
|
||||
}}</span>
|
||||
<ChevronRight
|
||||
v-show="!isCollapsed"
|
||||
class="ml-auto transition-transform"
|
||||
:class="open ? 'rotate-90' : ''" />
|
||||
</SidebarMenuButton>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<SidebarMenuSub>
|
||||
<SidebarMenuSubItem
|
||||
v-for="entry in item.children"
|
||||
:key="entry.index">
|
||||
<SidebarMenuSubButton
|
||||
:is-active="activeMenuIndex === entry.index"
|
||||
@click="handleSubmenuClick(entry, item.index)">
|
||||
<i
|
||||
v-if="entry.icon"
|
||||
:class="entry.icon"
|
||||
class="inline-flex size-5 items-center justify-center text-[16px]" />
|
||||
<span>{{ t(entry.label) }}</span>
|
||||
</SidebarMenuSubButton>
|
||||
</SidebarMenuSubItem>
|
||||
</SidebarMenuSub>
|
||||
</CollapsibleContent>
|
||||
</template>
|
||||
</el-popover>
|
||||
</Collapsible>
|
||||
</SidebarMenuItem>
|
||||
</template>
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
|
||||
<SidebarFooter class="p-2">
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<SidebarMenuButton :tooltip="t('nav_tooltip.help_support')">
|
||||
<i class="ri-question-line inline-flex size-6 items-center justify-center text-[19px]" />
|
||||
<span v-show="!isCollapsed">{{ t('nav_tooltip.help_support') }}</span>
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="right" align="start" class="w-56">
|
||||
<DropdownMenuItem @click="showChangeLogDialog">
|
||||
<span>{{ t('nav_menu.whats_new') }}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuLabel>{{ t('nav_menu.resources') }}</DropdownMenuLabel>
|
||||
<DropdownMenuItem @click="handleSupportLink('wiki')">
|
||||
<span>{{ t('nav_menu.wiki') }}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuLabel>{{ t('nav_menu.get_help') }}</DropdownMenuLabel>
|
||||
<DropdownMenuItem @click="handleSupportLink('github')">
|
||||
<span>{{ t('nav_menu.github') }}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="handleSupportLink('discord')">
|
||||
<span>{{ t('nav_menu.discord') }}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SidebarMenuItem>
|
||||
|
||||
<SidebarMenuItem>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<SidebarMenuButton :tooltip="t('nav_tooltip.manage')">
|
||||
<i class="ri-settings-3-line inline-flex size-6 items-center justify-center text-[19px]" />
|
||||
<span v-show="!isCollapsed">{{ t('nav_tooltip.manage') }}</span>
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="right" align="start" class="w-64">
|
||||
<div class="flex items-center gap-2 px-2 py-1.5">
|
||||
<img class="h-6 w-6 cursor-pointer" :src="vrcxLogo" alt="VRCX" @click="openGithub" />
|
||||
<div class="flex min-w-0 flex-col">
|
||||
<button
|
||||
type="button"
|
||||
class="text-left text-sm font-medium truncate"
|
||||
@click="openGithub">
|
||||
VRCX
|
||||
</button>
|
||||
<span class="text-xs text-muted-foreground">{{ version }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<template #reference>
|
||||
<button type="button" class="nav-menu-settings__item" @click.prevent>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem @click="handleSettingsClick">
|
||||
<span>{{ t('nav_tooltip.settings') }}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="handleOpenCustomNavDialog">
|
||||
<span>{{ t('nav_menu.custom_nav.header') }}</span>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<span>{{ t('view.settings.appearance.appearance.theme_mode') }}</span>
|
||||
<span class="nav-menu-settings__arrow">›</span>
|
||||
</button>
|
||||
</template>
|
||||
</el-popover>
|
||||
<button
|
||||
type="button"
|
||||
class="nav-menu-settings__item nav-menu-settings__item--danger"
|
||||
@click="handleLogoutClick">
|
||||
<span>{{ t('dialog.user.actions.logout') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<template #reference>
|
||||
<div class="bottom-button">
|
||||
<i class="ri-settings-3-line"></i>
|
||||
<span v-show="!isCollapsed" class="bottom-button__label">{{
|
||||
t('nav_tooltip.manage')
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-popover>
|
||||
<TooltipWrapper
|
||||
:delay-duration="150"
|
||||
:content="t('nav_tooltip.expand_menu')"
|
||||
:disabled="!isCollapsed"
|
||||
side="right">
|
||||
<div class="bottom-button" @click="toggleNavCollapse">
|
||||
<i class="ri-side-bar-line"></i>
|
||||
<span v-show="!isCollapsed" class="bottom-button__label">{{
|
||||
t('nav_tooltip.collapse_menu')
|
||||
}}</span>
|
||||
</div>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent side="right" align="start" class="w-72">
|
||||
<DropdownMenuItem
|
||||
v-for="theme in themes"
|
||||
:key="theme"
|
||||
:class="themeMode === theme ? 'font-medium' : undefined"
|
||||
@click="handleThemeSelect(theme)">
|
||||
<span class="flex-1">{{ themeDisplayName(theme) }}</span>
|
||||
<span v-if="themeMode === theme" class="text-muted-foreground">✓</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<span>{{ t('view.settings.appearance.theme_color.header') }}</span>
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent side="right" align="start" class="w-72 max-h-80 overflow-auto">
|
||||
<DropdownMenuItem
|
||||
v-for="color in colorFamilies"
|
||||
:key="color.name"
|
||||
:disabled="isApplyingPrimaryColor"
|
||||
@click="handleThemeColorSelect(color)">
|
||||
<span class="flex items-center gap-2 min-w-0 flex-1">
|
||||
<span class="h-3 w-3 shrink-0 rounded-sm" :style="{ backgroundColor: color.base }" />
|
||||
<span class="truncate">{{ color.name }}</span>
|
||||
</span>
|
||||
<span v-if="currentPrimary === color.base" class="text-muted-foreground">✓</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem variant="destructive" @click="handleLogoutClick">
|
||||
<span>{{ t('dialog.user.actions.logout') }}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SidebarMenuItem>
|
||||
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton
|
||||
:tooltip="isCollapsed ? t('nav_tooltip.expand_menu') : t('nav_tooltip.collapse_menu')"
|
||||
@click="toggleNavCollapse">
|
||||
<i class="ri-side-bar-line inline-flex size-6 items-center justify-center text-[19px]" />
|
||||
<span v-show="!isCollapsed">{{ t('nav_tooltip.collapse_menu') }}</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarFooter>
|
||||
|
||||
<SidebarRail />
|
||||
</Sidebar>
|
||||
|
||||
<CustomNavDialog
|
||||
v-model:visible="customNavDialogVisible"
|
||||
:layout="navLayout"
|
||||
@@ -244,15 +213,41 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, defineAsyncComponent, onMounted, ref, watch } from 'vue';
|
||||
import { ElMenu, ElMenuItem, ElPopover, ElSubMenu } from 'element-plus';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { dayjs } from 'element-plus';
|
||||
import { computed, defineAsyncComponent, onMounted, ref } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { ChevronRight } from 'lucide-vue-next';
|
||||
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuSub,
|
||||
SidebarMenuSubButton,
|
||||
SidebarMenuSubItem,
|
||||
SidebarRail
|
||||
} from '@/components/ui/sidebar';
|
||||
|
||||
import {
|
||||
useAppearanceSettingsStore,
|
||||
useAuthStore,
|
||||
@@ -314,11 +309,6 @@
|
||||
const { logout } = useAuthStore();
|
||||
const appearanceSettingsStore = useAppearanceSettingsStore();
|
||||
const { themeMode, isNavCollapsed: isCollapsed } = storeToRefs(appearanceSettingsStore);
|
||||
const settingsMenuVisible = ref(false);
|
||||
const themeMenuVisible = ref(false);
|
||||
const themeColorMenuVisible = ref(false);
|
||||
const supportMenuVisible = ref(false);
|
||||
const navMenuRef = ref(null);
|
||||
const navLayout = ref([]);
|
||||
const navLayoutReady = ref(false);
|
||||
|
||||
@@ -407,16 +397,6 @@
|
||||
selectPaletteColor
|
||||
} = useThemePrimaryColor();
|
||||
|
||||
watch(
|
||||
() => activeMenuIndex.value,
|
||||
(value) => {
|
||||
if (value) {
|
||||
navMenuRef.value?.updateActiveIndex(value);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
() => locale.value,
|
||||
() => {
|
||||
@@ -504,28 +484,19 @@
|
||||
};
|
||||
|
||||
const handleSettingsClick = () => {
|
||||
themeMenuVisible.value = false;
|
||||
supportMenuVisible.value = false;
|
||||
settingsMenuVisible.value = false;
|
||||
router.push({ name: 'settings' });
|
||||
};
|
||||
|
||||
const handleLogoutClick = () => {
|
||||
settingsMenuVisible.value = false;
|
||||
logout();
|
||||
};
|
||||
|
||||
const handleThemeSelect = (theme) => {
|
||||
themeMenuVisible.value = false;
|
||||
settingsMenuVisible.value = false;
|
||||
appearanceSettingsStore.setThemeMode(theme);
|
||||
};
|
||||
|
||||
const handleThemeColorSelect = async (colorFamily) => {
|
||||
await selectPaletteColor(colorFamily);
|
||||
themeColorMenuVisible.value = false;
|
||||
themeMenuVisible.value = false;
|
||||
settingsMenuVisible.value = false;
|
||||
};
|
||||
|
||||
const openGithub = () => {
|
||||
@@ -548,9 +519,6 @@
|
||||
};
|
||||
|
||||
const handleOpenCustomNavDialog = () => {
|
||||
themeMenuVisible.value = false;
|
||||
supportMenuVisible.value = false;
|
||||
settingsMenuVisible.value = false;
|
||||
customNavDialogVisible.value = true;
|
||||
};
|
||||
|
||||
@@ -602,7 +570,6 @@
|
||||
};
|
||||
|
||||
const handleSupportLink = (id) => {
|
||||
supportMenuVisible.value = false;
|
||||
const target = links[id];
|
||||
if (target) {
|
||||
openExternalLink(target);
|
||||
@@ -639,39 +606,23 @@
|
||||
return false;
|
||||
};
|
||||
|
||||
const closeNavFlyouts = () => {
|
||||
settingsMenuVisible.value = false;
|
||||
supportMenuVisible.value = false;
|
||||
themeMenuVisible.value = false;
|
||||
themeColorMenuVisible.value = false;
|
||||
};
|
||||
|
||||
const triggerNavAction = (entry, navIndex = entry?.index) => {
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.action === 'direct-access') {
|
||||
closeNavFlyouts();
|
||||
directAccessPaste();
|
||||
if (navIndex) {
|
||||
navMenuRef.value?.updateActiveIndex(navIndex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.routeName) {
|
||||
handleRouteChange(entry.routeName, navIndex);
|
||||
closeNavFlyouts();
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.path) {
|
||||
router.push(entry.path);
|
||||
if (navIndex) {
|
||||
navMenuRef.value?.updateActiveIndex(navIndex);
|
||||
}
|
||||
closeNavFlyouts();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -680,26 +631,8 @@
|
||||
return;
|
||||
}
|
||||
router.push({ name: routeName });
|
||||
if (navIndex) {
|
||||
navMenuRef.value?.updateActiveIndex(navIndex);
|
||||
}
|
||||
};
|
||||
|
||||
watch(settingsMenuVisible, (visible) => {
|
||||
if (visible) {
|
||||
supportMenuVisible.value = false;
|
||||
} else {
|
||||
themeMenuVisible.value = false;
|
||||
themeColorMenuVisible.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
watch(supportMenuVisible, (visible) => {
|
||||
if (visible) {
|
||||
settingsMenuVisible.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
function getFirstNavRoute(layout) {
|
||||
for (const entry of layout) {
|
||||
if (entry.type === 'item') {
|
||||
@@ -759,261 +692,6 @@
|
||||
min-width: 64px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
justify-content: flex-start;
|
||||
background-color: var(--el-bg-color-page);
|
||||
box-shadow: none;
|
||||
backdrop-filter: blur(14px) saturate(130%);
|
||||
}
|
||||
|
||||
.nav-menu-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow: hidden auto;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-menu :deep(.el-menu-item),
|
||||
.nav-menu :deep(.el-sub-menu__title) {
|
||||
height: 46px;
|
||||
line-height: 46px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 10px;
|
||||
font-size: 13px;
|
||||
padding: 0 20px !important;
|
||||
}
|
||||
|
||||
.nav-menu :deep(.el-menu-item i[class*='ri-']),
|
||||
.nav-menu :deep(.el-sub-menu__title i[class*='ri-']) {
|
||||
font-size: 19px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.nav-menu :deep(.el-sub-menu__title > div) {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.nav-menu :deep(.el-sub-menu__icon-arrow) {
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
.bottom-button {
|
||||
font-size: 19px;
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
padding: 0 20px;
|
||||
text-align: left;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
& > span {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-button i {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.bottom-button__label {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-regular);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bottom-button:hover {
|
||||
background-color: var(--el-menu-hover-bg-color);
|
||||
transition:
|
||||
border-color var(--el-transition-duration),
|
||||
background-color var(--el-transition-duration),
|
||||
color var(--el-transition-duration);
|
||||
}
|
||||
|
||||
.nav-menu-container-bottom {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.nav-menu-container.is-collapsed .nav-menu :deep(.el-menu-item),
|
||||
.nav-menu-container.is-collapsed .nav-menu :deep(.el-sub-menu__title) {
|
||||
column-gap: 0;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nav-menu-container.is-collapsed {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-menu-container.is-collapsed .nav-menu :deep(.el-sub-menu__title > div) {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.nav-menu-container.is-collapsed .bottom-button {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
gap: 0;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:deep(.el-menu-item .el-menu-tooltip__trigger) {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
:deep(.el-button.is-text:not(.is-disabled):hover) {
|
||||
background-color: var(--el-menu-hover-bg-color);
|
||||
}
|
||||
|
||||
.nav-menu-settings {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
.nav-menu-settings__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px 8px 10px;
|
||||
.nav-menu-settings__logo {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
object-fit: contain;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nav-menu-settings__meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 12px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.nav-menu-settings__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-regular);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nav-menu-settings__heart {
|
||||
font-size: 14px;
|
||||
color: var(--el-color-success);
|
||||
}
|
||||
|
||||
.nav-menu-settings__version {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
.nav-menu-settings__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 8px 12px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--el-text-color-regular);
|
||||
font-size: 13px;
|
||||
border-radius: 4px;
|
||||
transition: background-color var(--el-transition-duration);
|
||||
cursor: pointer;
|
||||
.nav-menu-settings__arrow {
|
||||
margin-left: auto;
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.nav-menu-settings__item:hover {
|
||||
background-color: var(--el-menu-hover-bg-color);
|
||||
}
|
||||
|
||||
.nav-menu-settings__item--danger {
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
.nav-menu-settings__item--danger:hover {
|
||||
background-color: color-mix(in oklch, var(--el-color-danger) 18%, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
.nav-menu-support {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
.nav-menu-support__section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.nav-menu-support__title {
|
||||
padding: 0 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.4px;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-menu-theme {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
.nav-menu-theme__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 6px 10px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 13px;
|
||||
border-radius: 6px;
|
||||
transition: background-color var(--el-transition-duration);
|
||||
cursor: pointer;
|
||||
.nav-menu-theme__check {
|
||||
font-size: 12px;
|
||||
color: var(--el-color-primary);
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
.nav-menu-theme__item:hover,
|
||||
.nav-menu-theme__item.is-active {
|
||||
background-color: var(--el-menu-hover-bg-color);
|
||||
}
|
||||
|
||||
.nav-menu-theme__label--swatch {
|
||||
display: inline-flex;
|
||||
|
||||
Reference in New Issue
Block a user