This commit is contained in:
pa
2026-01-17 23:14:31 +09:00
committed by Natsumi
parent 5e5abc1141
commit 2d812d7c05
18 changed files with 211 additions and 97 deletions

View File

@@ -8,7 +8,7 @@
:class="['x-location', { 'x-link': link && location !== 'private' && location !== 'offline' }]"
class="inline-flex min-w-0 flex-nowrap items-center overflow-hidden"
@click="handleShowWorldDialog">
<Loader2 :class="['is-loading']" class="mr-1" v-if="isTraveling" />
<Spinner v-if="isTraveling" class="mr-1" />
<span class="min-w-0 truncate">{{ text }}</span>
<span v-if="showInstanceIdInLocation && instanceName" class="ml-1 whitespace-nowrap">{{
` · #${instanceName}`
@@ -31,7 +31,7 @@
:class="['x-location', { 'x-link': link && location !== 'private' && location !== 'offline' }]"
class="inline-flex min-w-0 flex-nowrap items-center overflow-hidden"
@click="handleShowWorldDialog">
<Loader2 :class="['is-loading']" class="mr-1" v-if="isTraveling" />
<Spinner v-if="isTraveling" class="mr-1" />
<span class="min-w-0 truncate">{{ text }}</span>
<span v-if="showInstanceIdInLocation && instanceName" class="ml-1 whitespace-nowrap">{{
` · #${instanceName}`
@@ -54,8 +54,8 @@
</template>
<script setup>
import { AlertTriangle, Loader2, Lock } from 'lucide-vue-next';
import { onBeforeUnmount, ref, watch } from 'vue';
import { AlertTriangle, Lock } from 'lucide-vue-next';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
@@ -67,6 +67,7 @@
useWorldStore
} from '../stores';
import { getGroupName, getWorldName, parseLocation } from '../shared/utils';
import { Spinner } from './ui/spinner';
import { accessTypeLocaleKeyMap } from '../shared/constants';
const { t } = useI18n();

View File

@@ -1,6 +1,6 @@
<template>
<Sidebar side="left" variant="sidebar" collapsible="icon">
<SidebarContent class="pt-4">
<SidebarContent class="pt-2">
<div v-if="navLayoutReady" class="px-2">
<SidebarMenu>
<SidebarMenuItem v-if="pendingVRCXUpdate || pendingVRCXInstall">
@@ -40,7 +40,39 @@
</SidebarMenuItem>
<SidebarMenuItem v-else>
<DropdownMenu
v-if="isCollapsed"
:open="collapsedDropdownOpenId === item.index"
@update:open="(value) => handleCollapsedDropdownOpenChange(item.index, value)">
<DropdownMenuTrigger 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-lg" />
<span v-show="!isCollapsed">{{
item.titleIsCustom ? item.title : t(item.title || '')
}}</span>
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent side="right" align="start" class="w-56">
<DropdownMenuItem
v-for="entry in item.children"
:key="entry.index"
@select="(event) => handleCollapsedSubmenuSelect(event, entry, item.index)">
<i
v-if="entry.icon"
:class="entry.icon"
class="inline-flex size-4 items-center justify-center text-base" />
<span>{{ t(entry.label) }}</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<Collapsible
v-else
class="group/collapsible"
:default-open="
activeMenuIndex && item.children?.some((e) => e.index === activeMenuIndex)
@@ -87,7 +119,7 @@
</SidebarGroup>
</SidebarContent>
<SidebarFooter class="p-2">
<SidebarFooter class="px-2 py-3">
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenu>
@@ -249,8 +281,6 @@
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
<SidebarRail />
</Sidebar>
<CustomNavDialog
@@ -272,8 +302,7 @@
SidebarMenuItem,
SidebarMenuSub,
SidebarMenuSubButton,
SidebarMenuSubItem,
SidebarRail
SidebarMenuSubItem
} from '@/components/ui/sidebar';
import {
DropdownMenu,
@@ -358,6 +387,7 @@
const { themeMode, tableDensity, isDarkMode, isNavCollapsed: isCollapsed } = storeToRefs(appearanceSettingsStore);
const navLayout = ref([]);
const navLayoutReady = ref(false);
const collapsedDropdownOpenId = ref(null);
const menuItems = computed(() => {
const items = [];
@@ -454,6 +484,15 @@
}
);
watch(
() => isCollapsed.value,
(value) => {
if (!value) {
collapsedDropdownOpenId.value = null;
}
}
);
const generateFolderId = () => `nav-folder-${dayjs().toISOString()}-${Math.random().toString().slice(2, 4)}`;
const sanitizeLayout = (layout) => {
@@ -721,6 +760,17 @@
triggerNavAction(entry, navIndex);
};
const handleCollapsedDropdownOpenChange = (index, value) => {
collapsedDropdownOpenId.value = value ? index : null;
};
const handleCollapsedSubmenuSelect = (event, entry, index) => {
if (event?.preventDefault) {
event.preventDefault();
}
handleSubmenuClick(entry, index);
};
const handleMenuItemClick = (item) => {
triggerNavAction(item, item?.index);
};

View File

@@ -124,8 +124,8 @@
PaginationPrevious
} from '../pagination';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../table';
import { ScrollArea } from '../scroll-area';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../select';
import { ScrollArea } from '../scroll-area';
const props = defineProps({
table: {

View File

@@ -75,7 +75,7 @@
<div
:class="
cn(
'relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',
'relative w-(--sidebar-width) bg-transparent',
'group-data-[collapsible=offcanvas]:w-0',
'group-data-[side=right]:rotate-180',
variant === 'floating' || variant === 'inset'
@@ -86,14 +86,14 @@
<div
:class="
cn(
'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex',
'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) md:flex',
side === 'left'
? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
: 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
// Adjust the padding for floating and inset variants.
variant === 'floating' || variant === 'inset'
? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'
: 'group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l',
: 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',
props.class
)
"