mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-19 06:43:51 +02:00
adjust navmenu context menu and my avatars ui
This commit is contained in:
@@ -148,6 +148,10 @@
|
||||
<ContextMenuItem :disabled="!hasNotifications" @click="clearAllNotifications">
|
||||
{{ t('nav_menu.mark_all_read') }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem @click="handleOpenCustomNavDialog">
|
||||
{{ t('nav_menu.custom_nav.header') }}
|
||||
</ContextMenuItem>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
|
||||
@@ -361,7 +365,13 @@
|
||||
DropdownMenuTrigger
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { computed, defineAsyncComponent, h, onMounted, ref, watch } from 'vue';
|
||||
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from '@/components/ui/context-menu';
|
||||
import {
|
||||
ContextMenu,
|
||||
ContextMenuContent,
|
||||
ContextMenuItem,
|
||||
ContextMenuSeparator,
|
||||
ContextMenuTrigger
|
||||
} from '@/components/ui/context-menu';
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
|
||||
import { ChevronRight, Heart } from 'lucide-vue-next';
|
||||
import { Kbd } from '@/components/ui/kbd';
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
</Badge>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-auto p-3" align="start">
|
||||
<PopoverContent class="w-80 p-3" align="start">
|
||||
<div class="flex flex-col gap-3">
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.avatar.info.visibility') }}</FieldLabel>
|
||||
@@ -177,6 +177,17 @@
|
||||
class="cursor-pointer min-h-0">
|
||||
<template #row-context-menu="{ row }">
|
||||
<ContextMenuContent>
|
||||
<ContextMenuItem @click="handleContextMenuAction('details', row.original)">
|
||||
<Eye class="size-4" />
|
||||
{{ t('dialog.avatar.actions.view_details') }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem
|
||||
:disabled="row.original.id === currentAvatarId"
|
||||
@click="handleContextMenuAction('wear', row.original)">
|
||||
<Check class="size-4" />
|
||||
{{ t('view.favorite.select_avatar_tooltip') }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem @click="handleContextMenuAction('manageTags', row.original)">
|
||||
<Tag class="size-4" />
|
||||
{{ t('dialog.avatar.actions.manage_tags') }}
|
||||
@@ -284,6 +295,8 @@
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
Check,
|
||||
Eye,
|
||||
Image as ImageIcon,
|
||||
LayoutGrid,
|
||||
List,
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
ArrowUpDown,
|
||||
Check,
|
||||
Ellipsis,
|
||||
Eye,
|
||||
Image,
|
||||
Monitor,
|
||||
Pencil,
|
||||
@@ -94,7 +95,7 @@ export function getColumns({
|
||||
<img
|
||||
src={ref.thumbnailImageUrl}
|
||||
class="cursor-pointer rounded-sm object-cover"
|
||||
style="width: 36px; height: 24px;"
|
||||
style="width: 34px; height: 22px;"
|
||||
loading="lazy"
|
||||
onClick={() => onShowAvatarDialog(ref.id)}
|
||||
/>
|
||||
@@ -137,7 +138,7 @@ export function getColumns({
|
||||
const tags = row.original.$tags || [];
|
||||
if (!tags.length) return null;
|
||||
return (
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<div class="flex flex-nowrap gap-1 overflow-hidden">
|
||||
{tags.map((entry) => {
|
||||
const hashColor = getTagColor(entry.tag);
|
||||
const storedColor =
|
||||
@@ -367,14 +368,21 @@ export function getColumns({
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
class="rounded-full"
|
||||
size="icon-sm"
|
||||
class="rounded-full h-6 w-6"
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
>
|
||||
<Ellipsis class="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem
|
||||
onClick={() => onShowAvatarDialog(ref.id)}
|
||||
>
|
||||
<Eye class="size-4" />
|
||||
{t('dialog.avatar.actions.view_details')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
onClick={() =>
|
||||
onContextMenuAction('manageTags', ref)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<HoverCard :open-delay="700" :close-delay="100">
|
||||
<HoverCard :open="hoverOpen" :open-delay="700" :close-delay="100" @update:open="handleHoverOpen">
|
||||
<HoverCardTrigger as="div">
|
||||
<ContextMenu>
|
||||
<ContextMenu @update:open="handleContextMenuOpen">
|
||||
<ContextMenuTrigger as="div">
|
||||
<div class="avatar-card-wrapper rounded-lg" @click="$emit('click')">
|
||||
<Card
|
||||
@@ -71,6 +71,10 @@
|
||||
<Eye class="size-4" />
|
||||
{{ t('dialog.avatar.actions.view_details') }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem :disabled="isActive" @click="emit('context-action', 'wear', avatar)">
|
||||
<Check class="size-4" />
|
||||
{{ t('view.favorite.select_avatar_tooltip') }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem @click="emit('context-action', 'manageTags', avatar)">
|
||||
<Tag class="size-4" />
|
||||
@@ -122,7 +126,16 @@
|
||||
<HoverCardContent class="w-80 p-3 text-sm" side="right" :side-offset="8" align="start">
|
||||
<div class="flex flex-col gap-2">
|
||||
<!-- Name -->
|
||||
<div class="font-medium text-base truncate">{{ avatar.name }}</div>
|
||||
<div class="flex items-start gap-1">
|
||||
<div class="font-medium text-base truncate flex-1 min-w-0">{{ avatar.name }}</div>
|
||||
<Button
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
class="shrink-0 size-6 rounded-full"
|
||||
@click="emit('context-action', 'details', avatar)">
|
||||
<ExternalLink class="size-3" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<!-- Tags -->
|
||||
<div v-if="avatar.$tags?.length" class="flex flex-wrap gap-1">
|
||||
@@ -154,9 +167,6 @@
|
||||
</Badge>
|
||||
</span>
|
||||
|
||||
<span class="text-muted-foreground">{{ t('dialog.avatar.info.version') }}</span>
|
||||
<span>{{ avatar.version ?? '-' }}</span>
|
||||
|
||||
<span class="text-muted-foreground">{{ t('dialog.avatar.info.platform') }}</span>
|
||||
<div class="flex items-center gap-1">
|
||||
<Badge v-if="platformInfo.isPC" class="x-tag-platform-pc" variant="outline">
|
||||
@@ -185,6 +195,9 @@
|
||||
<span>{{ iosPerf }}</span>
|
||||
</template>
|
||||
|
||||
<span class="text-muted-foreground">{{ t('dialog.avatar.info.version') }}</span>
|
||||
<span>{{ avatar.version ?? '-' }}</span>
|
||||
|
||||
<template v-if="avatar.$timeSpent">
|
||||
<span class="text-muted-foreground">{{ t('dialog.avatar.info.time_spent') }}</span>
|
||||
<span>{{ timeToText(avatar.$timeSpent) }}</span>
|
||||
@@ -202,7 +215,19 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Apple, Eye, Image as ImageIcon, Monitor, Pencil, RefreshCw, Smartphone, Tag, User } from 'lucide-vue-next';
|
||||
import {
|
||||
Apple,
|
||||
Check,
|
||||
ExternalLink,
|
||||
Eye,
|
||||
Image as ImageIcon,
|
||||
Monitor,
|
||||
Pencil,
|
||||
RefreshCw,
|
||||
Smartphone,
|
||||
Tag,
|
||||
User
|
||||
} from 'lucide-vue-next';
|
||||
import {
|
||||
ContextMenu,
|
||||
ContextMenuContent,
|
||||
@@ -212,15 +237,33 @@
|
||||
} from '@/components/ui/context-menu';
|
||||
import { formatDateFilter, getAvailablePlatforms, getPlatformInfo, timeToText } from '@/shared/utils';
|
||||
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card';
|
||||
import { computed, ref } from 'vue';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card } from '@/components/ui/card';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { computed } from 'vue';
|
||||
import { getTagColor } from '@/shared/constants';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const hoverOpen = ref(false);
|
||||
const contextMenuOpen = ref(false);
|
||||
|
||||
const handleContextMenuOpen = (open) => {
|
||||
contextMenuOpen.value = open;
|
||||
if (open) {
|
||||
hoverOpen.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleHoverOpen = (open) => {
|
||||
if (contextMenuOpen.value) {
|
||||
return;
|
||||
}
|
||||
hoverOpen.value = open;
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
avatar: {
|
||||
type: Object,
|
||||
|
||||
Reference in New Issue
Block a user