mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-06 06:46:04 +02:00
fix styles
This commit is contained in:
+5
-1
@@ -21,11 +21,15 @@ html {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
height: calc(100vh - 20px);
|
height: calc(100vh - 20px);
|
||||||
margin: 10px 10px 10px 0;
|
margin: 10px 0 10px 0;
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.aside-collapsed .x-container {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
html.dark .x-container {
|
html.dark .x-container {
|
||||||
background: var(--sidebar);
|
background: var(--sidebar);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,12 @@
|
|||||||
<span class="flex items-center"
|
<span class="flex items-center"
|
||||||
>{{ avatarName }} <Lock v-if="avatarType && avatarType === '(own)'" class="h-4 w-4 mx-1"
|
>{{ avatarName }} <Lock v-if="avatarType && avatarType === '(own)'" class="h-4 w-4 mx-1"
|
||||||
/></span>
|
/></span>
|
||||||
<span v-if="avatarTags" style="font-size: 12px">{{ avatarTags }}</span>
|
<TooltipWrapper v-if="avatarTags">
|
||||||
|
<template #content>
|
||||||
|
<span>{{ avatarTags }}</span>
|
||||||
|
</template>
|
||||||
|
<span v-if="avatarTags" style="font-size: 12px" class="truncate">{{ avatarTags }}</span>
|
||||||
|
</TooltipWrapper>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -11,6 +16,7 @@
|
|||||||
import { ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import { Lock } from 'lucide-vue-next';
|
import { Lock } from 'lucide-vue-next';
|
||||||
|
|
||||||
|
import { TooltipWrapper } from './ui/tooltip';
|
||||||
import { useAvatarStore } from '../stores';
|
import { useAvatarStore } from '../stores';
|
||||||
|
|
||||||
const avatarStore = useAvatarStore();
|
const avatarStore = useAvatarStore();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<span @click="showUserDialog" class="x-link">{{ username }}</span>
|
<span @click="showUserDialog" class="cursor-pointer">{{ username }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|||||||
+67
-57
@@ -3,9 +3,9 @@
|
|||||||
<div v-if="!text" class="transparent">-</div>
|
<div v-if="!text" class="transparent">-</div>
|
||||||
<div v-show="text" class="flex items-center">
|
<div v-show="text" class="flex items-center">
|
||||||
<div v-if="region" :class="['flags', 'mr-1.5', region]"></div>
|
<div v-if="region" :class="['flags', 'mr-1.5', region]"></div>
|
||||||
<template v-if="disableTooltip">
|
<TooltipWrapper :content="tooltipContent" :disabled="tooltipDisabled" :delay-duration="300" side="top">
|
||||||
<div
|
<div
|
||||||
:class="['x-location', { 'x-link': link && location !== 'private' && location !== 'offline' }]"
|
:class="locationClasses"
|
||||||
class="inline-flex min-w-0 flex-nowrap items-center overflow-hidden"
|
class="inline-flex min-w-0 flex-nowrap items-center overflow-hidden"
|
||||||
@click="handleShowWorldDialog">
|
@click="handleShowWorldDialog">
|
||||||
<Spinner v-if="isTraveling" class="mr-1" />
|
<Spinner v-if="isTraveling" class="mr-1" />
|
||||||
@@ -13,48 +13,25 @@
|
|||||||
<span v-if="showInstanceIdInLocation && instanceName" class="ml-1 whitespace-nowrap">{{
|
<span v-if="showInstanceIdInLocation && instanceName" class="ml-1 whitespace-nowrap">{{
|
||||||
` · #${instanceName}`
|
` · #${instanceName}`
|
||||||
}}</span>
|
}}</span>
|
||||||
<span v-if="groupName" class="ml-0.5 whitespace-nowrap x-link" @click.stop="handleShowGroupDialog">
|
<span
|
||||||
|
v-if="groupName"
|
||||||
|
class="ml-0.5 whitespace-nowrap cursor-pointer"
|
||||||
|
@click.stop="handleShowGroupDialog">
|
||||||
({{ groupName }})
|
({{ groupName }})
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
</TooltipWrapper>
|
||||||
|
|
||||||
<AlertTriangle v-if="isClosed" :class="['inline-block', 'ml-5']" style="color: lightcoral" />
|
<TooltipWrapper v-if="isClosed" :content="closedTooltip" :disabled="disableTooltip">
|
||||||
</template>
|
<AlertTriangle class="inline-block ml-2 text-muted-foreground" />
|
||||||
|
</TooltipWrapper>
|
||||||
<template v-else>
|
<Lock v-if="strict" class="inline-block ml-2 text-muted-foreground" />
|
||||||
<TooltipWrapper
|
|
||||||
:content="`${t('dialog.new_instance.instance_id')}: #${instanceName}`"
|
|
||||||
:disabled="!instanceName || showInstanceIdInLocation"
|
|
||||||
:delay-duration="300"
|
|
||||||
side="top">
|
|
||||||
<div
|
|
||||||
:class="['x-location', { 'x-link': link && location !== 'private' && location !== 'offline' }]"
|
|
||||||
class="inline-flex min-w-0 flex-nowrap items-center overflow-hidden"
|
|
||||||
@click="handleShowWorldDialog">
|
|
||||||
<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}`
|
|
||||||
}}</span>
|
|
||||||
<span
|
|
||||||
v-if="groupName"
|
|
||||||
class="ml-0.5 whitespace-nowrap x-link"
|
|
||||||
@click.stop="handleShowGroupDialog">
|
|
||||||
({{ groupName }})
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</TooltipWrapper>
|
|
||||||
<TooltipWrapper v-if="isClosed" :content="t('dialog.user.info.instance_closed')">
|
|
||||||
<AlertTriangle :class="['inline-block', 'ml-5']" style="color: lightcoral" />
|
|
||||||
</TooltipWrapper>
|
|
||||||
</template>
|
|
||||||
<Lock v-if="strict" :class="['inline-block', 'ml-5']" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onBeforeUnmount, ref, watch } from 'vue';
|
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
||||||
import { AlertTriangle, Lock } from 'lucide-vue-next';
|
import { AlertTriangle, Lock } from 'lucide-vue-next';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
@@ -113,6 +90,19 @@
|
|||||||
const isClosed = ref(false);
|
const isClosed = ref(false);
|
||||||
const instanceName = ref('');
|
const instanceName = ref('');
|
||||||
|
|
||||||
|
const isLocationLink = computed(() => props.link && props.location !== 'private' && props.location !== 'offline');
|
||||||
|
const locationClasses = computed(() => [
|
||||||
|
'x-location',
|
||||||
|
{
|
||||||
|
'cursor-pointer': isLocationLink.value
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
const tooltipContent = computed(() => `${t('dialog.new_instance.instance_id')}: #${instanceName.value}`);
|
||||||
|
const tooltipDisabled = computed(
|
||||||
|
() => props.disableTooltip || !instanceName.value || showInstanceIdInLocation.value
|
||||||
|
);
|
||||||
|
const closedTooltip = computed(() => t('dialog.user.info.instance_closed'));
|
||||||
|
|
||||||
let isDisposed = false;
|
let isDisposed = false;
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
isDisposed = true;
|
isDisposed = true;
|
||||||
@@ -136,16 +126,21 @@
|
|||||||
return props.location;
|
return props.location;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parse() {
|
function resetState() {
|
||||||
if (isDisposed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
text.value = '';
|
text.value = '';
|
||||||
region.value = '';
|
region.value = '';
|
||||||
strict.value = false;
|
strict.value = false;
|
||||||
isTraveling.value = false;
|
isTraveling.value = false;
|
||||||
groupName.value = '';
|
groupName.value = '';
|
||||||
isClosed.value = false;
|
isClosed.value = false;
|
||||||
|
instanceName.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse() {
|
||||||
|
if (isDisposed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resetState();
|
||||||
|
|
||||||
let instanceId = props.location;
|
let instanceId = props.location;
|
||||||
if (typeof props.traveling !== 'undefined' && props.location === 'traveling') {
|
if (typeof props.traveling !== 'undefined' && props.location === 'traveling') {
|
||||||
@@ -159,27 +154,43 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const instanceRef = cachedInstances.get(L.tag);
|
applyInstanceRef(L);
|
||||||
if (typeof instanceRef !== 'undefined') {
|
updateGroupName(L, instanceId);
|
||||||
if (instanceRef.displayName) {
|
updateRegion(L);
|
||||||
setText(L);
|
strict.value = L.strict;
|
||||||
instanceName.value = instanceRef.displayName;
|
}
|
||||||
}
|
|
||||||
if (instanceRef.closedAt) {
|
|
||||||
isClosed.value = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
function applyInstanceRef(L) {
|
||||||
|
const instanceRef = cachedInstances.get(L.tag);
|
||||||
|
if (typeof instanceRef === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (instanceRef.displayName) {
|
||||||
|
setText(L);
|
||||||
|
instanceName.value = instanceRef.displayName;
|
||||||
|
}
|
||||||
|
if (instanceRef.closedAt) {
|
||||||
|
isClosed.value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateGroupName(L, instanceId) {
|
||||||
if (props.grouphint) {
|
if (props.grouphint) {
|
||||||
groupName.value = props.grouphint;
|
groupName.value = props.grouphint;
|
||||||
} else if (L.groupId) {
|
return;
|
||||||
groupName.value = L.groupId;
|
|
||||||
getGroupName(instanceId).then((name) => {
|
|
||||||
if (!isDisposed && name && currentInstanceId() === L.tag) {
|
|
||||||
groupName.value = name;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
if (!L.groupId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
groupName.value = L.groupId;
|
||||||
|
getGroupName(instanceId).then((name) => {
|
||||||
|
if (!isDisposed && name && currentInstanceId() === L.tag) {
|
||||||
|
groupName.value = name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateRegion(L) {
|
||||||
region.value = '';
|
region.value = '';
|
||||||
if (!L.isOffline && !L.isPrivate && !L.isTraveling) {
|
if (!L.isOffline && !L.isPrivate && !L.isTraveling) {
|
||||||
region.value = L.region;
|
region.value = L.region;
|
||||||
@@ -187,7 +198,6 @@
|
|||||||
region.value = 'us';
|
region.value = 'us';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strict.value = L.strict;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setText(L) {
|
function setText(L) {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<span class="x-location-world">
|
<span class="x-location-world">
|
||||||
<span v-if="region" :class="['flags', 'inline-block', 'mr-1.25', region]"></span>
|
<span v-if="region" :class="['flags', 'inline-block', 'mr-1.25', region]"></span>
|
||||||
<span @click="showLaunchDialog" class="x-link">
|
<span @click="showLaunchDialog" class="cursor-pointer">
|
||||||
<Unlock v-if="isUnlocked" :class="['inline-block', 'mr-1.25']" />
|
<Unlock v-if="isUnlocked" :class="['inline-block', 'mr-1.25']" />
|
||||||
<span> {{ accessTypeName }} #{{ instanceName }}</span>
|
<span> {{ accessTypeName }} #{{ instanceName }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="groupName" @click="showGroupDialog" class="x-link">({{ groupName }})</span>
|
<span v-if="groupName" @click="showGroupDialog" class="cursor-pointer">({{ groupName }})</span>
|
||||||
<TooltipWrapper v-if="isClosed" :content="t('dialog.user.info.instance_closed')">
|
<TooltipWrapper v-if="isClosed" :content="t('dialog.user.info.instance_closed')">
|
||||||
<AlertTriangle :class="['inline-block', 'ml-5']" style="color: lightcoral" />
|
<AlertTriangle :class="['inline-block', 'ml-5']" style="color: lightcoral" />
|
||||||
</TooltipWrapper>
|
</TooltipWrapper>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<div style="display: flex">
|
<div style="display: flex">
|
||||||
<img
|
<img
|
||||||
:src="avatarDialog.ref.thumbnailImageUrl"
|
:src="avatarDialog.ref.thumbnailImageUrl"
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
@click="showFullscreenImageDialog(avatarDialog.ref.imageUrl)"
|
@click="showFullscreenImageDialog(avatarDialog.ref.imageUrl)"
|
||||||
style="flex: none; width: 160px; height: 120px; border-radius: 12px"
|
style="flex: none; width: 160px; height: 120px; border-radius: 12px"
|
||||||
loading="lazy" />
|
loading="lazy" />
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 5px">
|
<div style="margin-top: 5px">
|
||||||
<span
|
<span
|
||||||
class="x-link x-grey"
|
class="cursor-pointer x-grey"
|
||||||
style="font-family: monospace"
|
style="font-family: monospace"
|
||||||
@click="showUserDialog(avatarDialog.ref.authorId)"
|
@click="showUserDialog(avatarDialog.ref.authorId)"
|
||||||
v-text="avatarDialog.ref.authorName"></span>
|
v-text="avatarDialog.ref.authorName"></span>
|
||||||
@@ -105,7 +105,7 @@
|
|||||||
<Badge
|
<Badge
|
||||||
v-if="avatarDialog.inCache"
|
v-if="avatarDialog.inCache"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
style="margin-right: 5px; margin-top: 5px"
|
style="margin-right: 5px; margin-top: 5px"
|
||||||
@click="openFolderGeneric(avatarDialog.cachePath)">
|
@click="openFolderGeneric(avatarDialog.cachePath)">
|
||||||
<span v-text="avatarDialog.cacheSize"></span>
|
<span v-text="avatarDialog.cacheSize"></span>
|
||||||
|
|||||||
@@ -154,7 +154,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<a
|
<a
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
@click.prevent="openExternalLink('https://remixicon.com/')">
|
@click.prevent="openExternalLink('https://remixicon.com/')">
|
||||||
https://remixicon.com/
|
https://remixicon.com/
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<img
|
<img
|
||||||
:src="groupDialog.ref.iconUrl"
|
:src="groupDialog.ref.iconUrl"
|
||||||
style="flex: none; width: 120px; height: 120px; border-radius: 12px"
|
style="flex: none; width: 120px; height: 120px; border-radius: 12px"
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
@click="showFullscreenImageDialog(groupDialog.ref.iconUrl)"
|
@click="showFullscreenImageDialog(groupDialog.ref.iconUrl)"
|
||||||
loading="lazy" />
|
loading="lazy" />
|
||||||
<div style="flex: 1; display: flex; align-items: center; margin-left: 15px">
|
<div style="flex: 1; display: flex; align-items: center; margin-left: 15px">
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
</TooltipWrapper>
|
</TooltipWrapper>
|
||||||
<div style="margin-top: 5px">
|
<div style="margin-top: 5px">
|
||||||
<span
|
<span
|
||||||
class="x-link x-grey"
|
class="cursor-pointer x-grey"
|
||||||
style="font-family: monospace"
|
style="font-family: monospace"
|
||||||
@click="showUserDialog(groupDialog.ref.ownerId)"
|
@click="showUserDialog(groupDialog.ref.ownerId)"
|
||||||
v-text="groupDialog.ownerDisplayName"></span>
|
v-text="groupDialog.ownerDisplayName"></span>
|
||||||
@@ -357,7 +357,7 @@
|
|||||||
<div class="group-banner-image-info">
|
<div class="group-banner-image-info">
|
||||||
<img
|
<img
|
||||||
:src="groupDialog.ref.bannerUrl"
|
:src="groupDialog.ref.bannerUrl"
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
style="
|
style="
|
||||||
flex: none;
|
flex: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -424,7 +424,7 @@
|
|||||||
style="display: inline-block; margin-right: 5px">
|
style="display: inline-block; margin-right: 5px">
|
||||||
<img
|
<img
|
||||||
:src="groupDialog.announcement.imageUrl"
|
:src="groupDialog.announcement.imageUrl"
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
style="
|
style="
|
||||||
flex: none;
|
flex: none;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
@@ -760,7 +760,7 @@
|
|||||||
<div v-if="post.imageUrl" style="display: inline-block; margin-right: 5px">
|
<div v-if="post.imageUrl" style="display: inline-block; margin-right: 5px">
|
||||||
<img
|
<img
|
||||||
:src="post.imageUrl"
|
:src="post.imageUrl"
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
style="
|
style="
|
||||||
flex: none;
|
flex: none;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
@@ -1123,7 +1123,7 @@
|
|||||||
class="p-0 overflow-hidden transition-shadow hover:shadow-md">
|
class="p-0 overflow-hidden transition-shadow hover:shadow-md">
|
||||||
<img
|
<img
|
||||||
:src="image.imageUrl"
|
:src="image.imageUrl"
|
||||||
:class="['x-link', 'max-w-full', 'max-h-full']"
|
:class="[' cursor-pointer', 'max-w-full', 'max-h-full']"
|
||||||
@click="showFullscreenImageDialog(image.imageUrl)"
|
@click="showFullscreenImageDialog(image.imageUrl)"
|
||||||
loading="lazy" />
|
loading="lazy" />
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div v-if="inviteDialog.visible">
|
<div v-if="inviteDialog.visible">
|
||||||
<Location :location="inviteDialog.worldId" :link="false" />
|
<Location :location="inviteDialog.worldId" :link="false" class="cursor-default" />
|
||||||
<br />
|
<br />
|
||||||
<Button size="sm" class="mr-2" variant="outline" style="margin-top: 10px" @click="addSelfToInvite">{{
|
<Button size="sm" class="mr-2" variant="outline" style="margin-top: 10px" @click="addSelfToInvite">{{
|
||||||
t('dialog.invite.add_self')
|
t('dialog.invite.add_self')
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
<span class="flex items-center gap-1">
|
<span class="flex items-center gap-1">
|
||||||
<span>{{ t('dialog.launch.short_url') }}</span>
|
<span>{{ t('dialog.launch.short_url') }}</span>
|
||||||
<TooltipWrapper side="top" :content="t('dialog.launch.short_url_notice')">
|
<TooltipWrapper side="top" :content="t('dialog.launch.short_url_notice')">
|
||||||
<AlertTriangle />
|
<Info class="text-muted-foreground" />
|
||||||
</TooltipWrapper>
|
</TooltipWrapper>
|
||||||
</span>
|
</span>
|
||||||
</FieldLabel>
|
</FieldLabel>
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
} from '@/components/ui/dropdown-menu';
|
} from '@/components/ui/dropdown-menu';
|
||||||
import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field';
|
import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field';
|
||||||
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
||||||
import { AlertTriangle, Copy, MoreHorizontal } from 'lucide-vue-next';
|
import { Copy, Info, MoreHorizontal } from 'lucide-vue-next';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ButtonGroup } from '@/components/ui/button-group';
|
import { ButtonGroup } from '@/components/ui/button-group';
|
||||||
import { InputGroupField } from '@/components/ui/input-group';
|
import { InputGroupField } from '@/components/ui/input-group';
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export const createColumns = ({ onLookupUser }) => [
|
|||||||
const original = row.original;
|
const original = row.original;
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class=" cursor-pointer"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
onLookupUser?.(original);
|
onLookupUser?.(original);
|
||||||
|
|||||||
@@ -66,10 +66,6 @@
|
|||||||
{{ t('dialog.user.actions.edit_pronouns') }}
|
{{ t('dialog.user.actions.edit_pronouns') }}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem @click="onCommand('Logout')">
|
|
||||||
<Power class="size-4" />
|
|
||||||
{{ t('dialog.user.actions.logout') }}
|
|
||||||
</DropdownMenuItem>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<template v-if="userDialog.isFriend">
|
<template v-if="userDialog.isFriend">
|
||||||
|
|||||||
@@ -178,7 +178,7 @@
|
|||||||
class="extra">
|
class="extra">
|
||||||
<div style="display: inline-block; flex: none; margin-right: 5px">
|
<div style="display: inline-block; flex: none; margin-right: 5px">
|
||||||
<Avatar
|
<Avatar
|
||||||
class="x-link size-15! rounded-lg!"
|
class="cursor-pointer size-15! rounded-lg!"
|
||||||
:style="{
|
:style="{
|
||||||
background: userDialog.isRepresentedGroupLoading ? '#f5f7fa' : ''
|
background: userDialog.isRepresentedGroupLoading ? '#f5f7fa' : ''
|
||||||
}"
|
}"
|
||||||
@@ -1442,7 +1442,6 @@
|
|||||||
const { getFriendRequest, handleFriendDelete } = useFriendStore();
|
const { getFriendRequest, handleFriendDelete } = useFriendStore();
|
||||||
const { clearInviteImageUpload, showFullscreenImageDialog, showGalleryPage } = useGalleryStore();
|
const { clearInviteImageUpload, showFullscreenImageDialog, showGalleryPage } = useGalleryStore();
|
||||||
|
|
||||||
const { logout } = useAuthStore();
|
|
||||||
const { cachedConfig } = storeToRefs(useAuthStore());
|
const { cachedConfig } = storeToRefs(useAuthStore());
|
||||||
const { applyPlayerModeration, handlePlayerModerationDelete } = useModerationStore();
|
const { applyPlayerModeration, handlePlayerModerationDelete } = useModerationStore();
|
||||||
const { shiftHeld } = storeToRefs(useUiStore());
|
const { shiftHeld } = storeToRefs(useUiStore());
|
||||||
@@ -1802,8 +1801,6 @@
|
|||||||
showBioDialog();
|
showBioDialog();
|
||||||
} else if (command === 'Pencil Pronouns') {
|
} else if (command === 'Pencil Pronouns') {
|
||||||
showPronounsDialog();
|
showPronounsDialog();
|
||||||
} else if (command === 'Logout') {
|
|
||||||
logout();
|
|
||||||
} else if (command === 'Request Invite') {
|
} else if (command === 'Request Invite') {
|
||||||
notificationRequest
|
notificationRequest
|
||||||
.sendRequestInvite(
|
.sendRequestInvite(
|
||||||
|
|||||||
@@ -4,14 +4,14 @@
|
|||||||
v-if="
|
v-if="
|
||||||
!userDialog.loading && (userDialog.ref.profilePicOverrideThumbnail || userDialog.ref.profilePicOverride)
|
!userDialog.loading && (userDialog.ref.profilePicOverrideThumbnail || userDialog.ref.profilePicOverride)
|
||||||
"
|
"
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
:src="userDialog.ref.profilePicOverrideThumbnail || userDialog.ref.profilePicOverride"
|
:src="userDialog.ref.profilePicOverrideThumbnail || userDialog.ref.profilePicOverride"
|
||||||
style="flex: none; height: 120px; width: 213.33px; border-radius: 12px; object-fit: cover"
|
style="flex: none; height: 120px; width: 213.33px; border-radius: 12px; object-fit: cover"
|
||||||
@click="showFullscreenImageDialog(userDialog.ref.profilePicOverride)"
|
@click="showFullscreenImageDialog(userDialog.ref.profilePicOverride)"
|
||||||
loading="lazy" />
|
loading="lazy" />
|
||||||
<img
|
<img
|
||||||
v-else-if="!userDialog.loading"
|
v-else-if="!userDialog.loading"
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
:src="userDialog.ref.currentAvatarThumbnailImageUrl"
|
:src="userDialog.ref.currentAvatarThumbnailImageUrl"
|
||||||
style="flex: none; height: 120px; width: 160px; border-radius: 12px; object-fit: cover"
|
style="flex: none; height: 120px; width: 160px; border-radius: 12px; object-fit: cover"
|
||||||
@click="showFullscreenImageDialog(userDialog.ref.currentAvatarImageUrl)"
|
@click="showFullscreenImageDialog(userDialog.ref.currentAvatarImageUrl)"
|
||||||
@@ -191,7 +191,7 @@
|
|||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<img
|
<img
|
||||||
class="x-link hover:grayscale-0"
|
class="cursor-pointer hover:grayscale-0"
|
||||||
:src="badge.badgeImageUrl"
|
:src="badge.badgeImageUrl"
|
||||||
style="
|
style="
|
||||||
flex: none;
|
flex: none;
|
||||||
@@ -208,7 +208,7 @@
|
|||||||
<PopoverContent side="bottom" class="w-75">
|
<PopoverContent side="bottom" class="w-75">
|
||||||
<img
|
<img
|
||||||
:src="badge.badgeImageUrl"
|
:src="badge.badgeImageUrl"
|
||||||
:class="['x-link', 'max-w-full', 'max-h-full']"
|
:class="['cursor-pointer', 'max-w-full', 'max-h-full']"
|
||||||
@click="showFullscreenImageDialog(badge.badgeImageUrl)"
|
@click="showFullscreenImageDialog(badge.badgeImageUrl)"
|
||||||
loading="lazy" />
|
loading="lazy" />
|
||||||
<br />
|
<br />
|
||||||
@@ -253,7 +253,7 @@
|
|||||||
|
|
||||||
<div v-if="userDialog.ref.userIcon" style="flex: none; margin-right: 10px">
|
<div v-if="userDialog.ref.userIcon" style="flex: none; margin-right: 10px">
|
||||||
<img
|
<img
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
:src="userImage(userDialog.ref, true, '256', true)"
|
:src="userImage(userDialog.ref, true, '256', true)"
|
||||||
style="flex: none; width: 120px; height: 120px; border-radius: 12px; object-fit: cover"
|
style="flex: none; width: 120px; height: 120px; border-radius: 12px; object-fit: cover"
|
||||||
@click="showFullscreenImageDialog(userDialog.ref.userIcon)"
|
@click="showFullscreenImageDialog(userDialog.ref.userIcon)"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<div style="display: flex">
|
<div style="display: flex">
|
||||||
<img
|
<img
|
||||||
:src="worldDialog.ref.thumbnailImageUrl"
|
:src="worldDialog.ref.thumbnailImageUrl"
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
style="flex: none; width: 160px; height: 120px; border-radius: 12px"
|
style="flex: none; width: 160px; height: 120px; border-radius: 12px"
|
||||||
@click="showFullscreenImageDialog(worldDialog.ref.imageUrl)"
|
@click="showFullscreenImageDialog(worldDialog.ref.imageUrl)"
|
||||||
loading="lazy" />
|
loading="lazy" />
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 5px">
|
<div style="margin-top: 5px">
|
||||||
<span
|
<span
|
||||||
class="x-link x-grey"
|
class="cursor-pointer x-grey"
|
||||||
style="font-family: monospace"
|
style="font-family: monospace"
|
||||||
@click="showUserDialog(worldDialog.ref.authorId)"
|
@click="showUserDialog(worldDialog.ref.authorId)"
|
||||||
v-text="worldDialog.ref.authorName" />
|
v-text="worldDialog.ref.authorName" />
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
<Badge
|
<Badge
|
||||||
v-if="worldDialog.inCache"
|
v-if="worldDialog.inCache"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
style="margin-right: 5px; margin-top: 5px"
|
style="margin-right: 5px; margin-top: 5px"
|
||||||
@click="openFolderGeneric(worldDialog.cachePath)">
|
@click="openFolderGeneric(worldDialog.cachePath)">
|
||||||
<span v-text="worldDialog.cacheSize" />
|
<span v-text="worldDialog.cacheSize" />
|
||||||
|
|||||||
@@ -348,7 +348,8 @@
|
|||||||
"stop_fetching": "Stop fetching"
|
"stop_fetching": "Stop fetching"
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"no_friends_to_process": "You have no friends to process"
|
"no_friends_to_process": "You have no friends to process",
|
||||||
|
"loading_cache": "Loading cached mutual friends from database"
|
||||||
},
|
},
|
||||||
"progress": {
|
"progress": {
|
||||||
"friends_processed": "Friends processed",
|
"friends_processed": "Friends processed",
|
||||||
|
|||||||
@@ -215,7 +215,11 @@
|
|||||||
const isOptOut = computed(() => Boolean(currentUser.value?.hasSharedConnectionsOptOut));
|
const isOptOut = computed(() => Boolean(currentUser.value?.hasSharedConnectionsOptOut));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const graphReady = computed(() => Array.isArray(graphPayload.value?.nodes) && graphPayload.value.nodes.length > 0);
|
const graphReady = computed(() => Array.isArray(graphPayload.value?.nodes) && graphPayload.value.nodes.length > 0);
|
||||||
const fetchButtonDisabled = computed(() => isFetching.value || isOptOut.value || totalFriends.value === 0);
|
const isLoadingSnapshot = ref(false);
|
||||||
|
const loadingToastId = ref(null);
|
||||||
|
const fetchButtonDisabled = computed(
|
||||||
|
() => isFetching.value || isOptOut.value || totalFriends.value === 0 || isLoadingSnapshot.value
|
||||||
|
);
|
||||||
const fetchButtonLabel = computed(() =>
|
const fetchButtonLabel = computed(() =>
|
||||||
hasFetched.value
|
hasFetched.value
|
||||||
? t('view.charts.mutual_friend.actions.fetch_again')
|
? t('view.charts.mutual_friend.actions.fetch_again')
|
||||||
@@ -361,9 +365,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadGraphFromDatabase() {
|
async function loadGraphFromDatabase() {
|
||||||
if (hasFetched.value || isFetching.value) {
|
if (hasFetched.value || isFetching.value || isLoadingSnapshot.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
isLoadingSnapshot.value = true;
|
||||||
|
loadingToastId.value = toast.loading(t('view.charts.mutual_friend.status.loading_cache'));
|
||||||
try {
|
try {
|
||||||
const snapshot = await database.getMutualGraphSnapshot();
|
const snapshot = await database.getMutualGraphSnapshot();
|
||||||
if (!snapshot || snapshot.size === 0) {
|
if (!snapshot || snapshot.size === 0) {
|
||||||
@@ -399,6 +405,12 @@
|
|||||||
status.needsRefetch = false;
|
status.needsRefetch = false;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[MutualNetworkGraph] Failed to load cached mutual graph', err);
|
console.error('[MutualNetworkGraph] Failed to load cached mutual graph', err);
|
||||||
|
} finally {
|
||||||
|
isLoadingSnapshot.value = false;
|
||||||
|
if (loadingToastId.value !== null && loadingToastId.value !== undefined) {
|
||||||
|
toast.dismiss(loadingToastId.value);
|
||||||
|
loadingToastId.value = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,57 +129,30 @@
|
|||||||
<MoreHorizontal />
|
<MoreHorizontal />
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent side="right" class="w-55 p-1 rounded-lg">
|
<DropdownMenuContent side="right" class="w-55">
|
||||||
<div class="favorites-group-menu">
|
<DropdownMenuItem @click="handleRemoteRename(group)">
|
||||||
<button
|
<span>{{ t('view.favorite.rename_tooltip') }}</span>
|
||||||
type="button"
|
</DropdownMenuItem>
|
||||||
class="favorites-group-menu__item"
|
<DropdownMenuSub>
|
||||||
@click="handleRemoteRename(group)">
|
<DropdownMenuSubTrigger>
|
||||||
<span>{{ t('view.favorite.rename_tooltip') }}</span>
|
<span>{{ t('view.favorite.visibility_tooltip') }}</span>
|
||||||
</button>
|
</DropdownMenuSubTrigger>
|
||||||
<DropdownMenuSub>
|
<DropdownMenuPortal>
|
||||||
<DropdownMenuSubTrigger
|
<DropdownMenuSubContent side="right" align="start" class="w-45">
|
||||||
class="favorites-group-menu__item favorites-group-menu__item--submenu">
|
<DropdownMenuCheckboxItem
|
||||||
<span>{{ t('view.favorite.visibility_tooltip') }}</span>
|
v-for="visibility in avatarGroupVisibilityOptions"
|
||||||
</DropdownMenuSubTrigger>
|
:key="visibility"
|
||||||
<DropdownMenuPortal>
|
:model-value="group.visibility === visibility"
|
||||||
<DropdownMenuSubContent
|
indicator-position="right"
|
||||||
side="right"
|
@select="handleVisibilitySelection(group, visibility)">
|
||||||
align="start"
|
<span>{{ formatVisibility(visibility) }}</span>
|
||||||
class="w-45 p-1 rounded-lg">
|
</DropdownMenuCheckboxItem>
|
||||||
<div class="group-visibility-menu">
|
</DropdownMenuSubContent>
|
||||||
<button
|
</DropdownMenuPortal>
|
||||||
v-for="visibility in avatarGroupVisibilityOptions"
|
</DropdownMenuSub>
|
||||||
:key="visibility"
|
<DropdownMenuItem variant="destructive" @click="handleRemoteClear(group)">
|
||||||
type="button"
|
<span>{{ t('view.favorite.clear') }}</span>
|
||||||
:class="[
|
</DropdownMenuItem>
|
||||||
'group-visibility-menu__item',
|
|
||||||
{
|
|
||||||
'is-active':
|
|
||||||
group.visibility === visibility
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
@click="
|
|
||||||
handleVisibilitySelection(group, visibility)
|
|
||||||
">
|
|
||||||
<span>{{ formatVisibility(visibility) }}</span>
|
|
||||||
<span
|
|
||||||
v-if="group.visibility === visibility"
|
|
||||||
class="group-visibility-menu__check">
|
|
||||||
<Check class="h-3 w-3" />
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</DropdownMenuSubContent>
|
|
||||||
</DropdownMenuPortal>
|
|
||||||
</DropdownMenuSub>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="favorites-group-menu__item favorites-group-menu__item--danger"
|
|
||||||
@click="handleRemoteClear(group)">
|
|
||||||
<span>{{ t('view.favorite.clear') }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
@@ -251,27 +224,16 @@
|
|||||||
><Ellipsis
|
><Ellipsis
|
||||||
/></Button>
|
/></Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent side="right" class="w-50 p-1 rounded-lg">
|
<DropdownMenuContent side="right" class="w-50">
|
||||||
<div class="favorites-group-menu">
|
<DropdownMenuItem @click="handleLocalRename(group)">
|
||||||
<button
|
<span>{{ t('view.favorite.rename_tooltip') }}</span>
|
||||||
type="button"
|
</DropdownMenuItem>
|
||||||
class="favorites-group-menu__item"
|
<DropdownMenuItem @click="handleCheckInvalidAvatars(group)">
|
||||||
@click="handleLocalRename(group)">
|
<span>{{ t('view.favorite.avatars.check_invalid') }}</span>
|
||||||
<span>{{ t('view.favorite.rename_tooltip') }}</span>
|
</DropdownMenuItem>
|
||||||
</button>
|
<DropdownMenuItem variant="destructive" @click="handleLocalDelete(group)">
|
||||||
<button
|
<span>{{ t('view.favorite.delete_tooltip') }}</span>
|
||||||
type="button"
|
</DropdownMenuItem>
|
||||||
class="favorites-group-menu__item"
|
|
||||||
@click="handleCheckInvalidAvatars(group)">
|
|
||||||
<span>{{ t('view.favorite.avatars.check_invalid') }}</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="favorites-group-menu__item favorites-group-menu__item--danger"
|
|
||||||
@click="handleLocalDelete(group)">
|
|
||||||
<span>{{ t('view.favorite.delete_tooltip') }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
@@ -317,15 +279,10 @@
|
|||||||
><Ellipsis
|
><Ellipsis
|
||||||
/></Button>
|
/></Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent side="right" class="w-45 p-1 rounded-lg">
|
<DropdownMenuContent side="right" class="w-45">
|
||||||
<div class="favorites-group-menu">
|
<DropdownMenuItem variant="destructive" @click="handleHistoryClear">
|
||||||
<button
|
<span>{{ t('view.favorite.clear_tooltip') }}</span>
|
||||||
type="button"
|
</DropdownMenuItem>
|
||||||
class="favorites-group-menu__item favorites-group-menu__item--danger"
|
|
||||||
@click="handleHistoryClear">
|
|
||||||
<span>{{ t('view.favorite.clear_tooltip') }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
@@ -537,6 +494,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
|
DropdownMenuCheckboxItem,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuPortal,
|
DropdownMenuPortal,
|
||||||
@@ -1736,63 +1694,6 @@
|
|||||||
padding: 12px 0;
|
padding: 12px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-group-menu {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-group-menu__item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 6px 12px;
|
|
||||||
font-size: 13px;
|
|
||||||
cursor: pointer;
|
|
||||||
color: inherit;
|
|
||||||
transition: background-color 0.15s ease;
|
|
||||||
min-height: 32px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-group-menu__item--submenu {
|
|
||||||
padding-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-group-menu__arrow {
|
|
||||||
margin-left: auto;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-visibility-menu {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-visibility-menu__item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
padding: 6px 10px;
|
|
||||||
border-radius: 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
color: inherit;
|
|
||||||
font-size: 13px;
|
|
||||||
transition: background-color 0.15s ease;
|
|
||||||
min-height: 32px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-visibility-menu__check {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-content {
|
.favorites-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -129,57 +129,35 @@
|
|||||||
<MoreHorizontal />
|
<MoreHorizontal />
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent side="right" class="w-55 p-1 rounded-lg">
|
<DropdownMenuContent side="right" class="w-55">
|
||||||
<div class="favorites-group-menu">
|
<DropdownMenuItem @click="handleRemoteRename(group)">
|
||||||
<button
|
<span>{{ t('view.favorite.rename_tooltip') }}</span>
|
||||||
type="button"
|
</DropdownMenuItem>
|
||||||
class="favorites-group-menu__item"
|
<DropdownMenuSub>
|
||||||
@click="handleRemoteRename(group)">
|
<DropdownMenuSubTrigger>
|
||||||
<span>{{ t('view.favorite.rename_tooltip') }}</span>
|
<span>{{ t('view.favorite.visibility_tooltip') }}</span>
|
||||||
</button>
|
</DropdownMenuSubTrigger>
|
||||||
<DropdownMenuSub>
|
<DropdownMenuPortal>
|
||||||
<DropdownMenuSubTrigger
|
<DropdownMenuSubContent
|
||||||
class="favorites-group-menu__item favorites-group-menu__item--submenu">
|
side="right"
|
||||||
<span>{{ t('view.favorite.visibility_tooltip') }}</span>
|
align="start"
|
||||||
</DropdownMenuSubTrigger>
|
class="w-[180px]">
|
||||||
<DropdownMenuPortal>
|
<DropdownMenuCheckboxItem
|
||||||
<DropdownMenuSubContent
|
v-for="visibility in friendGroupVisibilityOptions"
|
||||||
side="right"
|
:key="visibility"
|
||||||
align="start"
|
:model-value="group.visibility === visibility"
|
||||||
class="w-[180px] p-1 rounded-lg">
|
indicator-position="right"
|
||||||
<div class="group-visibility-menu">
|
@select="handleVisibilitySelection(group, visibility)">
|
||||||
<button
|
<span>{{ formatVisibility(visibility) }}</span>
|
||||||
v-for="visibility in friendGroupVisibilityOptions"
|
</DropdownMenuCheckboxItem>
|
||||||
:key="visibility"
|
</DropdownMenuSubContent>
|
||||||
type="button"
|
</DropdownMenuPortal>
|
||||||
:class="[
|
</DropdownMenuSub>
|
||||||
'group-visibility-menu__item',
|
<DropdownMenuItem
|
||||||
{
|
variant="destructive"
|
||||||
'is-active':
|
@click="handleRemoteClear(group)">
|
||||||
group.visibility === visibility
|
<span>{{ t('view.favorite.clear') }}</span>
|
||||||
}
|
</DropdownMenuItem>
|
||||||
]"
|
|
||||||
@click="
|
|
||||||
handleVisibilitySelection(group, visibility)
|
|
||||||
">
|
|
||||||
<span>{{ formatVisibility(visibility) }}</span>
|
|
||||||
<span
|
|
||||||
v-if="group.visibility === visibility"
|
|
||||||
class="group-visibility-menu__check">
|
|
||||||
<Check class="h-3 w-3" />
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</DropdownMenuSubContent>
|
|
||||||
</DropdownMenuPortal>
|
|
||||||
</DropdownMenuSub>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="favorites-group-menu__item favorites-group-menu__item--danger"
|
|
||||||
@click="handleRemoteClear(group)">
|
|
||||||
<span>{{ t('view.favorite.clear') }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
@@ -320,6 +298,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
|
DropdownMenuCheckboxItem,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuPortal,
|
DropdownMenuPortal,
|
||||||
@@ -993,73 +972,6 @@
|
|||||||
padding: 12px 0;
|
padding: 12px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-group-menu {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-group-menu__item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 6px 12px;
|
|
||||||
font-size: 13px;
|
|
||||||
cursor: pointer;
|
|
||||||
color: inherit;
|
|
||||||
transition: background-color 0.15s ease;
|
|
||||||
min-height: 32px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-group-menu__item:hover {
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-group-menu__item--danger {
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-group-menu__item--submenu {
|
|
||||||
padding-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-group-menu__arrow {
|
|
||||||
margin-left: auto;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-visibility-menu {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-visibility-menu__item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
padding: 6px 10px;
|
|
||||||
border-radius: 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
color: inherit;
|
|
||||||
font-size: 13px;
|
|
||||||
transition: background-color 0.15s ease;
|
|
||||||
min-height: 32px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-visibility-menu__item:hover,
|
|
||||||
.group-visibility-menu__item.is-active {
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-visibility-menu__check {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-content {
|
.favorites-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -129,54 +129,30 @@
|
|||||||
<MoreHorizontal />
|
<MoreHorizontal />
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent side="right" class="w-50 p-1 rounded-lg">
|
<DropdownMenuContent side="right" class="w-50">
|
||||||
<div class="favorites-group-menu">
|
<DropdownMenuItem @click="handleRemoteRename(group)">
|
||||||
<button
|
<span>{{ t('view.favorite.rename_tooltip') }}</span>
|
||||||
type="button"
|
</DropdownMenuItem>
|
||||||
class="favorites-group-menu__item"
|
<DropdownMenuSub>
|
||||||
@click="handleRemoteRename(group)">
|
<DropdownMenuSubTrigger>
|
||||||
<span>{{ t('view.favorite.rename_tooltip') }}</span>
|
<span>{{ t('view.favorite.visibility_tooltip') }}</span>
|
||||||
</button>
|
</DropdownMenuSubTrigger>
|
||||||
<DropdownMenuSub>
|
<DropdownMenuPortal>
|
||||||
<DropdownMenuSubTrigger
|
<DropdownMenuSubContent side="right" align="start" class="w-[200px]">
|
||||||
class="favorites-group-menu__item favorites-group-menu__item--submenu">
|
<DropdownMenuCheckboxItem
|
||||||
<span>{{ t('view.favorite.visibility_tooltip') }}</span>
|
v-for="visibility in worldGroupVisibilityOptions"
|
||||||
</DropdownMenuSubTrigger>
|
:key="visibility"
|
||||||
<DropdownMenuPortal>
|
:model-value="group.visibility === visibility"
|
||||||
<DropdownMenuSubContent
|
indicator-position="right"
|
||||||
side="right"
|
@select="handleVisibilitySelection(group, visibility)">
|
||||||
align="start"
|
<span>{{ formatVisibility(visibility) }}</span>
|
||||||
class="w-[200px] p-1 rounded-lg">
|
</DropdownMenuCheckboxItem>
|
||||||
<div class="group-visibility-menu">
|
</DropdownMenuSubContent>
|
||||||
<button
|
</DropdownMenuPortal>
|
||||||
v-for="visibility in worldGroupVisibilityOptions"
|
</DropdownMenuSub>
|
||||||
:key="visibility"
|
<DropdownMenuItem variant="destructive" @click="handleRemoteClear(group)">
|
||||||
type="button"
|
<span>{{ t('view.favorite.clear') }}</span>
|
||||||
class="group-visibility-menu__item"
|
</DropdownMenuItem>
|
||||||
:class="{
|
|
||||||
'is-active': group.visibility === visibility
|
|
||||||
}"
|
|
||||||
@click="
|
|
||||||
handleVisibilitySelection(group, visibility)
|
|
||||||
">
|
|
||||||
<span>{{ formatVisibility(visibility) }}</span>
|
|
||||||
<span
|
|
||||||
v-if="group.visibility === visibility"
|
|
||||||
class="group-visibility-menu__check"
|
|
||||||
>✔</span
|
|
||||||
>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</DropdownMenuSubContent>
|
|
||||||
</DropdownMenuPortal>
|
|
||||||
</DropdownMenuSub>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="favorites-group-menu__item favorites-group-menu__item--danger"
|
|
||||||
@click="handleRemoteClear(group)">
|
|
||||||
<span>{{ t('view.favorite.clear') }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
@@ -247,21 +223,13 @@
|
|||||||
><Ellipsis
|
><Ellipsis
|
||||||
/></Button>
|
/></Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent side="right" class="w-50 p-1 rounded-lg">
|
<DropdownMenuContent side="right" class="w-50">
|
||||||
<div class="favorites-group-menu">
|
<DropdownMenuItem @click="handleLocalRename(group)">
|
||||||
<button
|
<span>{{ t('view.favorite.rename_tooltip') }}</span>
|
||||||
type="button"
|
</DropdownMenuItem>
|
||||||
class="favorites-group-menu__item"
|
<DropdownMenuItem variant="destructive" @click="handleLocalDelete(group)">
|
||||||
@click="handleLocalRename(group)">
|
<span>{{ t('view.favorite.delete_tooltip') }}</span>
|
||||||
<span>{{ t('view.favorite.rename_tooltip') }}</span>
|
</DropdownMenuItem>
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="favorites-group-menu__item favorites-group-menu__item--danger"
|
|
||||||
@click="handleLocalDelete(group)">
|
|
||||||
<span>{{ t('view.favorite.delete_tooltip') }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
@@ -448,6 +416,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
|
DropdownMenuCheckboxItem,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuPortal,
|
DropdownMenuPortal,
|
||||||
@@ -1496,72 +1465,6 @@
|
|||||||
padding: 12px 0;
|
padding: 12px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-group-menu {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-group-menu__item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 6px 12px;
|
|
||||||
font-size: 13px;
|
|
||||||
cursor: pointer;
|
|
||||||
color: inherit;
|
|
||||||
transition: background-color 0.15s ease;
|
|
||||||
min-height: 32px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
|
||||||
.favorites-group-menu__item:hover {
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-group-menu__item--danger {
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-group-menu__item--submenu {
|
|
||||||
padding-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-group-menu__arrow {
|
|
||||||
margin-left: auto;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-visibility-menu {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-visibility-menu__item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
padding: 6px 10px;
|
|
||||||
border-radius: 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
color: inherit;
|
|
||||||
font-size: 13px;
|
|
||||||
transition: background-color 0.15s ease;
|
|
||||||
min-height: 32px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-visibility-menu__item:hover,
|
|
||||||
.group-visibility-menu__item.is-active {
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-visibility-menu__check {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-content {
|
.favorites-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const createColumns = ({ onShowAvatar, onShowUser, onDelete, onShowFullsc
|
|||||||
const original = row.original;
|
const original = row.original;
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class=" cursor-pointer"
|
||||||
title={original?.name}
|
title={original?.name}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -63,7 +63,7 @@ export const createColumns = ({ onShowAvatar, onShowUser, onDelete, onShowFullsc
|
|||||||
const original = row.original;
|
const original = row.original;
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class=" cursor-pointer"
|
||||||
title={original?.authorName}
|
title={original?.authorName}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const createColumns = ({ userImage, userImageFull, onShowFullscreenImage,
|
|||||||
const original = row.original;
|
const original = row.original;
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
title={original?.displayName}
|
title={original?.displayName}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const createColumns = ({ onShowWorld, onShowUser, onDelete, onShowFullscr
|
|||||||
const original = row.original;
|
const original = row.original;
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
title={original?.name}
|
title={original?.name}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -63,7 +63,7 @@ export const createColumns = ({ onShowWorld, onShowUser, onDelete, onShowFullscr
|
|||||||
const original = row.original;
|
const original = row.original;
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
title={original?.authorName}
|
title={original?.authorName}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ const expandedRow = ({ row }) => {
|
|||||||
src={
|
src={
|
||||||
original.previousCurrentAvatarThumbnailImageUrl
|
original.previousCurrentAvatarThumbnailImageUrl
|
||||||
}
|
}
|
||||||
class="x-link h-30 w-40 rounded pointer"
|
class="cursor-pointer h-30 w-40 rounded pointer"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
showFullscreenImageDialog(
|
showFullscreenImageDialog(
|
||||||
@@ -125,7 +125,7 @@ const expandedRow = ({ row }) => {
|
|||||||
src={
|
src={
|
||||||
original.currentAvatarThumbnailImageUrl
|
original.currentAvatarThumbnailImageUrl
|
||||||
}
|
}
|
||||||
class="x-link h-30 w-40 rounded pointer"
|
class="cursor-pointer h-30 w-40 rounded pointer"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
showFullscreenImageDialog(
|
showFullscreenImageDialog(
|
||||||
@@ -280,7 +280,7 @@ export const columns = [
|
|||||||
const original = row.original;
|
const original = row.original;
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
class="x-link pr-2.5 cursor-pointer"
|
class="cursor-pointer pr-2.5 cursor-pointer"
|
||||||
onClick={() => showUserDialog(original.userId)}
|
onClick={() => showUserDialog(original.userId)}
|
||||||
>
|
>
|
||||||
{original.displayName}
|
{original.displayName}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export const createColumns = ({ onDelete, onDeletePrompt }) => {
|
|||||||
const displayName =
|
const displayName =
|
||||||
original.displayName || original.userId || '';
|
original.displayName || original.userId || '';
|
||||||
return (
|
return (
|
||||||
<span class="block w-full whitespace-normal break-words">
|
<span class="block w-full whitespace-normal wrap-break-word cursor-pointer">
|
||||||
{original.type === 'DisplayName' ? (
|
{original.type === 'DisplayName' ? (
|
||||||
<span class="mr-1">
|
<span class="mr-1">
|
||||||
{original.previousDisplayName}
|
{original.previousDisplayName}
|
||||||
@@ -97,7 +97,7 @@ export const createColumns = ({ onDelete, onDeletePrompt }) => {
|
|||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
<span
|
<span
|
||||||
class="x-link pr-2.5"
|
class="cursor-pointer pr-2.5"
|
||||||
onClick={() => showUserDialog(original.userId)}
|
onClick={() => showUserDialog(original.userId)}
|
||||||
>
|
>
|
||||||
{displayName}
|
{displayName}
|
||||||
|
|||||||
@@ -10,49 +10,65 @@
|
|||||||
</Tabs>
|
</Tabs>
|
||||||
<div class="friend-view__actions">
|
<div class="friend-view__actions">
|
||||||
<InputGroupSearch v-model="searchTerm" class="friend-view__search" placeholder="Search Friend" />
|
<InputGroupSearch v-model="searchTerm" class="friend-view__search" placeholder="Search Friend" />
|
||||||
<Popover>
|
<TooltipWrapper :content="t('view.charts.instance_activity.settings.header')" side="top">
|
||||||
<PopoverTrigger asChild>
|
<div>
|
||||||
<div>
|
<Popover>
|
||||||
<TooltipWrapper :content="t('view.charts.instance_activity.settings.header')" side="top">
|
<PopoverTrigger asChild>
|
||||||
<Button class="rounded-full mr-2" size="icon" variant="outline">
|
<Button class="rounded-full mr-2" size="icon" variant="outline">
|
||||||
<Settings />
|
<Settings />
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipWrapper>
|
</PopoverTrigger>
|
||||||
</div>
|
<PopoverContent side="bottom" class="w-87.5">
|
||||||
</PopoverTrigger>
|
<div class="friend-view__settings">
|
||||||
<PopoverContent side="bottom" class="w-87.5">
|
<Field orientation="horizontal" class="friend-view__settings-row">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center">
|
<FieldLabel class="friend-view__settings-label">{{
|
||||||
<span class="friend-view__settings-label">{{
|
t('view.friends_locations.separate_same_instance_friends')
|
||||||
t('view.friends_locations.separate_same_instance_friends')
|
}}</FieldLabel>
|
||||||
}}</span>
|
<FieldContent>
|
||||||
<Switch v-model="showSameInstance" />
|
<Switch v-model="showSameInstance" />
|
||||||
</div>
|
</FieldContent>
|
||||||
<div class="friend-view__settings-row">
|
</Field>
|
||||||
<span class="friend-view__settings-label">{{ t('view.friends_locations.scale') }}</span>
|
<Field orientation="horizontal" class="friend-view__settings-row">
|
||||||
<div class="friend-view__scale-control">
|
<FieldLabel class="friend-view__settings-label">
|
||||||
<span class="friend-view__scale-value">{{ cardScalePercentLabel }} </span>
|
{{ t('view.friends_locations.scale') }}
|
||||||
<Slider
|
</FieldLabel>
|
||||||
v-model="cardScaleValue"
|
<FieldContent>
|
||||||
class="friend-view__slider"
|
<div class="friend-view__scale-control">
|
||||||
:min="0.5"
|
<span class="friend-view__scale-value"
|
||||||
:max="1.0"
|
>{{ cardScalePercentLabel }} </span
|
||||||
:step="0.01" />
|
>
|
||||||
</div>
|
<Slider
|
||||||
</div>
|
v-model="cardScaleValue"
|
||||||
<div class="friend-view__settings-row">
|
class="friend-view__slider"
|
||||||
<span class="friend-view__settings-label">{{ t('view.friends_locations.spacing') }}</span>
|
:min="0.5"
|
||||||
<div class="friend-view__scale-control">
|
:max="1.0"
|
||||||
<span class="friend-view__scale-value">{{ cardSpacingPercentLabel }} </span>
|
:step="0.01" />
|
||||||
<Slider
|
</div>
|
||||||
v-model="cardSpacingValue"
|
</FieldContent>
|
||||||
class="friend-view__slider"
|
</Field>
|
||||||
:min="0.25"
|
<Field orientation="horizontal" class="friend-view__settings-row">
|
||||||
:max="1.0"
|
<FieldLabel class="friend-view__settings-label">
|
||||||
:step="0.05" />
|
{{ t('view.friends_locations.spacing') }}
|
||||||
</div>
|
</FieldLabel>
|
||||||
</div>
|
<FieldContent>
|
||||||
</PopoverContent>
|
<div class="friend-view__scale-control">
|
||||||
</Popover>
|
<span class="friend-view__scale-value"
|
||||||
|
>{{ cardSpacingPercentLabel }} </span
|
||||||
|
>
|
||||||
|
<Slider
|
||||||
|
v-model="cardSpacingValue"
|
||||||
|
class="friend-view__slider"
|
||||||
|
:min="0.25"
|
||||||
|
:max="1.0"
|
||||||
|
:step="0.05" />
|
||||||
|
</div>
|
||||||
|
</FieldContent>
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
</TooltipWrapper>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="friend-view__toolbar friend-view__toolbar--loading">
|
<div v-else class="friend-view__toolbar friend-view__toolbar--loading">
|
||||||
@@ -64,7 +80,7 @@
|
|||||||
<template v-if="row.type === 'header'">
|
<template v-if="row.type === 'header'">
|
||||||
<header class="friend-view__instance-header">
|
<header class="friend-view__instance-header">
|
||||||
<Location class="text-xs" :location="row.instanceId" style="display: inline" />
|
<Location class="text-xs" :location="row.instanceId" style="display: inline" />
|
||||||
<span class="friend-view__instance-count">{{ row.count }}</span>
|
<span class="friend-view__instance-count">({{ row.count }})</span>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -95,6 +111,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, nextTick, onBeforeMount, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue';
|
import { computed, nextTick, onBeforeMount, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue';
|
||||||
|
import { Field, FieldContent, FieldLabel } from '@/components/ui/field';
|
||||||
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
import { Loader2, Settings } from 'lucide-vue-next';
|
import { Loader2, Settings } from 'lucide-vue-next';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
@@ -714,6 +731,11 @@
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.friend-view__settings {
|
||||||
|
display: grid;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.friend-view__loading-text {
|
.friend-view__loading-text {
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
}
|
}
|
||||||
@@ -828,7 +850,6 @@
|
|||||||
.friend-view__instance-header {
|
.friend-view__instance-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
|
||||||
padding: 4px 2px;
|
padding: 4px 2px;
|
||||||
margin: 5px 10px;
|
margin: 5px 10px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export const createColumns = ({ getCreatedAt, onDelete, onDeletePrompt }) => {
|
|||||||
return (
|
return (
|
||||||
<Badge variant="outline" class="text-muted-foreground">
|
<Badge variant="outline" class="text-muted-foreground">
|
||||||
<span
|
<span
|
||||||
class={isLink ? 'x-link' : undefined}
|
class={isLink ? 'cursor-pointer' : undefined}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
isLink && showWorldDialog(original.location)
|
isLink && showWorldDialog(original.location)
|
||||||
}
|
}
|
||||||
@@ -111,10 +111,10 @@ export const createColumns = ({ getCreatedAt, onDelete, onDeletePrompt }) => {
|
|||||||
const isFriend = original.isFriend;
|
const isFriend = original.isFriend;
|
||||||
const isFavorite = original.isFavorite;
|
const isFavorite = original.isFavorite;
|
||||||
return (
|
return (
|
||||||
<span>
|
<span class="cursor-pointer">
|
||||||
{original.displayName ? (
|
{original.displayName ? (
|
||||||
<span
|
<span
|
||||||
class="x-link table-user mr-1"
|
class="cursor-pointer table-user mr-1"
|
||||||
onClick={() => lookupUser(original)}
|
onClick={() => lookupUser(original)}
|
||||||
>
|
>
|
||||||
{original.displayName}
|
{original.displayName}
|
||||||
@@ -183,13 +183,13 @@ export const createColumns = ({ getCreatedAt, onDelete, onDeletePrompt }) => {
|
|||||||
original.videoId !== 'PopcornPalace';
|
original.videoId !== 'PopcornPalace';
|
||||||
const label = original.videoName || original.videoUrl;
|
const label = original.videoName || original.videoUrl;
|
||||||
return (
|
return (
|
||||||
<span class="block w-full min-w-0 truncate">
|
<span class="block w-full min-w-0 truncate cursor-pointer">
|
||||||
{original.videoId ? (
|
{original.videoId ? (
|
||||||
<span class="mr-1.5">{original.videoId}:</span>
|
<span class="mr-1.5">{original.videoId}:</span>
|
||||||
) : null}
|
) : null}
|
||||||
{showLink ? (
|
{showLink ? (
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
openExternalLink(original.videoUrl)
|
openExternalLink(original.videoUrl)
|
||||||
}
|
}
|
||||||
@@ -208,9 +208,9 @@ export const createColumns = ({ getCreatedAt, onDelete, onDeletePrompt }) => {
|
|||||||
original.type === 'StringLoad'
|
original.type === 'StringLoad'
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<span class="block w-full min-w-0 truncate">
|
<span class="block w-full min-w-0 truncate cursor-pointer">
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
openExternalLink(original.resourceUrl)
|
openExternalLink(original.resourceUrl)
|
||||||
}
|
}
|
||||||
@@ -230,7 +230,7 @@ export const createColumns = ({ getCreatedAt, onDelete, onDeletePrompt }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span class="x-link block w-full min-w-0 truncate">
|
<span class="block w-full min-w-0 truncate">
|
||||||
{original.data}
|
{original.data}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -18,7 +18,10 @@
|
|||||||
<ResizablePanelGroup
|
<ResizablePanelGroup
|
||||||
ref="panelGroupRef"
|
ref="panelGroupRef"
|
||||||
direction="horizontal"
|
direction="horizontal"
|
||||||
class="group/main-layout flex-1 h-full min-w-0"
|
:class="[
|
||||||
|
'group/main-layout flex-1 h-full min-w-0',
|
||||||
|
{ 'aside-collapsed': isAsideCollapsedStatic }
|
||||||
|
]"
|
||||||
@layout="handleLayout">
|
@layout="handleLayout">
|
||||||
<template #default="{ layout }">
|
<template #default="{ layout }">
|
||||||
<ResizablePanel :default-size="mainDefaultSize" :order="1">
|
<ResizablePanel :default-size="mainDefaultSize" :order="1">
|
||||||
@@ -126,7 +129,7 @@
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const appearanceSettingsStore = useAppearanceSettingsStore();
|
const appearanceSettingsStore = useAppearanceSettingsStore();
|
||||||
const { navWidth, isNavCollapsed } = storeToRefs(appearanceSettingsStore);
|
const { navWidth, isNavCollapsed, asideWidth } = storeToRefs(appearanceSettingsStore);
|
||||||
|
|
||||||
const sidebarOpen = computed(() => !isNavCollapsed.value);
|
const sidebarOpen = computed(() => !isNavCollapsed.value);
|
||||||
|
|
||||||
@@ -184,6 +187,10 @@
|
|||||||
isSideBarTabShow
|
isSideBarTabShow
|
||||||
} = useAuthenticatedLayoutResizable();
|
} = useAuthenticatedLayoutResizable();
|
||||||
|
|
||||||
|
const isAsideCollapsedStatic = computed(
|
||||||
|
() => !isSideBarTabShow.value || asideWidth.value === 0
|
||||||
|
);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => watchState.isLoggedIn,
|
() => watchState.isLoggedIn,
|
||||||
(isLoggedIn) => {
|
(isLoggedIn) => {
|
||||||
|
|||||||
@@ -158,14 +158,17 @@
|
|||||||
<div class="x-legal-notice-container">
|
<div class="x-legal-notice-container">
|
||||||
<div style="text-align: center; font-size: 12px">
|
<div style="text-align: center; font-size: 12px">
|
||||||
<p>
|
<p>
|
||||||
<a class="x-link" @click="openExternalLink('https://vrchat.com/home/password')">{{
|
<a class="cursor-pointer" @click="openExternalLink('https://vrchat.com/home/password')">{{
|
||||||
t('view.login.forgotPassword')
|
t('view.login.forgotPassword')
|
||||||
}}</a>
|
}}</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
© 2019-2026
|
© 2019-2026
|
||||||
<a class="x-link" @click="openExternalLink('https://github.com/pypy-vrc')">pypy</a> &
|
<a class="cursor-pointer" @click="openExternalLink('https://github.com/pypy-vrc')">pypy</a>
|
||||||
<a class="x-link" @click="openExternalLink('https://github.com/Natsumi-sama')">Natsumi</a>
|
&
|
||||||
|
<a class="cursor-pointer" @click="openExternalLink('https://github.com/Natsumi-sama')"
|
||||||
|
>Natsumi</a
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
<p>{{ t('view.settings.general.legal_notice.info') }}</p>
|
<p>{{ t('view.settings.general.legal_notice.info') }}</p>
|
||||||
<p>{{ t('view.settings.general.legal_notice.disclaimer1') }}</p>
|
<p>{{ t('view.settings.general.legal_notice.disclaimer1') }}</p>
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export const createColumns = ({ onDelete, onDeletePrompt }) => {
|
|||||||
const original = row.original;
|
const original = row.original;
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
class="x-link block w-full min-w-0 truncate pr-2.5"
|
class="cursor-pointer block w-full min-w-0 truncate pr-2.5 cursor-pointer"
|
||||||
onClick={() => showUserDialog(original.sourceUserId)}
|
onClick={() => showUserDialog(original.sourceUserId)}
|
||||||
>
|
>
|
||||||
{original.sourceDisplayName}
|
{original.sourceDisplayName}
|
||||||
@@ -107,7 +107,7 @@ export const createColumns = ({ onDelete, onDeletePrompt }) => {
|
|||||||
const original = row.original;
|
const original = row.original;
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
class="x-link block w-full whitespace-normal break-words pr-2.5"
|
class="cursor-pointer block w-full whitespace-normal wrap-break-word pr-2.5 cursor-pointer"
|
||||||
onClick={() => showUserDialog(original.targetUserId)}
|
onClick={() => showUserDialog(original.targetUserId)}
|
||||||
>
|
>
|
||||||
{original.targetDisplayName}
|
{original.targetDisplayName}
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ export const createColumns = ({
|
|||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
showWorldDialog(
|
showWorldDialog(
|
||||||
original.location
|
original.location
|
||||||
@@ -200,7 +200,7 @@ export const createColumns = ({
|
|||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
openNotificationLink(
|
openNotificationLink(
|
||||||
original.link
|
original.link
|
||||||
@@ -242,7 +242,7 @@ export const createColumns = ({
|
|||||||
return (
|
return (
|
||||||
<span class="table-user-text block w-full min-w-0 truncate">
|
<span class="table-user-text block w-full min-w-0 truncate">
|
||||||
<span
|
<span
|
||||||
class="x-link block w-full min-w-0 truncate"
|
class="cursor-pointer block w-full min-w-0 truncate"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
showUserDialog(original.senderUserId)
|
showUserDialog(original.senderUserId)
|
||||||
}
|
}
|
||||||
@@ -257,7 +257,7 @@ export const createColumns = ({
|
|||||||
return (
|
return (
|
||||||
<span class="table-user-text block w-full min-w-0 truncate">
|
<span class="table-user-text block w-full min-w-0 truncate">
|
||||||
<span
|
<span
|
||||||
class="x-link block w-full min-w-0 truncate"
|
class="cursor-pointer block w-full min-w-0 truncate"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
openNotificationLink(original.link)
|
openNotificationLink(original.link)
|
||||||
}
|
}
|
||||||
@@ -306,7 +306,7 @@ export const createColumns = ({
|
|||||||
return (
|
return (
|
||||||
<span class="table-user-text block w-full min-w-0 truncate">
|
<span class="table-user-text block w-full min-w-0 truncate">
|
||||||
<span
|
<span
|
||||||
class="x-link block w-full min-w-0 truncate"
|
class="cursor-pointer block w-full min-w-0 truncate"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
showGroupDialog(original.senderUserId)
|
showGroupDialog(original.senderUserId)
|
||||||
}
|
}
|
||||||
@@ -332,7 +332,7 @@ export const createColumns = ({
|
|||||||
return (
|
return (
|
||||||
<span class="table-user-text block w-full min-w-0 truncate">
|
<span class="table-user-text block w-full min-w-0 truncate">
|
||||||
<span
|
<span
|
||||||
class="x-link block w-full min-w-0 truncate"
|
class="cursor-pointer block w-full min-w-0 truncate"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
openNotificationLink(original.link)
|
openNotificationLink(original.link)
|
||||||
}
|
}
|
||||||
@@ -347,7 +347,7 @@ export const createColumns = ({
|
|||||||
return (
|
return (
|
||||||
<span class="table-user-text block w-full min-w-0 truncate">
|
<span class="table-user-text block w-full min-w-0 truncate">
|
||||||
<span
|
<span
|
||||||
class="x-link block w-full min-w-0 truncate"
|
class="cursor-pointer block w-full min-w-0 truncate"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
openNotificationLink(original.link)
|
openNotificationLink(original.link)
|
||||||
}
|
}
|
||||||
@@ -400,7 +400,7 @@ export const createColumns = ({
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Emoji
|
<Emoji
|
||||||
class="x-link h-7.5 w-7.5 rounded object-cover"
|
class="cursor-pointer h-7.5 w-7.5 rounded object-cover"
|
||||||
onClick={() => showFullscreenImageDialog(imageUrl)}
|
onClick={() => showFullscreenImageDialog(imageUrl)}
|
||||||
imageUrl={imageUrl}
|
imageUrl={imageUrl}
|
||||||
size={30}
|
size={30}
|
||||||
@@ -411,7 +411,7 @@ export const createColumns = ({
|
|||||||
if (original.details?.imageUrl) {
|
if (original.details?.imageUrl) {
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
class="x-link h-7.5 w-7.5 rounded object-cover"
|
class="cursor-pointer h-7.5 w-7.5 rounded object-cover"
|
||||||
src={getSmallThumbnailUrl(
|
src={getSmallThumbnailUrl(
|
||||||
original.details.imageUrl
|
original.details.imageUrl
|
||||||
)}
|
)}
|
||||||
@@ -428,7 +428,7 @@ export const createColumns = ({
|
|||||||
if (original.imageUrl) {
|
if (original.imageUrl) {
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
class="x-link h-7.5 w-7.5 rounded object-cover"
|
class="cursor-pointer h-7.5 w-7.5 rounded object-cover"
|
||||||
src={getSmallThumbnailUrl(original.imageUrl)}
|
src={getSmallThumbnailUrl(original.imageUrl)}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
showFullscreenImageDialog(original.imageUrl)
|
showFullscreenImageDialog(original.imageUrl)
|
||||||
|
|||||||
@@ -8,14 +8,14 @@
|
|||||||
class="mb-7">
|
class="mb-7">
|
||||||
<img
|
<img
|
||||||
:src="currentInstanceWorld.ref.thumbnailImageUrl"
|
:src="currentInstanceWorld.ref.thumbnailImageUrl"
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
style="flex: none; width: 160px; height: 120px; border-radius: 4px"
|
style="flex: none; width: 160px; height: 120px; border-radius: 4px"
|
||||||
@click="showFullscreenImageDialog(currentInstanceWorld.ref.imageUrl)"
|
@click="showFullscreenImageDialog(currentInstanceWorld.ref.imageUrl)"
|
||||||
loading="lazy" />
|
loading="lazy" />
|
||||||
<div style="margin-left: 10px; display: flex; flex-direction: column; min-width: 320px; width: 100%">
|
<div style="margin-left: 10px; display: flex; flex-direction: column; min-width: 320px; width: 100%">
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
style="
|
style="
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
class="x-link x-grey"
|
class="cursor-pointer x-grey"
|
||||||
style="font-family: monospace"
|
style="font-family: monospace"
|
||||||
@click="showUserDialog(currentInstanceWorld.ref.authorId)"
|
@click="showUserDialog(currentInstanceWorld.ref.authorId)"
|
||||||
v-text="currentInstanceWorld.ref.authorName"></span>
|
v-text="currentInstanceWorld.ref.authorName"></span>
|
||||||
@@ -268,6 +268,7 @@
|
|||||||
persistKey: 'playerList',
|
persistKey: 'playerList',
|
||||||
data: currentInstanceUsersData,
|
data: currentInstanceUsersData,
|
||||||
columns: playerListColumns,
|
columns: playerListColumns,
|
||||||
|
enablePagination: false,
|
||||||
getRowId: (row) => `${row?.ref?.id ?? ''}:${row?.displayName ?? ''}`
|
getRowId: (row) => `${row?.ref?.id ?? ''}:${row?.displayName ?? ''}`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ function DetailCell({ row, isPrevious, onShowAvatar, onShowGroup, onShowWorld, o
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onShowAvatar?.(r.avatar?.id);
|
onShowAvatar?.(r.avatar?.id);
|
||||||
@@ -116,7 +116,7 @@ function DetailCell({ row, isPrevious, onShowAvatar, onShowGroup, onShowWorld, o
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
style="margin-right: 5px"
|
style="margin-right: 5px"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -129,7 +129,7 @@ function DetailCell({ row, isPrevious, onShowAvatar, onShowGroup, onShowWorld, o
|
|||||||
<ArrowRight />
|
<ArrowRight />
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
style="margin-left: 5px"
|
style="margin-left: 5px"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -145,7 +145,7 @@ function DetailCell({ row, isPrevious, onShowAvatar, onShowGroup, onShowWorld, o
|
|||||||
if (r.type === 'PortalSpawn') {
|
if (r.type === 'PortalSpawn') {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onShowWorld?.(r.location, r.shortName);
|
onShowWorld?.(r.location, r.shortName);
|
||||||
@@ -176,7 +176,7 @@ function DetailCell({ row, isPrevious, onShowAvatar, onShowGroup, onShowWorld, o
|
|||||||
<span>Android </span>
|
<span>Android </span>
|
||||||
) : null}
|
) : null}
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onShowAvatar?.(r.avatar?.id);
|
onShowAvatar?.(r.avatar?.id);
|
||||||
@@ -233,7 +233,14 @@ function DetailCell({ row, isPrevious, onShowAvatar, onShowGroup, onShowWorld, o
|
|||||||
return <span>{r.text}</span>;
|
return <span>{r.text}</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createColumns = ({ isPrevious, onShowUser, onShowAvatar, onShowGroup, onShowWorld, onShowImage }) => [
|
export const createColumns = ({
|
||||||
|
isPrevious,
|
||||||
|
onShowUser,
|
||||||
|
onShowAvatar,
|
||||||
|
onShowGroup,
|
||||||
|
onShowWorld,
|
||||||
|
onShowImage
|
||||||
|
}) => [
|
||||||
{
|
{
|
||||||
id: 'created_at',
|
id: 'created_at',
|
||||||
accessorFn: (row) => (row?.created_at ? Date.parse(row.created_at) : 0),
|
accessorFn: (row) => (row?.created_at ? Date.parse(row.created_at) : 0),
|
||||||
@@ -250,7 +257,9 @@ export const createColumns = ({ isPrevious, onShowUser, onShowAvatar, onShowGrou
|
|||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>{formatDateFilter(row.original?.created_at, 'short')}</span>
|
<span>
|
||||||
|
{formatDateFilter(row.original?.created_at, 'short')}
|
||||||
|
</span>
|
||||||
</TooltipWrapper>
|
</TooltipWrapper>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -261,7 +270,7 @@ export const createColumns = ({ isPrevious, onShowUser, onShowAvatar, onShowGrou
|
|||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
style="padding-right: 10px"
|
style="padding-right: 10px"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|||||||
@@ -283,8 +283,8 @@
|
|||||||
<div class="options-container-item" style="display: block">
|
<div class="options-container-item" style="display: block">
|
||||||
<p>
|
<p>
|
||||||
© 2019-2026
|
© 2019-2026
|
||||||
<a class="x-link" @click="openExternalLink('https://github.com/pypy-vrc')">pypy</a> &
|
<a class="cursor-pointer" @click="openExternalLink('https://github.com/pypy-vrc')">pypy</a> &
|
||||||
<a class="x-link" @click="openExternalLink('https://github.com/Natsumi-sama')">Natsumi</a>
|
<a class="cursor-pointer" @click="openExternalLink('https://github.com/Natsumi-sama')">Natsumi</a>
|
||||||
</p>
|
</p>
|
||||||
<p>{{ t('view.settings.general.legal_notice.info') }}</p>
|
<p>{{ t('view.settings.general.legal_notice.info') }}</p>
|
||||||
<p>{{ t('view.settings.general.legal_notice.disclaimer1') }}</p>
|
<p>{{ t('view.settings.general.legal_notice.disclaimer1') }}</p>
|
||||||
|
|||||||
@@ -8,8 +8,9 @@
|
|||||||
<h2 v-text="changeLogDialog.buildName"></h2>
|
<h2 v-text="changeLogDialog.buildName"></h2>
|
||||||
<span v-show="changeLogDialog.buildName">
|
<span v-show="changeLogDialog.buildName">
|
||||||
{{ t('dialog.change_log.description') }}
|
{{ t('dialog.change_log.description') }}
|
||||||
<a class="x-link" @click="openExternalLink('https://www.patreon.com/Natsumi_VRCX')">Patreon</a>,
|
<a class="cursor-pointer" @click="openExternalLink('https://www.patreon.com/Natsumi_VRCX')"
|
||||||
<a class="x-link" @click="openExternalLink('https://ko-fi.com/natsumi_sama')">Ko-fi</a>.
|
>Patreon</a
|
||||||
|
>, <a class="cursor-pointer" @click="openExternalLink('https://ko-fi.com/natsumi_sama')">Ko-fi</a>.
|
||||||
</span>
|
</span>
|
||||||
<VueShowdown
|
<VueShowdown
|
||||||
:markdown="changeLogDialog.changeLog"
|
:markdown="changeLogDialog.changeLog"
|
||||||
|
|||||||
@@ -190,6 +190,7 @@
|
|||||||
order: 99;
|
order: 99;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-tab-count {
|
.sidebar-tab-count {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="x-friend-list" style="padding: 10px 5px">
|
<div class="x-friend-list" style="padding: 10px 5px">
|
||||||
<div
|
<div
|
||||||
class="x-friend-group x-link flex items-center"
|
class="x-friend-group cursor-pointer flex items-center"
|
||||||
style="padding: 0 0 5px"
|
style="padding: 0 0 5px"
|
||||||
@click="
|
@click="
|
||||||
isFriendsGroupMe = !isFriendsGroupMe;
|
isFriendsGroupMe = !isFriendsGroupMe;
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="vipFriendsDisplayNumber"
|
v-show="vipFriendsDisplayNumber"
|
||||||
class="x-friend-group x-link flex items-center"
|
class="x-friend-group cursor-pointer flex items-center"
|
||||||
@click="
|
@click="
|
||||||
isVIPFriends = !isVIPFriends;
|
isVIPFriends = !isVIPFriends;
|
||||||
saveFriendsGroupStates();
|
saveFriendsGroupStates();
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-if="isSidebarGroupByInstance && friendsInSameInstance.length">
|
<template v-if="isSidebarGroupByInstance && friendsInSameInstance.length">
|
||||||
<div class="x-friend-group x-link flex items-center" @click="toggleSwitchGroupByInstanceCollapsed">
|
<div class="x-friend-group cursor-pointer flex items-center" @click="toggleSwitchGroupByInstanceCollapsed">
|
||||||
<ChevronDown class="rotation-transition" :class="{ 'is-rotated': isSidebarGroupByInstanceCollapsed }" />
|
<ChevronDown class="rotation-transition" :class="{ 'is-rotated': isSidebarGroupByInstanceCollapsed }" />
|
||||||
<span style="margin-left: 5px"
|
<span style="margin-left: 5px"
|
||||||
>{{ t('side_panel.same_instance') }} ― {{ friendsInSameInstance.length }}</span
|
>{{ t('side_panel.same_instance') }} ― {{ friendsInSameInstance.length }}</span
|
||||||
@@ -109,7 +109,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<div
|
<div
|
||||||
v-show="onlineFriendsByGroupStatus.length"
|
v-show="onlineFriendsByGroupStatus.length"
|
||||||
class="x-friend-group x-link flex items-center"
|
class="x-friend-group cursor-pointer flex items-center"
|
||||||
@click="
|
@click="
|
||||||
isOnlineFriends = !isOnlineFriends;
|
isOnlineFriends = !isOnlineFriends;
|
||||||
saveFriendsGroupStates();
|
saveFriendsGroupStates();
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="activeFriends.length"
|
v-show="activeFriends.length"
|
||||||
class="x-friend-group x-link flex items-center"
|
class="x-friend-group cursor-pointer flex items-center"
|
||||||
@click="
|
@click="
|
||||||
isActiveFriends = !isActiveFriends;
|
isActiveFriends = !isActiveFriends;
|
||||||
saveFriendsGroupStates();
|
saveFriendsGroupStates();
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="offlineFriends.length"
|
v-show="offlineFriends.length"
|
||||||
class="x-friend-group x-link flex items-center"
|
class="x-friend-group cursor-pointer flex items-center"
|
||||||
@click="
|
@click="
|
||||||
isOfflineFriends = !isOfflineFriends;
|
isOfflineFriends = !isOfflineFriends;
|
||||||
saveFriendsGroupStates();
|
saveFriendsGroupStates();
|
||||||
@@ -310,9 +310,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.x-link:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.is-rotated {
|
.is-rotated {
|
||||||
transform: rotate(-90deg);
|
transform: rotate(-90deg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="x-friend-list" style="padding: 10px 5px">
|
<div class="x-friend-list" style="padding: 10px 5px">
|
||||||
<template v-for="(group, index) in groupedGroupInstances" :key="getGroupId(group)">
|
<template v-for="(group, index) in groupedGroupInstances" :key="getGroupId(group)">
|
||||||
<div class="x-friend-group x-link" :style="{ paddingTop: index === 0 ? '0px' : '10px' }">
|
<div class="x-friend-group cursor-pointer" :style="{ paddingTop: index === 0 ? '0px' : '10px' }">
|
||||||
<div @click="toggleGroupSidebarCollapse(getGroupId(group))" style="display: flex; align-items: center">
|
<div @click="toggleGroupSidebarCollapse(getGroupId(group))" style="display: flex; align-items: center">
|
||||||
<ChevronDown
|
<ChevronDown
|
||||||
class="rotation-transition"
|
class="rotation-transition"
|
||||||
@@ -93,12 +93,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.x-link:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.x-link:hover span {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
.is-rotated {
|
.is-rotated {
|
||||||
transform: rotate(-90deg);
|
transform: rotate(-90deg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,7 @@
|
|||||||
<span class="header">{{ t('dialog.screenshot_metadata.header') }}</span>
|
<span class="header">{{ t('dialog.screenshot_metadata.header') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div @dragover.prevent @dragenter.prevent @drop="handleDrop">
|
<div @dragover.prevent @dragenter.prevent @drop="handleDrop">
|
||||||
<span>{{
|
<span>{{ t('dialog.screenshot_metadata.drag') }}</span>
|
||||||
t('dialog.screenshot_metadata.drag')
|
|
||||||
}}</span>
|
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<Button size="sm" variant="outline" class="mr-2" @click="getAndDisplayScreenshotFromFile">{{
|
<Button size="sm" variant="outline" class="mr-2" @click="getAndDisplayScreenshotFromFile">{{
|
||||||
@@ -100,8 +98,7 @@
|
|||||||
<DisplayName
|
<DisplayName
|
||||||
v-if="screenshotMetadataDialog.metadata.author"
|
v-if="screenshotMetadataDialog.metadata.author"
|
||||||
:userid="screenshotMetadataDialog.metadata.author.id"
|
:userid="screenshotMetadataDialog.metadata.author.id"
|
||||||
:hint="screenshotMetadataDialog.metadata.author.displayName"
|
:hint="screenshotMetadataDialog.metadata.author.displayName" />
|
||||||
/>
|
|
||||||
<br />
|
<br />
|
||||||
<div class="my-2 w-[90%] ml-17">
|
<div class="my-2 w-[90%] ml-17">
|
||||||
<Carousel :opts="{ loop: false }" @init-api="handleScreenshotMetadataCarouselInit">
|
<Carousel :opts="{ loop: false }" @init-api="handleScreenshotMetadataCarouselInit">
|
||||||
@@ -109,7 +106,6 @@
|
|||||||
<CarouselItem>
|
<CarouselItem>
|
||||||
<div class="h-150 w-full">
|
<div class="h-150 w-full">
|
||||||
<img
|
<img
|
||||||
class="x-link"
|
|
||||||
:src="screenshotMetadataDialog.metadata.previousFilePath"
|
:src="screenshotMetadataDialog.metadata.previousFilePath"
|
||||||
style="width: 100%; height: 100%; object-fit: contain" />
|
style="width: 100%; height: 100%; object-fit: contain" />
|
||||||
</div>
|
</div>
|
||||||
@@ -117,7 +113,7 @@
|
|||||||
<CarouselItem>
|
<CarouselItem>
|
||||||
<div class="h-150 w-full">
|
<div class="h-150 w-full">
|
||||||
<img
|
<img
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
:src="screenshotMetadataDialog.metadata.filePath"
|
:src="screenshotMetadataDialog.metadata.filePath"
|
||||||
style="width: 100%; height: 100%; object-fit: contain"
|
style="width: 100%; height: 100%; object-fit: contain"
|
||||||
@click="showFullscreenImageDialog(screenshotMetadataDialog.metadata.filePath)" />
|
@click="showFullscreenImageDialog(screenshotMetadataDialog.metadata.filePath)" />
|
||||||
@@ -126,7 +122,6 @@
|
|||||||
<CarouselItem>
|
<CarouselItem>
|
||||||
<div class="h-150 w-full">
|
<div class="h-150 w-full">
|
||||||
<img
|
<img
|
||||||
class="x-link"
|
|
||||||
:src="screenshotMetadataDialog.metadata.nextFilePath"
|
:src="screenshotMetadataDialog.metadata.nextFilePath"
|
||||||
style="width: 100%; height: 100%; object-fit: contain" />
|
style="width: 100%; height: 100%; object-fit: contain" />
|
||||||
</div>
|
</div>
|
||||||
@@ -143,10 +138,8 @@
|
|||||||
<br />
|
<br />
|
||||||
</template>
|
</template>
|
||||||
<span v-for="user in screenshotMetadataDialog.metadata.players" :key="user.id" style="margin-top: 5px">
|
<span v-for="user in screenshotMetadataDialog.metadata.players" :key="user.id" style="margin-top: 5px">
|
||||||
<span class="x-link" @click="lookupUser(user)" v-text="user.displayName"></span>
|
<span class="cursor-pointer" @click="lookupUser(user)" v-text="user.displayName"></span>
|
||||||
<span
|
<span v-if="user.pos" v-text="'(' + user.pos.x + ', ' + user.pos.y + ', ' + user.pos.z + ')'"></span>
|
||||||
v-if="user.pos"
|
|
||||||
v-text="'(' + user.pos.x + ', ' + user.pos.y + ', ' + user.pos.z + ')'"></span>
|
|
||||||
<br />
|
<br />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export const createColumns = ({ userImage, userImageFull, onShowFullscreenImage,
|
|||||||
const original = row.original;
|
const original = row.original;
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
class="x-link"
|
class="cursor-pointer"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onShowUser?.(original?.id);
|
onShowUser?.(original?.id);
|
||||||
|
|||||||
Reference in New Issue
Block a user