mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-22 16:23:50 +02:00
theme and virtualized list
This commit is contained in:
@@ -1,79 +1,62 @@
|
||||
<template>
|
||||
<Dialog v-model:open="socialStatusDialog.visible">
|
||||
<DialogContent class="x-dialog sm:max-w-100">
|
||||
<DialogContent class="x-dialog sm:-w-20">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('dialog.social_status.header') }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div>
|
||||
<Select :model-value="socialStatusDialog.status" @update:modelValue="handleSocialStatusChange">
|
||||
<SelectTrigger size="sm" style="margin-top: 10px; width: 100%">
|
||||
<span class="flex items-center gap-2">
|
||||
<i v-if="socialStatusDialog.status === 'join me'" class="x-user-status joinme"></i>
|
||||
<i v-else-if="socialStatusDialog.status === 'active'" class="x-user-status online"></i>
|
||||
<i v-else-if="socialStatusDialog.status === 'ask me'" class="x-user-status askme"></i>
|
||||
<i v-else-if="socialStatusDialog.status === 'busy'" class="x-user-status busy"></i>
|
||||
<i v-else-if="socialStatusDialog.status === 'offline'" class="x-user-status offline"></i>
|
||||
<SelectValue :placeholder="t('dialog.social_status.status_placeholder')" />
|
||||
</span>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="join me" :text-value="t('dialog.user.status.join_me')">
|
||||
<i class="x-user-status joinme"></i> {{ t('dialog.user.status.join_me') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="active" :text-value="t('dialog.user.status.online')">
|
||||
<i class="x-user-status online"></i> {{ t('dialog.user.status.online') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="ask me" :text-value="t('dialog.user.status.ask_me')">
|
||||
<i class="x-user-status askme"></i> {{ t('dialog.user.status.ask_me') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="busy" :text-value="t('dialog.user.status.busy')">
|
||||
<i class="x-user-status busy"></i> {{ t('dialog.user.status.busy') }}
|
||||
</SelectItem>
|
||||
<SelectItem
|
||||
v-if="currentUser.$isModerator"
|
||||
value="offline"
|
||||
:text-value="t('dialog.user.status.offline')">
|
||||
<i class="x-user-status offline"></i> {{ t('dialog.user.status.offline') }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<div class="pt-6 pb-4 px-16">
|
||||
<div class="flex items-center gap-2">
|
||||
<InputGroupField
|
||||
v-model="socialStatusDialog.statusDescription"
|
||||
:placeholder="t('dialog.social_status.status_placeholder')"
|
||||
:maxlength="32"
|
||||
clearable>
|
||||
</InputGroupField>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<InputGroupButton variant="outline" size="icon-lg">
|
||||
<History class="text-lg" />
|
||||
</InputGroupButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuItem v-if="!historyItems.length" disabled>
|
||||
{{ t('dialog.social_status.history') }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
v-for="item in historyItems"
|
||||
:key="item.no ?? item.status"
|
||||
@click="setSocialStatusFromHistory(item)">
|
||||
{{ item.status }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
<InputGroupField
|
||||
v-model="socialStatusDialog.statusDescription"
|
||||
:placeholder="t('dialog.social_status.status_placeholder')"
|
||||
:maxlength="32"
|
||||
clearable
|
||||
show-count
|
||||
class="mt-2.5" />
|
||||
<Collapsible v-model:open="isOpen" class="mt-3 flex w-full flex-col gap-2">
|
||||
<div class="flex items-center justify-between gap-4 px-4">
|
||||
<h4 class="text-sm font-semibold">{{ t('dialog.social_status.history') }}</h4>
|
||||
<CollapsibleTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8">
|
||||
<ChevronsUpDown />
|
||||
<span class="sr-only">Toggle</span>
|
||||
</Button>
|
||||
</CollapsibleTrigger>
|
||||
</div>
|
||||
<div
|
||||
v-if="!isOpen && latestHistoryItem"
|
||||
class="cursor-pointer rounded-md border w-full px-4 py-2 font-mono text-sm"
|
||||
@click="setSocialStatusFromHistory(latestHistoryItem)">
|
||||
{{ latestHistoryItem.status }}
|
||||
</div>
|
||||
<CollapsibleContent class="flex flex-col gap-2">
|
||||
<div
|
||||
v-for="item in historyItems"
|
||||
:key="item.no ?? item.status"
|
||||
class="cursor-pointer rounded-md border w-full px-4 py-2 font-mono text-sm"
|
||||
@click="setSocialStatusFromHistory(item)">
|
||||
{{ item.status }}
|
||||
</div>
|
||||
</CollapsibleContent></Collapsible
|
||||
>
|
||||
<div class="mt-6 flex flex-col gap-2" role="radiogroup">
|
||||
<Item
|
||||
v-for="option in statusOptions"
|
||||
:key="option.value"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
role="radio"
|
||||
tabindex="0"
|
||||
:aria-checked="socialStatusDialog.status === option.value"
|
||||
class="cursor-pointer hover:bg-accent"
|
||||
@click="handleSocialStatusChange(option.value)"
|
||||
@keydown.enter.prevent="handleSocialStatusChange(option.value)"
|
||||
@keydown.space.prevent="handleSocialStatusChange(option.value)">
|
||||
<ItemMedia>
|
||||
<i class="x-user-status" :class="option.statusClass"></i>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>{{ option.label }}</ItemTitle>
|
||||
</ItemContent>
|
||||
<ItemActions>
|
||||
<Check v-if="socialStatusDialog.status === option.value" class="text-base text-primary" />
|
||||
</ItemActions>
|
||||
</Item>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
@@ -86,13 +69,18 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
|
||||
import { computed, ref } from 'vue';
|
||||
import { Item, ItemActions, ItemContent, ItemMedia, ItemTitle } from '@/components/ui/item';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { Check, History } from 'lucide-vue-next';
|
||||
import { InputGroupButton, InputGroupField } from '@/components/ui/input-group';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ChevronsUpDown } from 'lucide-vue-next';
|
||||
import { InputGroupField } from '@/components/ui/input-group';
|
||||
import { computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
@@ -114,9 +102,40 @@
|
||||
}
|
||||
});
|
||||
|
||||
const isOpen = ref(false);
|
||||
const historyItems = computed(() => props.socialStatusHistoryTable?.data ?? []);
|
||||
const latestHistoryItem = computed(() => historyItems.value[0] ?? null);
|
||||
|
||||
const statusOptions = computed(() => {
|
||||
const options = [
|
||||
{
|
||||
value: 'join me',
|
||||
statusClass: 'joinme',
|
||||
label: t('dialog.user.status.join_me')
|
||||
},
|
||||
{
|
||||
value: 'active',
|
||||
statusClass: 'online',
|
||||
label: t('dialog.user.status.online')
|
||||
},
|
||||
{
|
||||
value: 'ask me',
|
||||
statusClass: 'askme',
|
||||
label: t('dialog.user.status.ask_me')
|
||||
},
|
||||
{
|
||||
value: 'busy',
|
||||
statusClass: 'busy',
|
||||
label: t('dialog.user.status.busy')
|
||||
}
|
||||
];
|
||||
if (currentUser.value?.$isModerator) {
|
||||
options.push({
|
||||
value: 'offline',
|
||||
statusClass: 'offline',
|
||||
label: t('dialog.user.status.offline')
|
||||
});
|
||||
}
|
||||
return options;
|
||||
});
|
||||
|
||||
function handleSocialStatusChange(value) {
|
||||
props.socialStatusDialog.status = String(value);
|
||||
|
||||
Reference in New Issue
Block a user