use tailwind class

This commit is contained in:
pa
2026-03-08 22:46:26 +09:00
parent be2f07f24e
commit 9b564303a4
85 changed files with 1167 additions and 642 deletions
+3 -3
View File
@@ -8,19 +8,19 @@ html {
.x-container { .x-container {
position: relative; position: relative;
padding: 10px; padding: 8px;
overflow: hidden auto; overflow: hidden auto;
box-sizing: border-box; box-sizing: border-box;
min-width: 0; min-width: 0;
background: var(--background); background: var(--background);
height: calc(100% - 20px); height: calc(100% - 20px);
margin: 10px 0 10px 0; margin: 8px 0 8px 0;
border-radius: var(--radius); border-radius: var(--radius);
border: 1px solid var(--border); border: 1px solid var(--border);
} }
.aside-collapsed .x-container { .aside-collapsed .x-container {
margin-right: 10px; margin-right: 8px;
} }
html.dark .x-container { html.dark .x-container {
+3 -4
View File
@@ -53,10 +53,9 @@
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="showHistoryButton" side="top" :content="historyTooltip"> <TooltipWrapper v-if="showHistoryButton" side="top" :content="historyTooltip">
<Button <Button
class="rounded-full w-6 h-6 text-xs text-muted-foreground hover:text-foreground" class="rounded-full w-6 h-6 text-xs text-muted-foreground hover:text-foreground ml-1.5"
size="icon-sm" size="icon-sm"
variant="outline" variant="outline"
style="margin-left: 5px"
@click="handleHistory"> @click="handleHistory">
<History class="h-4 w-4" /> <History class="h-4 w-4" />
</Button> </Button>
@@ -101,7 +100,7 @@
</span> </span>
<span v-if="instance?.users?.length">{{ t('dialog.user.info.instance_users') }}<br /></span> <span v-if="instance?.users?.length">{{ t('dialog.user.info.instance_users') }}<br /></span>
<template v-for="user in instance?.users || []" :key="user.id"> <template v-for="user in instance?.users || []" :key="user.id">
<span style="cursor: pointer; margin-right: 5px" @click="showUserDialog(user.id)"> <span style="cursor: pointer; margin-right: 6px" @click="showUserDialog(user.id)">
{{ user.displayName }} {{ user.displayName }}
</span> </span>
</template> </template>
@@ -268,7 +267,7 @@
const showLaunchButton = computed(() => props.showLaunch && checkCanInviteSelf(resolvedLaunchLocation.value)); const showLaunchButton = computed(() => props.showLaunch && checkCanInviteSelf(resolvedLaunchLocation.value));
const showInviteYourself = computed(() => props.showInvite && checkCanInviteSelf(resolvedInviteLocation.value)); const showInviteYourself = computed(() => props.showInvite && checkCanInviteSelf(resolvedInviteLocation.value));
const inviteStyle = computed(() => (showLaunchButton.value ? 'margin-left: 5px' : '')); const inviteStyle = computed(() => (showLaunchButton.value ? 'margin-left: 6px' : ''));
const showRefreshButton = computed(() => props.showRefresh && typeof props.onRefresh === 'function'); const showRefreshButton = computed(() => props.showRefresh && typeof props.onRefresh === 'function');
const showHistoryButton = computed(() => props.showHistory && typeof props.onHistory === 'function'); const showHistoryButton = computed(() => props.showHistory && typeof props.onHistory === 'function');
+14 -1
View File
@@ -9,7 +9,7 @@
<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-1']" style="color: lightcoral" /> <AlertTriangle :class="['inline-block', 'ml-1']" style="color: lightcoral" />
</TooltipWrapper> </TooltipWrapper>
<Lock v-if="strict" style="display: inline-block; margin-left: 5px" /> <Lock class="ml-1.5" v-if="strict" style="display: inline-block" />
</span> </span>
</template> </template>
@@ -50,6 +50,9 @@
const groupName = ref(''); const groupName = ref('');
const isClosed = ref(false); const isClosed = ref(false);
/**
*
*/
function parse() { function parse() {
const locObj = props.locationobject; const locObj = props.locationobject;
location.value = locObj.tag; location.value = locObj.tag;
@@ -94,6 +97,10 @@
} }
} }
/**
*
* @param accessTypeNameRaw
*/
function translateAccessType(accessTypeNameRaw) { function translateAccessType(accessTypeNameRaw) {
const key = accessTypeLocaleKeyMap[accessTypeNameRaw]; const key = accessTypeLocaleKeyMap[accessTypeNameRaw];
if (!key) { if (!key) {
@@ -118,10 +125,16 @@
{ immediate: true } { immediate: true }
); );
/**
*
*/
function showLaunchDialog() { function showLaunchDialog() {
launchStore.showLaunchDialog(location.value, shortName.value); launchStore.showLaunchDialog(location.value, shortName.value);
} }
/**
*
*/
function showGroupDialog() { function showGroupDialog() {
if (!location.value) return; if (!location.value) return;
const L = parseLocation(location.value); const L = parseLocation(location.value);
+2 -2
View File
@@ -539,7 +539,7 @@
align-items: center; align-items: center;
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 0 6px; padding: 0 8px;
} }
.status-bar-left { .status-bar-left {
@@ -561,7 +561,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
padding: 0 6px; padding: 0 8px;
height: 22px; height: 22px;
white-space: nowrap; white-space: nowrap;
border-right: 1px solid var(--border); border-right: 1px solid var(--border);
@@ -16,16 +16,16 @@
style="width: 160px; height: 120px; border-radius: var(--radius-xl); object-fit: cover" style="width: 160px; height: 120px; border-radius: var(--radius-xl); object-fit: cover"
loading="lazy" /> loading="lazy" />
</div> </div>
<div style="flex: 1; display: flex; align-items: flex-start; margin-left: 15px"> <div class="ml-4" style="flex: 1; display: flex; align-items: flex-start">
<div style="flex: 1"> <div style="flex: 1">
<div> <div>
<span <span
class="font-bold" class="font-bold mr-1.5"
style="margin-right: 5px; cursor: pointer" style="cursor: pointer"
v-text="avatarDialog.ref.name" v-text="avatarDialog.ref.name"
@click="copyToClipboard(avatarDialog.ref.name)"></span> @click="copyToClipboard(avatarDialog.ref.name)"></span>
</div> </div>
<div style="margin-top: 5px"> <div class="mt-1.5">
<span <span
class="cursor-pointer x-grey" class="cursor-pointer x-grey"
style="font-family: monospace" style="font-family: monospace"
@@ -34,19 +34,16 @@
</div> </div>
<div> <div>
<Badge <Badge
class="mr-1.5 mt-1.5"
v-if="avatarDialog.ref.releaseStatus === 'public'" v-if="avatarDialog.ref.releaseStatus === 'public'"
variant="outline" variant="outline">
style="margin-right: 5px; margin-top: 5px">
{{ t('dialog.avatar.tags.public') }} {{ t('dialog.avatar.tags.public') }}
</Badge> </Badge>
<Badge v-else variant="outline" style="margin-right: 5px; margin-top: 5px"> <Badge class="mr-1.5 mt-1.5" v-else variant="outline">
{{ t('dialog.avatar.tags.private') }} {{ t('dialog.avatar.tags.private') }}
</Badge> </Badge>
<TooltipWrapper v-if="avatarDialog.isPC" side="top" content="PC"> <TooltipWrapper v-if="avatarDialog.isPC" side="top" content="PC">
<Badge <Badge class="text-platform-pc border-platform-pc! mr-1.5 mt-1.5" variant="outline"
class="text-platform-pc border-platform-pc!"
variant="outline"
style="margin-right: 5px; margin-top: 5px"
><Monitor class="h-4 w-4 text-platform-pc" /> ><Monitor class="h-4 w-4 text-platform-pc" />
<span <span
v-if="avatarDialog.platformInfo.pc" v-if="avatarDialog.platformInfo.pc"
@@ -62,9 +59,8 @@
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="avatarDialog.isQuest" side="top" content="Android"> <TooltipWrapper v-if="avatarDialog.isQuest" side="top" content="Android">
<Badge <Badge
class="text-platform-quest border-platform-quest!" class="text-platform-quest border-platform-quest! mr-1.5 mt-1.5"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"
><Smartphone class="h-4 w-4 text-platform-quest" /> ><Smartphone class="h-4 w-4 text-platform-quest" />
<span <span
v-if="avatarDialog.platformInfo.android" v-if="avatarDialog.platformInfo.android"
@@ -79,10 +75,7 @@
</Badge> </Badge>
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="avatarDialog.isIos" side="top" content="iOS"> <TooltipWrapper v-if="avatarDialog.isIos" side="top" content="iOS">
<Badge <Badge class="text-platform-ios border-platform-ios mr-1.5 mt-1.5" variant="outline"
class="text-platform-ios border-platform-ios"
variant="outline"
style="margin-right: 5px; margin-top: 5px"
><Apple class="h-4 w-4 text-platform-ios" /> ><Apple class="h-4 w-4 text-platform-ios" />
<span <span
v-if="avatarDialog.platformInfo.ios" v-if="avatarDialog.platformInfo.ios"
@@ -99,16 +92,15 @@
<Badge <Badge
v-if="avatarDialog.inCache" v-if="avatarDialog.inCache"
variant="outline" variant="outline"
class="cursor-pointer" class="cursor-pointer mr-1.5 mt-1.5"
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>
&nbsp;{{ t('dialog.avatar.tags.cache') }} &nbsp;{{ t('dialog.avatar.tags.cache') }}
</Badge> </Badge>
<Badge <Badge
class="mr-1.5 mt-1.5"
v-if="avatarDialog.ref.styles?.primary || avatarDialog.ref.styles?.secondary" v-if="avatarDialog.ref.styles?.primary || avatarDialog.ref.styles?.secondary"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"
>{{ t('view.favorite.avatars.styles') }} >{{ t('view.favorite.avatars.styles') }}
<span <span
v-if="avatarDialog.ref.styles.primary" v-if="avatarDialog.ref.styles.primary"
@@ -121,16 +113,10 @@
>{{ avatarDialog.ref.styles.secondary }}</span >{{ avatarDialog.ref.styles.secondary }}</span
> >
</Badge> </Badge>
<Badge <Badge class="mr-1.5 mt-1.5" v-if="avatarDialog.isQuestFallback" variant="outline">
v-if="avatarDialog.isQuestFallback"
variant="outline"
style="margin-right: 5px; margin-top: 5px">
{{ t('dialog.avatar.tags.fallback') }} {{ t('dialog.avatar.tags.fallback') }}
</Badge> </Badge>
<Badge <Badge class="mr-1.5 mt-1.5" v-if="avatarDialog.hasImposter" variant="outline"
v-if="avatarDialog.hasImposter"
variant="outline"
style="margin-right: 5px; margin-top: 5px"
>{{ t('dialog.avatar.tags.impostor') }} >{{ t('dialog.avatar.tags.impostor') }}
<span <span
v-if="avatarDialog.imposterVersion" v-if="avatarDialog.imposterVersion"
@@ -138,18 +124,12 @@
>v{{ avatarDialog.imposterVersion }}</span >v{{ avatarDialog.imposterVersion }}</span
> >
</Badge> </Badge>
<Badge <Badge class="mr-1.5 mt-1.5" v-if="avatarDialog.ref.unityPackageUrl" variant="outline">
v-if="avatarDialog.ref.unityPackageUrl"
variant="outline"
style="margin-right: 5px; margin-top: 5px">
{{ t('dialog.avatar.tags.future_proofing') }} {{ t('dialog.avatar.tags.future_proofing') }}
</Badge> </Badge>
<div> <div>
<template v-for="tag in avatarDialog.ref.tags" :key="tag"> <template v-for="tag in avatarDialog.ref.tags" :key="tag">
<Badge <Badge class="mr-1.5 mt-1.5" v-if="tag.startsWith('content_')" variant="outline">
v-if="tag.startsWith('content_')"
variant="outline"
style="margin-right: 5px; margin-top: 5px">
<span v-if="tag === 'content_horror'">{{ <span v-if="tag === 'content_horror'">{{
t('dialog.avatar.tags.content_horror') t('dialog.avatar.tags.content_horror')
}}</span> }}</span>
@@ -167,10 +147,7 @@
}}</span> }}</span>
<span v-else>{{ tag.replace('content_', '') }}</span> <span v-else>{{ tag.replace('content_', '') }}</span>
</Badge> </Badge>
<Badge <Badge class="mr-1.5 mt-1.5" v-if="tag.startsWith('author_tag_')" variant="outline">
v-if="tag.startsWith('author_tag_')"
variant="outline"
style="margin-right: 5px; margin-top: 5px">
<span> <span>
{{ tag.replace('author_tag_', '') }} {{ tag.replace('author_tag_', '') }}
</span> </span>
@@ -178,7 +155,7 @@
</template> </template>
</div> </div>
</div> </div>
<div style="margin-top: 5px"> <div style="margin-top: 6px">
<span <span
v-show="avatarDialog.ref.name !== avatarDialog.ref.description" v-show="avatarDialog.ref.name !== avatarDialog.ref.description"
style="font-size: 12px" style="font-size: 12px"
@@ -412,7 +389,7 @@
</div> </div>
<div class="box-border flex items-center p-1.5 text-[13px] w-full cursor-default"> <div class="box-border flex items-center p-1.5 text-[13px] w-full cursor-default">
<div class="flex-1 overflow-hidden"> <div class="flex-1 overflow-hidden">
<span class="block truncate font-medium leading-[18px]" style="margin-bottom: 5px">{{ <span class="block truncate font-medium leading-[18px]" style="margin-bottom: 6px">{{
t('dialog.avatar.info.memo') t('dialog.avatar.info.memo')
}}</span> }}</span>
<InputGroupTextareaField <InputGroupTextareaField
@@ -473,7 +450,7 @@
<TooltipWrapper <TooltipWrapper
v-if="Object.keys(avatarDialog.fileAnalysis).length" v-if="Object.keys(avatarDialog.fileAnalysis).length"
side="top" side="top"
style="margin-left: 5px"> style="margin-left: 6px">
<template #content> <template #content>
<template <template
v-for="(created_at, platform) in avatarDialogPlatformCreatedAt" v-for="(created_at, platform) in avatarDialogPlatformCreatedAt"
@@ -65,8 +65,7 @@
:autosize="{ minRows: 2, maxRows: 5 }" :autosize="{ minRows: 2, maxRows: 5 }"
:rows="2" :rows="2"
placeholder="" placeholder=""
style="margin-top: 10px" input-class="resize-none mt-2"
input-class="resize-none"
@update:modelValue="(v) => updateDialog({ authorTags: v })" /> @update:modelValue="(v) => updateDialog({ authorTags: v })" />
</template> </template>
@@ -83,8 +82,8 @@
</template> </template>
<script setup> <script setup>
import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -118,6 +117,10 @@
} }
); );
/**
*
* @param patch
*/
function updateDialog(patch) { function updateDialog(patch) {
emit('update:setAvatarStylesDialog', { emit('update:setAvatarStylesDialog', {
...props.setAvatarStylesDialog, ...props.setAvatarStylesDialog,
@@ -125,6 +128,9 @@
}); });
} }
/**
*
*/
async function getAvatarStyles() { async function getAvatarStyles() {
try { try {
const ref = await avatarRequest.getAvailableAvatarStyles(); const ref = await avatarRequest.getAvailableAvatarStyles();
@@ -144,10 +150,16 @@
} }
} }
/**
*
*/
function closeSetAvatarStylesDialog() { function closeSetAvatarStylesDialog() {
updateDialog({ visible: false }); updateDialog({ visible: false });
} }
/**
*
*/
function saveSetAvatarStylesDialog() { function saveSetAvatarStylesDialog() {
const primaryStyleId = const primaryStyleId =
props.setAvatarStylesDialog.availableAvatarStylesMap.get(props.setAvatarStylesDialog.primaryStyle) || ''; props.setAvatarStylesDialog.availableAvatarStylesMap.get(props.setAvatarStylesDialog.primaryStyle) || '';
@@ -43,7 +43,7 @@
v-model="setAvatarTagsDialog.selectedTagsCsv" v-model="setAvatarTagsDialog.selectedTagsCsv"
:rows="2" :rows="2"
:placeholder="t('dialog.set_avatar_tags.custom_tags_placeholder')" :placeholder="t('dialog.set_avatar_tags.custom_tags_placeholder')"
style="margin-top: 10px" class="mt-2"
input-class="resize-none" input-class="resize-none"
@input="updateInputAvatarTags" /> @input="updateInputAvatarTags" />
<br /> <br />
@@ -59,7 +59,7 @@
t('dialog.set_avatar_tags.select_all') t('dialog.set_avatar_tags.select_all')
}}</Button> }}</Button>
</template> </template>
<span style="margin-left: 5px" <span style="margin-left: 6px"
>{{ props.setAvatarTagsDialog.selectedAvatarIds.length }} / >{{ props.setAvatarTagsDialog.selectedAvatarIds.length }} /
{{ setAvatarTagsDialog.ownAvatars.length }}</span {{ setAvatarTagsDialog.ownAvatars.length }}</span
> >
@@ -67,7 +67,7 @@
<br /> <br />
<div <div
class="flex flex-wrap items-start max-h-[300px] overflow-hidden auto" class="flex flex-wrap items-start max-h-[300px] overflow-hidden auto"
style="margin-top: 10px; min-height: 60px"> style="margin-top: 8px; min-height: 60px">
<div <div
v-for="avatar in setAvatarTagsDialog.ownAvatars" v-for="avatar in setAvatarTagsDialog.ownAvatars"
:key="avatar.id" :key="avatar.id"
@@ -96,7 +96,7 @@
<span v-else class="block truncate text-xs" v-text="avatar.releaseStatus"></span> <span v-else class="block truncate text-xs" v-text="avatar.releaseStatus"></span>
<span class="block truncate text-xs" v-text="avatarTagStrings.get(avatar.id)"></span> <span class="block truncate text-xs" v-text="avatarTagStrings.get(avatar.id)"></span>
</div> </div>
<Button size="sm" variant="ghost" style="margin-left: 5px" @click.stop> <Button size="sm" variant="ghost" style="margin-left: 6px" @click.stop>
<Checkbox <Checkbox
:model-value="props.setAvatarTagsDialog.selectedAvatarIds.includes(avatar.id)" :model-value="props.setAvatarTagsDialog.selectedAvatarIds.includes(avatar.id)"
@update:modelValue="(val) => toggleAvatarSelection(avatar.id, val)" /> @update:modelValue="(val) => toggleAvatarSelection(avatar.id, val)" />
@@ -7,7 +7,7 @@
<div> <div>
<span>{{ t('dialog.gallery_select.gallery') }}</span> <span>{{ t('dialog.gallery_select.gallery') }}</span>
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{ galleryTable.length }}/64</span> <span class="ml-1.5" style="color: #909399; font-size: 12px">{{ galleryTable.length }}/64</span>
<br /> <br />
<input <input
id="GalleryUploadButton" id="GalleryUploadButton"
@@ -82,6 +82,11 @@
} }
}); });
/**
*
* @param imageUrl
* @param fileId
*/
function selectImageGallerySelect(imageUrl, fileId) { function selectImageGallerySelect(imageUrl, fileId) {
const D = props.gallerySelectDialog; const D = props.gallerySelectDialog;
D.selectedFileId = fileId; D.selectedFileId = fileId;
@@ -89,10 +94,17 @@
D.visible = false; D.visible = false;
} }
/**
*
*/
function displayGalleryUpload() { function displayGalleryUpload() {
document.getElementById('GalleryUploadButton').click(); document.getElementById('GalleryUploadButton').click();
} }
/**
*
* @param e
*/
function onFileChangeGallery(e) { function onFileChangeGallery(e) {
const clearFile = function () { const clearFile = function () {
const fileInput = /** @type{HTMLInputElement} */ (document.querySelector('#GalleryUploadButton')); const fileInput = /** @type{HTMLInputElement} */ (document.querySelector('#GalleryUploadButton'));
@@ -17,17 +17,15 @@
@click="showFullscreenImageDialog(groupDialog.ref.iconUrl)" @click="showFullscreenImageDialog(groupDialog.ref.iconUrl)"
loading="lazy" /> loading="lazy" />
</div> </div>
<div style="flex: 1; display: flex; align-items: flex-start; margin-left: 15px"> <div class="ml-4" style="flex: 1; display: flex; align-items: flex-start">
<div class="group-header" style="flex: 1"> <div class="group-header" style="flex: 1">
<span v-if="groupDialog.ref.ownerId === currentUser.id" style="margin-right: 5px">👑</span> <span class="mr-1.5" v-if="groupDialog.ref.ownerId === currentUser.id">👑</span>
<span <span
class="font-bold" class="font-bold mr-1.5"
style="margin-right: 5px; cursor: pointer" style="cursor: pointer"
v-text="groupDialog.ref.name" v-text="groupDialog.ref.name"
@click="copyToClipboard(groupDialog.ref.name)"></span> @click="copyToClipboard(groupDialog.ref.name)"></span>
<span <span class="group-discriminator x-grey mr-1.5" style="font-family: monospace; font-size: 12px">
class="group-discriminator x-grey"
style="font-family: monospace; font-size: 12px; margin-right: 5px">
{{ groupDialog.ref.shortCode }}.{{ groupDialog.ref.discriminator }} {{ groupDialog.ref.shortCode }}.{{ groupDialog.ref.discriminator }}
</span> </span>
<TooltipWrapper v-for="item in groupDialog.ref.$languages" :key="item.key" side="top"> <TooltipWrapper v-for="item in groupDialog.ref.$languages" :key="item.key" side="top">
@@ -37,9 +35,9 @@
<span <span
class="flags" class="flags"
:class="languageClass(item.key)" :class="languageClass(item.key)"
style="display: inline-block; margin-right: 5px"></span> style="display: inline-block; margin-right: 6px"></span>
</TooltipWrapper> </TooltipWrapper>
<div style="margin-top: 5px"> <div style="margin-top: 6px">
<span <span
class="cursor-pointer x-grey" class="cursor-pointer x-grey"
style="font-family: monospace" style="font-family: monospace"
@@ -50,85 +48,85 @@
<Badge <Badge
v-if="groupDialog.ref.isVerified" v-if="groupDialog.ref.isVerified"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
{{ t('dialog.group.tags.verified') }} {{ t('dialog.group.tags.verified') }}
</Badge> </Badge>
<Badge <Badge
v-if="groupDialog.ref.privacy === 'private'" v-if="groupDialog.ref.privacy === 'private'"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
{{ t('dialog.group.tags.private') }} {{ t('dialog.group.tags.private') }}
</Badge> </Badge>
<Badge <Badge
v-if="groupDialog.ref.privacy === 'default'" v-if="groupDialog.ref.privacy === 'default'"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
{{ t('dialog.group.tags.public') }} {{ t('dialog.group.tags.public') }}
</Badge> </Badge>
<Badge <Badge
v-if="groupDialog.ref.joinState === 'open'" v-if="groupDialog.ref.joinState === 'open'"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
{{ t('dialog.group.tags.open') }} {{ t('dialog.group.tags.open') }}
</Badge> </Badge>
<Badge <Badge
v-else-if="groupDialog.ref.joinState === 'request'" v-else-if="groupDialog.ref.joinState === 'request'"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
{{ t('dialog.group.tags.request') }} {{ t('dialog.group.tags.request') }}
</Badge> </Badge>
<Badge <Badge
v-else-if="groupDialog.ref.joinState === 'invite'" v-else-if="groupDialog.ref.joinState === 'invite'"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
{{ t('dialog.group.tags.invite') }} {{ t('dialog.group.tags.invite') }}
</Badge> </Badge>
<Badge <Badge
v-else-if="groupDialog.ref.joinState === 'closed'" v-else-if="groupDialog.ref.joinState === 'closed'"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
{{ t('dialog.group.tags.closed') }} {{ t('dialog.group.tags.closed') }}
</Badge> </Badge>
<Badge <Badge
v-if="groupDialog.inGroup" v-if="groupDialog.inGroup"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
{{ t('dialog.group.tags.joined') }} {{ t('dialog.group.tags.joined') }}
</Badge> </Badge>
<Badge <Badge
v-if="groupDialog.ref.myMember && groupDialog.ref.myMember.bannedAt" v-if="groupDialog.ref.myMember && groupDialog.ref.myMember.bannedAt"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
{{ t('dialog.group.tags.banned') }} {{ t('dialog.group.tags.banned') }}
</Badge> </Badge>
<template v-if="groupDialog.inGroup && groupDialog.ref.myMember"> <template v-if="groupDialog.inGroup && groupDialog.ref.myMember">
<Badge <Badge
v-if="groupDialog.ref.myMember.visibility === 'visible'" v-if="groupDialog.ref.myMember.visibility === 'visible'"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
{{ t('dialog.group.tags.visible') }} {{ t('dialog.group.tags.visible') }}
</Badge> </Badge>
<Badge <Badge
v-else-if="groupDialog.ref.myMember.visibility === 'friends'" v-else-if="groupDialog.ref.myMember.visibility === 'friends'"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
{{ t('dialog.group.tags.friends') }} {{ t('dialog.group.tags.friends') }}
</Badge> </Badge>
<Badge <Badge
v-else-if="groupDialog.ref.myMember.visibility === 'hidden'" v-else-if="groupDialog.ref.myMember.visibility === 'hidden'"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
{{ t('dialog.group.tags.hidden') }} {{ t('dialog.group.tags.hidden') }}
</Badge> </Badge>
<Badge <Badge
v-if="groupDialog.ref.myMember.isSubscribedToAnnouncements" v-if="groupDialog.ref.myMember.isSubscribedToAnnouncements"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
{{ t('dialog.group.tags.subscribed') }} {{ t('dialog.group.tags.subscribed') }}
</Badge> </Badge>
</template> </template>
</div> </div>
<div style="margin-top: 5px"> <div style="margin-top: 6px">
<pre <pre
v-show="groupDialog.ref.name !== groupDialog.ref.description" v-show="groupDialog.ref.name !== groupDialog.ref.description"
style=" style="
@@ -151,7 +149,7 @@
class="rounded-full mr-2" class="rounded-full mr-2"
variant="secondary" variant="secondary"
size="icon-lg" size="icon-lg"
style="margin-left: 5px" style="margin-left: 6px"
@click="clearGroupRepresentation(groupDialog.id)"> @click="clearGroupRepresentation(groupDialog.id)">
<BookmarkCheck /> <BookmarkCheck />
</Button> </Button>
@@ -362,11 +360,11 @@
<div class="flex flex-wrap items-start px-2.5" style="max-height: none"> <div class="flex flex-wrap items-start px-2.5" style="max-height: none">
<span <span
v-if="groupDialog.instances.length" v-if="groupDialog.instances.length"
style="font-size: 12px; font-weight: bold; margin: 5px"> style="font-size: 12px; font-weight: bold; margin: 6px">
{{ t('dialog.group.info.instances') }} {{ t('dialog.group.info.instances') }}
</span> </span>
<div v-for="room in groupDialog.instances" :key="room.tag" style="width: 100%"> <div v-for="room in groupDialog.instances" :key="room.tag" style="width: 100%">
<div style="margin: 5px 0" class="flex items-center"> <div style="margin: 6px 0" class="flex items-center">
<Location :location="room.tag" class="text-sm" /> <Location :location="room.tag" class="text-sm" />
<InstanceActionBar <InstanceActionBar
class="ml-1" class="ml-1"
@@ -380,7 +378,7 @@
<div <div
v-if="room.users.length" v-if="room.users.length"
class="flex flex-wrap items-start" class="flex flex-wrap items-start"
style="margin: 10px 0; padding: 0; max-height: unset"> style="margin: 8px 0; padding: 0; max-height: unset">
<div <div
v-for="user in room.users" v-for="user in room.users"
:key="user.id" :key="user.id"
@@ -418,7 +416,7 @@
<span style="display: block" v-text="groupDialog.announcement.title" /> <span style="display: block" v-text="groupDialog.announcement.title" />
<div <div
v-if="groupDialog.announcement.imageUrl" v-if="groupDialog.announcement.imageUrl"
style="display: inline-block; margin-right: 5px"> style="display: inline-block; margin-right: 6px">
<img <img
:src="groupDialog.announcement.imageUrl" :src="groupDialog.announcement.imageUrl"
class="cursor-pointer" class="cursor-pointer"
@@ -448,7 +446,7 @@
<div <div
v-if="groupDialog.announcement.id" v-if="groupDialog.announcement.id"
class="text-xs" class="text-xs"
style="float: right; margin-left: 5px"> style="float: right; margin-left: 6px">
<TooltipWrapper v-if="groupDialog.announcement.roleIds.length" side="top"> <TooltipWrapper v-if="groupDialog.announcement.roleIds.length" side="top">
<template #content> <template #content>
<span>{{ t('dialog.group.posts.visibility') }}</span> <span>{{ t('dialog.group.posts.visibility') }}</span>
@@ -466,12 +464,12 @@
</span> </span>
</template> </template>
</template> </template>
<Eye style="margin-right: 5px" /> <Eye style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<DisplayName <DisplayName
:userid="groupDialog.announcement.authorId" :userid="groupDialog.announcement.authorId"
style="margin-right: 5px" /> style="margin-right: 6px" />
<span v-if="groupDialog.announcement.editorId" style="margin-right: 5px"> <span v-if="groupDialog.announcement.editorId" style="margin-right: 6px">
({{ t('dialog.group.posts.edited_by') }} ({{ t('dialog.group.posts.edited_by') }}
<DisplayName :userid="groupDialog.announcement.editorId" />) <DisplayName :userid="groupDialog.announcement.editorId" />)
</span> </span>
@@ -502,7 +500,7 @@
<Button <Button
size="sm" size="sm"
variant="ghost" variant="ghost"
style="margin-left: 5px; padding: 0" style="margin-left: 6px; padding: 0"
@click=" @click="
showGroupPostEditDialog(groupDialog.id, groupDialog.announcement) showGroupPostEditDialog(groupDialog.id, groupDialog.announcement)
"></Button> "></Button>
@@ -511,7 +509,7 @@
<Button <Button
size="sm" size="sm"
variant="ghost" variant="ghost"
style="margin-left: 5px; padding: 0" style="margin-left: 6px; padding: 0"
@click="confirmDeleteGroupPost(groupDialog.announcement)"></Button> @click="confirmDeleteGroupPost(groupDialog.announcement)"></Button>
</TooltipWrapper> </TooltipWrapper>
</template> </template>
@@ -623,7 +621,7 @@
}}</span> }}</span>
<div <div
v-if="groupDialog.ref.links && groupDialog.ref.links.length > 0" v-if="groupDialog.ref.links && groupDialog.ref.links.length > 0"
style="margin-top: 5px" style="margin-top: 6px"
class="flex"> class="flex">
<template v-for="(link, index) in groupDialog.ref.links" :key="index"> <template v-for="(link, index) in groupDialog.ref.links" :key="index">
<TooltipWrapper v-if="link"> <TooltipWrapper v-if="link">
@@ -636,7 +634,7 @@
width: 16px; width: 16px;
height: 16px; height: 16px;
vertical-align: middle; vertical-align: middle;
margin-right: 5px; margin-right: 6px;
cursor: pointer; cursor: pointer;
" "
@click.stop="openExternalLink(link)" @click.stop="openExternalLink(link)"
@@ -687,8 +685,8 @@
</div> </div>
<div <div
v-if="groupDialog.ref.membershipStatus === 'member'" v-if="groupDialog.ref.membershipStatus === 'member'"
style="width: 100%; margin-top: 10px; border-top: 1px solid #e4e7ed14"> style="width: 100%; margin-top: 8px; border-top: 1px solid #e4e7ed14">
<div style="width: 100%; display: flex; margin-top: 10px"> <div style="width: 100%; display: flex; margin-top: 8px">
<div class="box-border flex items-center p-1.5 text-[13px] cursor-default w-[167px]"> <div class="box-border flex items-center p-1.5 text-[13px] cursor-default w-[167px]">
<div class="flex-1 overflow-hidden"> <div class="flex-1 overflow-hidden">
<span class="block truncate font-medium leading-[18px]">{{ <span class="block truncate font-medium leading-[18px]">{{
@@ -755,7 +753,7 @@
</template> </template>
<template #Posts> <template #Posts>
<template v-if="groupDialog.visible"> <template v-if="groupDialog.visible">
<span style="margin-right: 10px; vertical-align: top" <span style="margin-right: 8px; vertical-align: top"
>{{ t('dialog.group.posts.posts_count') }} {{ groupDialog.posts.length }}</span >{{ t('dialog.group.posts.posts_count') }} {{ groupDialog.posts.length }}</span
> >
<InputGroupField <InputGroupField
@@ -763,7 +761,7 @@
clearable clearable
size="sm" size="sm"
:placeholder="t('dialog.group.posts.search_placeholder')" :placeholder="t('dialog.group.posts.search_placeholder')"
style="width: 89%; margin-bottom: 10px" style="width: 89%; margin-bottom: 8px"
@input="updateGroupPostSearch" /> @input="updateGroupPostSearch" />
<div class="flex flex-wrap items-start"> <div class="flex flex-wrap items-start">
<div <div
@@ -772,7 +770,7 @@
class="box-border flex items-center p-1.5 text-[13px] w-full cursor-default"> class="box-border flex items-center p-1.5 text-[13px] w-full cursor-default">
<div class="flex-1 overflow-hidden"> <div class="flex-1 overflow-hidden">
<span style="display: block" v-text="post.title" /> <span style="display: block" v-text="post.title" />
<div v-if="post.imageUrl" style="display: inline-block; margin-right: 5px"> <div v-if="post.imageUrl" style="display: inline-block; margin-right: 6px">
<img <img
:src="post.imageUrl" :src="post.imageUrl"
class="cursor-pointer" class="cursor-pointer"
@@ -799,7 +797,7 @@
>{{ post.text || '-' }}</pre >{{ post.text || '-' }}</pre
> >
<br /> <br />
<div v-if="post.authorId" class="text-xs" style="float: right; margin-left: 5px"> <div v-if="post.authorId" class="text-xs" style="float: right; margin-left: 6px">
<TooltipWrapper v-if="post.roleIds.length" side="top"> <TooltipWrapper v-if="post.roleIds.length" side="top">
<template #content> <template #content>
<span>{{ t('dialog.group.posts.visibility') }}</span> <span>{{ t('dialog.group.posts.visibility') }}</span>
@@ -816,10 +814,10 @@
> >
</template> </template>
</template> </template>
<Eye style="margin-right: 5px" /> <Eye style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<DisplayName :userid="post.authorId" style="margin-right: 5px" /> <DisplayName :userid="post.authorId" style="margin-right: 6px" />
<span v-if="post.editorId" style="margin-right: 5px" <span v-if="post.editorId" style="margin-right: 6px"
>({{ t('dialog.group.posts.edited_by') }} >({{ t('dialog.group.posts.edited_by') }}
<DisplayName :userid="post.editorId" />)</span <DisplayName :userid="post.editorId" />)</span
> >
@@ -878,7 +876,7 @@
<span v-else style="font-weight: bold; font-size: 16px">{{ <span v-else style="font-weight: bold; font-size: 16px">{{
t('dialog.group.members.friends_only') t('dialog.group.members.friends_only')
}}</span> }}</span>
<div style="margin-top: 10px"> <div style="margin-top: 8px">
<Button <Button
class="rounded-full h-6 w-6" class="rounded-full h-6 w-6"
variant="ghost" variant="ghost"
@@ -892,23 +890,23 @@
class="rounded-full h-6 w-6 ml-2" class="rounded-full h-6 w-6 ml-2"
size="icon-sm" size="icon-sm"
variant="ghost" variant="ghost"
style="margin-left: 5px" style="margin-left: 6px"
@click="downloadAndSaveJson(`${groupDialog.id}_members`, groupDialog.members)"> @click="downloadAndSaveJson(`${groupDialog.id}_members`, groupDialog.members)">
<Download class="h-4 w-4" /> <Download class="h-4 w-4" />
</Button> </Button>
<span <span
v-if="groupDialog.memberSearch.length" v-if="groupDialog.memberSearch.length"
style="font-size: 14px; margin-left: 5px; margin-right: 5px" style="font-size: 14px; margin-left: 6px; margin-right: 6px"
>{{ groupDialog.memberSearchResults.length }}/{{ groupDialog.ref.memberCount }}</span >{{ groupDialog.memberSearchResults.length }}/{{ groupDialog.ref.memberCount }}</span
> >
<span v-else style="font-size: 14px; margin-left: 5px; margin-right: 5px" <span v-else style="font-size: 14px; margin-left: 6px; margin-right: 6px"
>{{ groupDialog.members.length }}/{{ groupDialog.ref.memberCount }}</span >{{ groupDialog.members.length }}/{{ groupDialog.ref.memberCount }}</span
> >
<div <div
v-if="hasGroupPermission(groupDialog.ref, 'group-members-manage')" v-if="hasGroupPermission(groupDialog.ref, 'group-members-manage')"
style="float: right" style="float: right"
class="flex items-center"> class="flex items-center">
<span style="margin-right: 5px">{{ t('dialog.group.members.sort_by') }}</span> <span style="margin-right: 6px">{{ t('dialog.group.members.sort_by') }}</span>
<Select <Select
v-model="groupDialogMemberSortValue" v-model="groupDialogMemberSortValue"
:disabled="isGroupMembersLoading || groupDialog.memberSearch.length > 0"> :disabled="isGroupMembersLoading || groupDialog.memberSearch.length > 0">
@@ -948,13 +946,13 @@
clearable clearable
size="sm" size="sm"
:placeholder="t('dialog.group.members.search')" :placeholder="t('dialog.group.members.search')"
style="margin-top: 10px; margin-bottom: 10px" style="margin-top: 8px; margin-bottom: 8px"
@input="groupMembersSearch" /> @input="groupMembersSearch" />
</div> </div>
<div <div
v-if="groupDialog.memberSearch.length" v-if="groupDialog.memberSearch.length"
class="flex flex-wrap items-start" class="flex flex-wrap items-start"
style="margin-top: 10px; overflow: auto; max-height: 250px; min-width: 130px"> style="margin-top: 8px; overflow: auto; max-height: 250px; min-width: 130px">
<div <div
v-for="user in groupDialog.memberSearchResults" v-for="user in groupDialog.memberSearchResults"
:key="user.id" :key="user.id"
@@ -977,7 +975,7 @@
v-if="user.isRepresenting" v-if="user.isRepresenting"
side="top" side="top"
:content="t('dialog.group.members.representing')"> :content="t('dialog.group.members.representing')">
<Tag style="margin-right: 5px" /> <Tag style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="user.visibility !== 'visible'" side="top"> <TooltipWrapper v-if="user.visibility !== 'visible'" side="top">
<template #content> <template #content>
@@ -986,13 +984,13 @@
{{ user.visibility }}</span {{ user.visibility }}</span
> >
</template> </template>
<Eye style="margin-right: 5px" /> <Eye style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper <TooltipWrapper
v-if="!user.isSubscribedToAnnouncements" v-if="!user.isSubscribedToAnnouncements"
side="top" side="top"
:content="t('dialog.group.members.unsubscribed_announcements')"> :content="t('dialog.group.members.unsubscribed_announcements')">
<MessageSquare style="margin-right: 5px" /> <MessageSquare style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="user.managerNotes" side="top"> <TooltipWrapper v-if="user.managerNotes" side="top">
<template #content> <template #content>
@@ -1000,7 +998,7 @@
<br /> <br />
<span>{{ user.managerNotes }}</span> <span>{{ user.managerNotes }}</span>
</template> </template>
<Pencil style="margin-right: 5px" /> <Pencil style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
</template> </template>
<template v-for="roleId in user.roleIds" :key="roleId"> <template v-for="roleId in user.roleIds" :key="roleId">
@@ -1017,7 +1015,7 @@
<ul <ul
v-else-if="groupDialog.members.length > 0" v-else-if="groupDialog.members.length > 0"
class="infinite-list flex flex-wrap items-start" class="infinite-list flex flex-wrap items-start"
style="margin-top: 10px; overflow: auto; max-height: 250px; min-width: 130px"> style="margin-top: 8px; overflow: auto; max-height: 250px; min-width: 130px">
<li <li
v-for="user in groupDialog.members" v-for="user in groupDialog.members"
:key="user.id" :key="user.id"
@@ -1040,7 +1038,7 @@
v-if="user.isRepresenting" v-if="user.isRepresenting"
side="top" side="top"
:content="t('dialog.group.members.representing')"> :content="t('dialog.group.members.representing')">
<Tag style="margin-right: 5px" /> <Tag style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="user.visibility !== 'visible'" side="top"> <TooltipWrapper v-if="user.visibility !== 'visible'" side="top">
<template #content> <template #content>
@@ -1049,13 +1047,13 @@
{{ user.visibility }}</span {{ user.visibility }}</span
> >
</template> </template>
<Eye style="margin-right: 5px" /> <Eye style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper <TooltipWrapper
v-if="!user.isSubscribedToAnnouncements" v-if="!user.isSubscribedToAnnouncements"
side="top" side="top"
:content="t('dialog.group.members.unsubscribed_announcements')"> :content="t('dialog.group.members.unsubscribed_announcements')">
<MessageSquare style="margin-right: 5px" /> <MessageSquare style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="user.managerNotes" side="top"> <TooltipWrapper v-if="user.managerNotes" side="top">
<template #content> <template #content>
@@ -1063,7 +1061,7 @@
<br /> <br />
<span>{{ user.managerNotes }}</span> <span>{{ user.managerNotes }}</span>
</template> </template>
<Pencil style="margin-right: 5px" /> <Pencil style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
</template> </template>
<template v-for="roleId in user.roleIds" :key="roleId"> <template v-for="roleId in user.roleIds" :key="roleId">
@@ -1110,8 +1108,8 @@
:key="`label-${index}`" :key="`label-${index}`"
v-slot:[`label-${index}`]> v-slot:[`label-${index}`]>
<span style="font-weight: bold; font-size: 16px" v-text="gallery.name" /> <span style="font-weight: bold; font-size: 16px" v-text="gallery.name" />
<i class="x-status-icon" style="margin-left: 5px" :class="groupGalleryStatus(gallery)" /> <i class="x-status-icon" style="margin-left: 6px" :class="groupGalleryStatus(gallery)" />
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{ <span style="color: #909399; font-size: 12px; margin-left: 6px">{{
groupDialog.galleries[gallery.id] ? groupDialog.galleries[gallery.id].length : 0 groupDialog.galleries[gallery.id] ? groupDialog.galleries[gallery.id].length : 0
}}</span> }}</span>
</template> </template>
@@ -1119,13 +1117,13 @@
v-for="(gallery, index) in groupDialog.ref.galleries" v-for="(gallery, index) in groupDialog.ref.galleries"
:key="`content-${index}`" :key="`content-${index}`"
v-slot:[String(index)]> v-slot:[String(index)]>
<span style="color: #c7c7c7; padding: 10px" v-text="gallery.description" /> <span style="color: #c7c7c7; padding: 8px" v-text="gallery.description" />
<div <div
style=" style="
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 15px; gap: 16px;
margin-top: 10px; margin-top: 8px;
max-height: 600px; max-height: 600px;
overflow-y: auto; overflow-y: auto;
"> ">
@@ -11,7 +11,7 @@
<DialogTitle>{{ t('dialog.group_member_moderation.export_bans') }}</DialogTitle> <DialogTitle>{{ t('dialog.group_member_moderation.export_bans') }}</DialogTitle>
</DialogHeader> </DialogHeader>
<div style="margin-bottom: 10px" class="flex flex-col gap-2"> <div class="flex flex-col gap-2 mb-2">
<label v-for="option in exportBansOptions" :key="option.label" class="inline-flex items-center gap-2"> <label v-for="option in exportBansOptions" :key="option.label" class="inline-flex items-center gap-2">
<Checkbox <Checkbox
:model-value="checkedExportBansOptions.includes(option.label)" :model-value="checkedExportBansOptions.includes(option.label)"
@@ -24,8 +24,7 @@
v-model="exportContent" v-model="exportContent"
:rows="15" :rows="15"
readonly readonly
style="margin-top: 15px" input-class="resize-none mt-4"
input-class="resize-none"
@click="handleCopyExportContent" /> @click="handleCopyExportContent" />
</DialogContent> </DialogContent>
</Dialog> </Dialog>
@@ -53,7 +53,7 @@
<Button size="sm" variant="secondary" @click="errors = ''"> <Button size="sm" variant="secondary" @click="errors = ''">
{{ t('dialog.group_member_moderation.import_bans_clear_errors') }} {{ t('dialog.group_member_moderation.import_bans_clear_errors') }}
</Button> </Button>
<pre style="white-space: pre-wrap; font-size: 12px; margin-top: 5px" v-text="errors"></pre> <pre class="mt-1.5" style="white-space: pre-wrap; font-size: 12px" v-text="errors"></pre>
</template> </template>
<template v-if="resultMessage"> <template v-if="resultMessage">
@@ -9,7 +9,7 @@
<h3>{{ groupMemberModeration.groupRef.name }}</h3> <h3>{{ groupMemberModeration.groupRef.name }}</h3>
<TabsUnderline default-value="members" :items="groupModerationTabs" :unmount-on-hide="false"> <TabsUnderline default-value="members" :items="groupModerationTabs" :unmount-on-hide="false">
<template #members> <template #members>
<div style="margin-top: 10px"> <div class="mt-2">
<Button <Button
class="rounded-full" class="rounded-full"
variant="outline" variant="outline"
@@ -19,13 +19,13 @@
<Spinner v-if="isGroupMembersLoading" /> <Spinner v-if="isGroupMembersLoading" />
<RefreshCw v-else /> <RefreshCw v-else />
</Button> </Button>
<span style="font-size: 14px; margin-left: 5px; margin-right: 5px"> <span class="ml-1.5 mr-1.5" style="font-size: 14px">
{{ groupMemberModerationTable.data.length }}/{{ {{ groupMemberModerationTable.data.length }}/{{
groupMemberModeration.groupRef.memberCount groupMemberModeration.groupRef.memberCount
}} }}
</span> </span>
<div style="float: right; margin-top: 5px"> <div class="mt-1.5" style="float: right">
<span style="margin-right: 5px">{{ t('dialog.group.members.sort_by') }}</span> <span class="mr-1.5">{{ t('dialog.group.members.sort_by') }}</span>
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger <DropdownMenuTrigger
as-child as-child
@@ -51,7 +51,7 @@
" "
@click.stop> @click.stop>
{{ t(memberSortOrder.name) }} {{ t(memberSortOrder.name) }}
<ArrowDown style="margin-left: 5px" /> <ArrowDown class="ml-1.5" />
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent> <DropdownMenuContent>
@@ -63,9 +63,7 @@
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
<span class="ml-2" style="margin-right: 5px">{{ <span class="ml-2 mr-1.5">{{ t('dialog.group.members.filter') }}</span>
t('dialog.group.members.filter')
}}</span>
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger <DropdownMenuTrigger
as-child as-child
@@ -91,7 +89,7 @@
" "
@click.stop> @click.stop>
{{ t(memberFilter.name) }} {{ t(memberFilter.name) }}
<ArrowDown style="margin-left: 5px" /> <ArrowDown class="ml-1.5" />
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent> <DropdownMenuContent>
@@ -117,14 +115,14 @@
clearable clearable
size="sm" size="sm"
:placeholder="t('dialog.group.members.search')" :placeholder="t('dialog.group.members.search')"
style="margin-top: 10px; margin-bottom: 10px" style="margin-top: 8px; margin-bottom: 8px"
@input="groupMembersSearch" /> @input="groupMembersSearch" />
<Button size="sm" variant="outline" @click="selectAll(groupMemberModerationTable.data)">{{ <Button size="sm" variant="outline" @click="selectAll(groupMemberModerationTable.data)">{{
t('dialog.group_member_moderation.select_all') t('dialog.group_member_moderation.select_all')
}}</Button> }}</Button>
<DataTableLayout <DataTableLayout
v-if="groupMemberModerationTable.data.length" v-if="groupMemberModerationTable.data.length"
style="margin-top: 10px" style="margin-top: 8px"
:table="groupMemberModerationTanstackTable" :table="groupMemberModerationTanstackTable"
:loading="isGroupMembersLoading" :loading="isGroupMembersLoading"
:page-sizes="pageSizes" :page-sizes="pageSizes"
@@ -133,7 +131,7 @@
</template> </template>
<template #bans> <template #bans>
<div style="margin-top: 10px"> <div style="margin-top: 8px">
<div class="flex justify-between"> <div class="flex justify-between">
<div class="flex gap-2 items-center"> <div class="flex gap-2 items-center">
<Button <Button
@@ -151,7 +149,7 @@
@click="selectAll(groupBansModerationTable.data)" @click="selectAll(groupBansModerationTable.data)"
>{{ t('dialog.group_member_moderation.select_all') }}</Button >{{ t('dialog.group_member_moderation.select_all') }}</Button
> >
<span style="font-size: 14px; margin-left: 5px; margin-right: 5px">{{ <span style="font-size: 14px; margin-left: 6px; margin-right: 6px">{{
groupBansModerationTable.data.length groupBansModerationTable.data.length
}}</span> }}</span>
</div> </div>
@@ -183,7 +181,7 @@
</div> </div>
<DataTableLayout <DataTableLayout
style="margin-top: 10px" style="margin-top: 8px"
:table="groupBansModerationTanstackTable" :table="groupBansModerationTanstackTable"
:loading="isGroupMembersLoading" :loading="isGroupMembersLoading"
:page-sizes="pageSizes" :page-sizes="pageSizes"
@@ -192,7 +190,7 @@
</template> </template>
<template #invites> <template #invites>
<div style="margin-top: 10px"> <div style="margin-top: 8px">
<Button <Button
class="rounded-full" class="rounded-full"
variant="outline" variant="outline"
@@ -208,7 +206,7 @@
<span style="font-weight: bold; font-size: 16px">{{ <span style="font-weight: bold; font-size: 16px">{{
t('dialog.group_member_moderation.sent_invites') t('dialog.group_member_moderation.sent_invites')
}}</span> }}</span>
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{ <span style="color: #909399; font-size: 12px; margin-left: 6px">{{
groupInvitesModerationTable.data.length groupInvitesModerationTable.data.length
}}</span> }}</span>
</template> </template>
@@ -216,7 +214,7 @@
<span style="font-weight: bold; font-size: 16px">{{ <span style="font-weight: bold; font-size: 16px">{{
t('dialog.group_member_moderation.join_requests') t('dialog.group_member_moderation.join_requests')
}}</span> }}</span>
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{ <span style="color: #909399; font-size: 12px; margin-left: 6px">{{
groupJoinRequestsModerationTable.data.length groupJoinRequestsModerationTable.data.length
}}</span> }}</span>
</template> </template>
@@ -224,7 +222,7 @@
<span style="font-weight: bold; font-size: 16px">{{ <span style="font-weight: bold; font-size: 16px">{{
t('dialog.group_member_moderation.blocked_requests') t('dialog.group_member_moderation.blocked_requests')
}}</span> }}</span>
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{ <span style="color: #909399; font-size: 12px; margin-left: 6px">{{
groupBlockedModerationTable.data.length groupBlockedModerationTable.data.length
}}</span> }}</span>
</template> </template>
@@ -236,7 +234,7 @@
>{{ t('dialog.group_member_moderation.select_all') }}</Button >{{ t('dialog.group_member_moderation.select_all') }}</Button
> >
<DataTableLayout <DataTableLayout
style="margin-top: 10px" style="margin-top: 8px"
:table="groupInvitesModerationTanstackTable" :table="groupInvitesModerationTanstackTable"
:loading="isGroupMembersLoading" :loading="isGroupMembersLoading"
:page-sizes="pageSizes" :page-sizes="pageSizes"
@@ -266,7 +264,7 @@
>{{ t('dialog.group_member_moderation.select_all') }}</Button >{{ t('dialog.group_member_moderation.select_all') }}</Button
> >
<DataTableLayout <DataTableLayout
style="margin-top: 10px" style="margin-top: 8px"
:table="groupJoinRequestsModerationTanstackTable" :table="groupJoinRequestsModerationTanstackTable"
:loading="isGroupMembersLoading" :loading="isGroupMembersLoading"
:page-sizes="pageSizes" :page-sizes="pageSizes"
@@ -326,7 +324,7 @@
>{{ t('dialog.group_member_moderation.select_all') }}</Button >{{ t('dialog.group_member_moderation.select_all') }}</Button
> >
<DataTableLayout <DataTableLayout
style="margin-top: 10px" style="margin-top: 8px"
:table="groupBlockedModerationTanstackTable" :table="groupBlockedModerationTanstackTable"
:loading="isGroupMembersLoading" :loading="isGroupMembersLoading"
:page-sizes="pageSizes" :page-sizes="pageSizes"
@@ -352,7 +350,7 @@
</template> </template>
<template #logs> <template #logs>
<div style="margin-top: 10px"> <div style="margin-top: 8px">
<Button <Button
class="rounded-full" class="rounded-full"
variant="outline" variant="outline"
@@ -362,14 +360,14 @@
<Spinner v-if="isGroupMembersLoading" /> <Spinner v-if="isGroupMembersLoading" />
<RefreshCw v-else /> <RefreshCw v-else />
</Button> </Button>
<span style="font-size: 14px; margin-left: 5px; margin-right: 5px">{{ <span style="font-size: 14px; margin-left: 6px; margin-right: 6px">{{
groupLogsModerationTable.data.length groupLogsModerationTable.data.length
}}</span> }}</span>
<br /> <br />
<div style="display: flex; justify-content: space-between; align-items: center"> <div style="display: flex; justify-content: space-between; align-items: center">
<div> <div>
<Select v-model="selectedAuditLogTypes" multiple> <Select v-model="selectedAuditLogTypes" multiple>
<SelectTrigger style="margin: 10px 0; width: 250px"> <SelectTrigger style="margin: 8px 0; width: 250px">
<SelectValue <SelectValue
:placeholder="t('dialog.group_member_moderation.filter_type')" /> :placeholder="t('dialog.group_member_moderation.filter_type')" />
</SelectTrigger> </SelectTrigger>
@@ -394,10 +392,10 @@
clearable clearable
size="sm" size="sm"
:placeholder="t('dialog.group.members.search')" :placeholder="t('dialog.group.members.search')"
style="margin-top: 10px; margin-bottom: 10px" /> style="margin-top: 8px; margin-bottom: 8px" />
<br /> <br />
<DataTableLayout <DataTableLayout
style="margin-top: 10px" style="margin-top: 8px"
:table="groupLogsModerationTanstackTable" :table="groupLogsModerationTanstackTable"
:loading="isGroupMembersLoading" :loading="isGroupMembersLoading"
:page-sizes="pageSizes" :page-sizes="pageSizes"
@@ -413,13 +411,13 @@
<InputGroupField <InputGroupField
v-model="selectUserId" v-model="selectUserId"
size="sm" size="sm"
style="margin-top: 5px" style="margin-top: 6px"
:placeholder="t('dialog.group_member_moderation.user_id_placeholder')" :placeholder="t('dialog.group_member_moderation.user_id_placeholder')"
clearable /> clearable />
<Button <Button
size="sm" size="sm"
variant="outline" variant="outline"
style="margin-top: 10px" style="margin-top: 8px"
:disabled="!selectUserId" :disabled="!selectUserId"
@click="selectGroupMemberUserId" @click="selectGroupMemberUserId"
>{{ t('dialog.group_member_moderation.select_user') }}</Button >{{ t('dialog.group_member_moderation.select_user') }}</Button
@@ -431,7 +429,7 @@
class="rounded-full" class="rounded-full"
size="icon-sm" size="icon-sm"
variant="outline" variant="outline"
style="margin-left: 5px" style="margin-left: 6px"
@click="clearAllSelected"> @click="clearAllSelected">
<Trash2 <Trash2
/></Button> /></Button>
@@ -440,7 +438,7 @@
v-for="user in selectedUsersArray" v-for="user in selectedUsersArray"
:key="user.id" :key="user.id"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
<TooltipWrapper v-if="user.membershipStatus !== 'member'" side="top"> <TooltipWrapper v-if="user.membershipStatus !== 'member'" side="top">
<template #content> <template #content>
<span>{{ t('dialog.group_member_moderation.user_isnt_in_group') }}</span> <span>{{ t('dialog.group_member_moderation.user_isnt_in_group') }}</span>
@@ -449,11 +447,11 @@
</TooltipWrapper> </TooltipWrapper>
<span <span
v-text="user.user?.displayName || user.userId" v-text="user.user?.displayName || user.userId"
style="font-weight: bold; margin-left: 5px"></span> style="font-weight: bold; margin-left: 6px"></span>
<button <button
type="button" type="button"
style=" style="
margin-left: 6px; margin-left: 8px;
border: none; border: none;
background: transparent; background: transparent;
padding: 0; padding: 0;
@@ -474,14 +472,14 @@
class="text-xs" class="text-xs"
:rows="2" :rows="2"
:placeholder="t('dialog.group_member_moderation.note_placeholder')" :placeholder="t('dialog.group_member_moderation.note_placeholder')"
style="margin-top: 5px" style="margin-top: 6px"
input-class="resize-none min-h-0" /> input-class="resize-none min-h-0" />
<br /> <br />
<br /> <br />
<span class="name">{{ t('dialog.group_member_moderation.selected_roles') }}</span> <span class="name">{{ t('dialog.group_member_moderation.selected_roles') }}</span>
<br /> <br />
<Select v-model="selectedRoles" multiple> <Select v-model="selectedRoles" multiple>
<SelectTrigger style="margin-top: 5px"> <SelectTrigger style="margin-top: 6px">
<SelectValue :placeholder="t('dialog.group_member_moderation.choose_roles_placeholder')" /> <SelectValue :placeholder="t('dialog.group_member_moderation.choose_roles_placeholder')" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -566,14 +564,14 @@
@click="handleUnban" @click="handleUnban"
>{{ t('dialog.group_member_moderation.unban') }}</Button >{{ t('dialog.group_member_moderation.unban') }}</Button
> >
<span v-if="progressCurrent" style="margin-top: 10px"> <span v-if="progressCurrent" style="margin-top: 8px">
<Spinner class="inline-block ml-2 mr-2" /> <Spinner class="inline-block ml-2 mr-2" />
{{ t('dialog.group_member_moderation.progress') }} {{ progressCurrent }}/{{ progressTotal }} {{ t('dialog.group_member_moderation.progress') }} {{ progressCurrent }}/{{ progressTotal }}
</span> </span>
<Button <Button
variant="secondary" variant="secondary"
v-if="progressCurrent" v-if="progressCurrent"
style="margin-left: 5px" style="margin-left: 6px"
@click="progressTotal = 0" @click="progressTotal = 0"
>{{ t('dialog.group_member_moderation.cancel') }}</Button >{{ t('dialog.group_member_moderation.cancel') }}</Button
> >
@@ -11,7 +11,7 @@
<DialogTitle>{{ t('dialog.group_member_moderation.export_logs') }}</DialogTitle> <DialogTitle>{{ t('dialog.group_member_moderation.export_logs') }}</DialogTitle>
</DialogHeader> </DialogHeader>
<div style="margin-bottom: 10px" class="flex flex-col gap-2"> <div class="flex flex-col gap-2 mb-2">
<label <label
v-for="option in checkGroupsLogsExportLogsOptions" v-for="option in checkGroupsLogsExportLogsOptions"
:key="option.label" :key="option.label"
@@ -27,8 +27,7 @@
v-model="groupLogsExportContent" v-model="groupLogsExportContent"
:rows="15" :rows="15"
readonly readonly
style="margin-top: 15px" input-class="resize-none mt-4"
input-class="resize-none"
@click="handleCopyGroupLogsExportContent" /> @click="handleCopyGroupLogsExportContent" />
</DialogContent> </DialogContent>
</Dialog> </Dialog>
@@ -19,8 +19,7 @@
<InputGroupTextareaField <InputGroupTextareaField
v-model="groupPostEditDialog.text" v-model="groupPostEditDialog.text"
:rows="4" :rows="4"
style="margin-top: 10px" input-class="resize-none mt-2" />
input-class="resize-none" />
</FieldContent> </FieldContent>
</Field> </Field>
<Field v-if="!groupPostEditDialog.postId"> <Field v-if="!groupPostEditDialog.postId">
@@ -84,7 +83,7 @@
<FieldLabel>{{ t('dialog.group_post_edit.image') }}</FieldLabel> <FieldLabel>{{ t('dialog.group_post_edit.image') }}</FieldLabel>
<FieldContent> <FieldContent>
<template v-if="gallerySelectDialog.selectedFileId"> <template v-if="gallerySelectDialog.selectedFileId">
<div style="display: inline-block; flex: none; margin-right: 5px"> <div class="mr-1.5" style="display: inline-block; flex: none">
<img <img
:src="gallerySelectDialog.selectedImageUrl" :src="gallerySelectDialog.selectedImageUrl"
style=" style="
@@ -195,16 +194,26 @@
return names.slice(0, 3).join(', ') + (names.length > 3 ? ` +${names.length - 3}` : ''); return names.slice(0, 3).join(', ') + (names.length > 3 ? ` +${names.length - 3}` : '');
}); });
/**
*
* @param value
*/
function handleRoleIdsChange(value) { function handleRoleIdsChange(value) {
const next = Array.isArray(value) ? value.map((v) => String(v ?? '')).filter(Boolean) : []; const next = Array.isArray(value) ? value.map((v) => String(v ?? '')).filter(Boolean) : [];
groupPostEditDialog.value.roleIds = next; groupPostEditDialog.value.roleIds = next;
} }
/**
*
*/
function showGallerySelectDialog() { function showGallerySelectDialog() {
const D = gallerySelectDialog.value; const D = gallerySelectDialog.value;
D.visible = true; D.visible = true;
refreshGalleryTable(); refreshGalleryTable();
} }
/**
*
*/
async function refreshGalleryTable() { async function refreshGalleryTable() {
const params = { const params = {
n: 100, n: 100,
@@ -216,6 +225,9 @@
galleryTable.value = args.json.reverse(); galleryTable.value = args.json.reverse();
} }
} }
/**
*
*/
function editGroupPost() { function editGroupPost() {
const D = groupPostEditDialog.value; const D = groupPostEditDialog.value;
if (!D.groupId || !D.postId) { if (!D.groupId || !D.postId) {
@@ -243,6 +255,9 @@
}); });
D.visible = false; D.visible = false;
} }
/**
*
*/
function createGroupPost() { function createGroupPost() {
const D = groupPostEditDialog.value; const D = groupPostEditDialog.value;
if (!D.title || !D.text) { if (!D.title || !D.text) {
@@ -267,6 +282,9 @@
}); });
D.visible = false; D.visible = false;
} }
/**
*
*/
function clearImageGallerySelect() { function clearImageGallerySelect() {
const D = gallerySelectDialog.value; const D = gallerySelectDialog.value;
D.selectedFileId = ''; D.selectedFileId = '';
@@ -14,28 +14,27 @@
<div v-if="inviteDialog.visible" class="overflow-hidden"> <div v-if="inviteDialog.visible" class="overflow-hidden">
<Location :location="inviteDialog.worldId" :link="false" class="cursor-default" /> <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 mt-2" variant="outline" @click="addSelfToInvite">{{
t('dialog.invite.add_self') t('dialog.invite.add_self')
}}</Button> }}</Button>
<Button <Button
size="sm" size="sm"
class="mr-2" class="mr-2 mt-2"
variant="outline" variant="outline"
:disabled="inviteDialog.friendsInInstance.length === 0" :disabled="inviteDialog.friendsInInstance.length === 0"
style="margin-top: 10px"
@click="addFriendsInInstanceToInvite" @click="addFriendsInInstanceToInvite"
>{{ t('dialog.invite.add_friends_in_instance') }}</Button >{{ t('dialog.invite.add_friends_in_instance') }}</Button
> >
<Button <Button
class="mt-2"
size="sm" size="sm"
variant="outline" variant="outline"
:disabled="vipFriends.length === 0" :disabled="vipFriends.length === 0"
style="margin-top: 10px"
@click="addFavoriteFriendsToInvite" @click="addFavoriteFriendsToInvite"
>{{ t('dialog.invite.add_favorite_friends') }}</Button >{{ t('dialog.invite.add_favorite_friends') }}</Button
> >
<div style="width: 100%; margin-top: 15px"> <div class="mt-4" style="width: 100%">
<VirtualCombobox <VirtualCombobox
:model-value="Array.isArray(inviteDialog.userIds) ? inviteDialog.userIds : []" :model-value="Array.isArray(inviteDialog.userIds) ? inviteDialog.userIds : []"
@update:modelValue="setInviteUserIds" @update:modelValue="setInviteUserIds"
@@ -13,7 +13,7 @@
<template v-if="isLocalUserVrcPlusSupporter"> <template v-if="isLocalUserVrcPlusSupporter">
<!-- <template v-if="gallerySelectDialog.selectedFileId">--> <!-- <template v-if="gallerySelectDialog.selectedFileId">-->
<!-- <div style="display: inline-block; flex: none; margin-right: 5px">--> <!-- <div class="mr-1.5" style="display: inline-block; flex: none">-->
<!-- <el-popover placement="right" :width="500px" trigger="click">--> <!-- <el-popover placement="right" :width="500px" trigger="click">-->
<!-- <template #reference>--> <!-- <template #reference>-->
<!-- <img--> <!-- <img-->
@@ -33,7 +33,7 @@
<!-- </el-button>--> <!-- </el-button>-->
<!-- </template>--> <!-- </template>-->
<!-- <template v-else>--> <!-- <template v-else>-->
<!-- <el-button size="small" @click="showGallerySelectDialog" style="margin-right: 5px">--> <!-- <el-button size="small" @click="showGallerySelectDialog" style="margin-right: 6px">-->
<!-- {{ t('dialog.invite_message.select_image') }}--> <!-- {{ t('dialog.invite_message.select_image') }}-->
<!-- </el-button>--> <!-- </el-button>-->
<!-- </template>--> <!-- </template>-->
@@ -41,7 +41,7 @@
</template> </template>
<DataTableLayout <DataTableLayout
style="margin-top: 10px" style="margin-top: 8px"
:table="inviteMessageTanstackTable" :table="inviteMessageTanstackTable"
:loading="false" :loading="false"
:show-pagination="false" :show-pagination="false"
@@ -137,15 +137,27 @@
initialSorting: [{ id: 'slot', desc: false }] initialSorting: [{ id: 'slot', desc: false }]
}); });
/**
*
* @param row
*/
function handleInviteMessageRowClick(row) { function handleInviteMessageRowClick(row) {
showSendInviteConfirmDialog(row?.original); showSendInviteConfirmDialog(row?.original);
} }
/**
*
* @param row
*/
function showSendInviteConfirmDialog(row) { function showSendInviteConfirmDialog(row) {
emit('update:sendInviteDialog', { ...props.sendInviteDialog, messageSlot: row }); emit('update:sendInviteDialog', { ...props.sendInviteDialog, messageSlot: row });
isSendInviteConfirmDialogVisible.value = true; isSendInviteConfirmDialogVisible.value = true;
} }
/**
*
* @param row
*/
function showEditAndSendInviteDialog(row) { function showEditAndSendInviteDialog(row) {
emit('update:sendInviteDialog', { ...props.sendInviteDialog, messageSlot: row }); emit('update:sendInviteDialog', { ...props.sendInviteDialog, messageSlot: row });
editAndSendInviteDialog.value = { editAndSendInviteDialog.value = {
@@ -154,10 +166,16 @@
}; };
} }
/**
*
*/
function cancelSendInvite() { function cancelSendInvite() {
emit('update:sendInviteDialogVisible', false); emit('update:sendInviteDialogVisible', false);
} }
/**
*
*/
function closeInviteDialog() { function closeInviteDialog() {
cancelSendInvite(); cancelSendInvite();
emit('closeInviteDialog'); emit('closeInviteDialog');
+2 -2
View File
@@ -9,7 +9,7 @@
<span>{{ t('dialog.invite_to_group.description') }}</span> <span>{{ t('dialog.invite_to_group.description') }}</span>
<br /> <br />
<div style="margin-top: 15px; width: 100%"> <div class="mt-4" style="width: 100%">
<VirtualCombobox <VirtualCombobox
v-model="inviteGroupDialog.groupId" v-model="inviteGroupDialog.groupId"
:groups="groupPickerGroups" :groups="groupPickerGroups"
@@ -36,7 +36,7 @@
</VirtualCombobox> </VirtualCombobox>
</div> </div>
<div style="width: 100%; margin-top: 15px"> <div style="width: 100%; margin-top: 16px">
<VirtualCombobox <VirtualCombobox
v-model="inviteGroupDialog.userIds" v-model="inviteGroupDialog.userIds"
:groups="friendPickerGroups" :groups="friendPickerGroups"
@@ -23,7 +23,7 @@
</div> </div>
</div> </div>
<div style="margin-top: 15px; width: 100%"> <div class="mt-4" style="width: 100%">
<VirtualCombobox <VirtualCombobox
:model-value="moderateGroupDialog.groupId" :model-value="moderateGroupDialog.groupId"
@update:modelValue="setGroupId" @update:modelValue="setGroupId"
+16 -2
View File
@@ -28,8 +28,8 @@
style=" style="
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
gap: 5px; gap: 6px;
margin-top: 10px; margin-top: 8px;
max-height: 600px; max-height: 600px;
overflow-y: auto; overflow-y: auto;
"> ">
@@ -109,6 +109,9 @@
} }
); );
/**
*
*/
function closeDialog() { function closeDialog() {
sendBoopDialog.value.visible = false; sendBoopDialog.value.visible = false;
} }
@@ -120,6 +123,10 @@
} }
}); });
/**
*
* @param emojiName
*/
function getEmojiValue(emojiName) { function getEmojiValue(emojiName) {
if (!emojiName) { if (!emojiName) {
return ''; return '';
@@ -139,6 +146,9 @@
} }
]); ]);
/**
*
*/
function sendBoop() { function sendBoop() {
const D = sendBoopDialog.value; const D = sendBoopDialog.value;
dismissBoop(D.userId); dismissBoop(D.userId);
@@ -152,6 +162,10 @@
D.visible = false; D.visible = false;
} }
/**
*
* @param userId
*/
function dismissBoop(userId) { function dismissBoop(userId) {
// JANK: This is a hack to remove boop notifications when responding // JANK: This is a hack to remove boop notifications when responding
const array = notificationTable.value.data; const array = notificationTable.value.data;
@@ -16,13 +16,13 @@
autosize /> autosize />
<InputGroupAction <InputGroupAction
class="mt-1.5"
v-for="(link, index) in bioDialog.bioLinks" v-for="(link, index) in bioDialog.bioLinks"
:key="index" :key="index"
v-model="bioDialog.bioLinks[index]" v-model="bioDialog.bioLinks[index]"
:maxlength="1000" :maxlength="1000"
show-count show-count
size="sm" size="sm">
style="margin-top: 5px">
<template #leading> <template #leading>
<img :src="getFaviconUrl(link)" style="width: 16px; height: 16px; vertical-align: middle" /> <img :src="getFaviconUrl(link)" style="width: 16px; height: 16px; vertical-align: middle" />
</template> </template>
@@ -71,6 +71,9 @@
} }
}); });
/**
*
*/
function saveBio() { function saveBio() {
const D = props.bioDialog; const D = props.bioDialog;
if (D.loading) { if (D.loading) {
@@ -6,20 +6,19 @@
</DialogHeader> </DialogHeader>
<div> <div>
<div v-for="item in currentUser.$languages" :key="item.key" style="margin: 6px 0"> <div class="my-2 mx-0" v-for="item in currentUser.$languages" :key="item.key">
<Badge variant="outline" style="margin-right: 5px"> <Badge class="mr-1.5" variant="outline">
<span <span
class="flags" class="flags mr-1.5"
:class="languageClass(item.key)" :class="languageClass(item.key)"
style="display: inline-block; margin-right: 5px"></span> style="display: inline-block"></span>
{{ item.value }} ({{ item.key.toUpperCase() }}) {{ item.value }} ({{ item.key.toUpperCase() }})
<button <button
class="ml-2 p-0"
type="button" type="button"
style=" style="
margin-left: 6px;
border: none; border: none;
background: transparent; background: transparent;
padding: 0;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
color: inherit; color: inherit;
@@ -36,7 +35,7 @@
languageDialog.loading || (currentUser.$languages && currentUser.$languages.length === 3) languageDialog.loading || (currentUser.$languages && currentUser.$languages.length === 3)
" "
@update:modelValue="handleAddUserLanguage"> @update:modelValue="handleAddUserLanguage">
<SelectTrigger size="sm" style="margin-top: 14px"> <SelectTrigger class="mt-3.5" size="sm">
<SelectValue :placeholder="t('dialog.language.select_language')" /> <SelectValue :placeholder="t('dialog.language.select_language')" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -47,9 +46,9 @@
:value="item.key" :value="item.key"
:text-value="item.value"> :text-value="item.value">
<span <span
class="flags" class="flags mr-1.5"
:class="languageClass(item.key)" :class="languageClass(item.key)"
style="display: inline-block; margin-right: 5px"></span> style="display: inline-block"></span>
{{ item.value }} ({{ item.key.toUpperCase() }}) {{ item.value }} ({{ item.key.toUpperCase() }})
</SelectItem> </SelectItem>
</SelectGroup> </SelectGroup>
@@ -79,11 +78,19 @@
const selectedLanguageToAdd = ref(''); const selectedLanguageToAdd = ref('');
/**
*
* @param language
*/
function handleAddUserLanguage(language) { function handleAddUserLanguage(language) {
addUserLanguage(language); addUserLanguage(language);
selectedLanguageToAdd.value = ''; selectedLanguageToAdd.value = '';
} }
/**
*
* @param language
*/
function removeUserLanguage(language) { function removeUserLanguage(language) {
if (language !== String(language)) { if (language !== String(language)) {
return; return;
@@ -99,6 +106,10 @@
}); });
} }
/**
*
* @param language
*/
function addUserLanguage(language) { function addUserLanguage(language) {
if (language !== String(language)) { if (language !== String(language)) {
return; return;
@@ -16,7 +16,7 @@
</template> </template>
<DataTableLayout <DataTableLayout
style="margin-top: 10px" style="margin-top: 8px"
:table="inviteRequestMessageTanstackTable" :table="inviteRequestMessageTanstackTable"
:loading="false" :loading="false"
:show-pagination="false" :show-pagination="false"
@@ -114,15 +114,27 @@
initialSorting: [{ id: 'slot', desc: false }] initialSorting: [{ id: 'slot', desc: false }]
}); });
/**
*
* @param row
*/
function handleInviteRequestMessageRowClick(row) { function handleInviteRequestMessageRowClick(row) {
showSendInviteConfirmDialog(row?.original); showSendInviteConfirmDialog(row?.original);
} }
/**
*
* @param row
*/
function showSendInviteConfirmDialog(row) { function showSendInviteConfirmDialog(row) {
emit('update:sendInviteDialog', { ...props.sendInviteDialog, messageSlot: row }); emit('update:sendInviteDialog', { ...props.sendInviteDialog, messageSlot: row });
isSendInviteConfirmDialogVisible.value = true; isSendInviteConfirmDialogVisible.value = true;
} }
/**
*
* @param row
*/
function showEditAndSendInviteDialog(row) { function showEditAndSendInviteDialog(row) {
emit('update:sendInviteDialog', { ...props.sendInviteDialog, messageSlot: row }); emit('update:sendInviteDialog', { ...props.sendInviteDialog, messageSlot: row });
editAndSendInviteDialog.value = { editAndSendInviteDialog.value = {
@@ -130,10 +142,16 @@
visible: true visible: true
}; };
} }
/**
*
*/
function cancelSendInviteRequest() { function cancelSendInviteRequest() {
emit('update:sendInviteRequestDialogVisible', false); emit('update:sendInviteRequestDialogVisible', false);
} }
/**
*
*/
function closeInviteDialog() { function closeInviteDialog() {
cancelSendInviteRequest(); cancelSendInviteRequest();
} }
@@ -21,14 +21,9 @@
<template #Info> <template #Info>
<template v-if="isFriendOnline(userDialog.friend) || currentUser.id === userDialog.id"> <template v-if="isFriendOnline(userDialog.friend) || currentUser.id === userDialog.id">
<div <div
class="mb-2 pb-2"
v-if="userDialog.ref.location" v-if="userDialog.ref.location"
style=" style="display: flex; flex-direction: column; border-bottom: 1px solid #e4e7ed14">
display: flex;
flex-direction: column;
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #e4e7ed14;
">
<div style="flex: none"> <div style="flex: none">
<template v-if="isRealInstance(userDialog.$location.tag)"> <template v-if="isRealInstance(userDialog.$location.tag)">
<InstanceActionBar <InstanceActionBar
@@ -48,7 +43,7 @@
</div> </div>
<div <div
class="flex flex-wrap items-start" class="flex flex-wrap items-start"
style="flex: 1; margin-top: 10px; max-height: 150px; overflow: auto"> style="flex: 1; margin-top: 8px; max-height: 150px; overflow: auto">
<div <div
v-if="userDialog.$location.userId" v-if="userDialog.$location.userId"
class="box-border flex items-center p-1.5 text-[13px] cursor-pointer w-[167px] hover:rounded-[25px_5px_5px_25px]" class="box-border flex items-center p-1.5 text-[13px] cursor-pointer w-[167px] hover:rounded-[25px_5px_5px_25px]"
@@ -177,7 +172,7 @@
</div> </div>
<div class="box-border flex items-center p-1.5 text-[13px] w-full cursor-default"> <div class="box-border flex items-center p-1.5 text-[13px] w-full cursor-default">
<div class="flex-1 overflow-hidden"> <div class="flex-1 overflow-hidden">
<span class="block truncate font-medium leading-[18px]" style="margin-bottom: 5px">{{ <span class="block truncate font-medium leading-[18px]" style="margin-bottom: 6px">{{
t('dialog.user.info.represented_group') t('dialog.user.info.represented_group')
}}</span> }}</span>
<div <div
@@ -186,7 +181,7 @@
(userDialog.representedGroup && userDialog.representedGroup.isRepresenting) (userDialog.representedGroup && userDialog.representedGroup.isRepresenting)
" "
class="text-xs"> class="text-xs">
<div style="display: inline-block; flex: none; margin-right: 5px"> <div style="display: inline-block; flex: none; margin-right: 6px">
<Avatar <Avatar
class="cursor-pointer size-15! rounded-lg!" class="cursor-pointer size-15! rounded-lg!"
:style="{ :style="{
@@ -206,10 +201,10 @@
@click="showGroupDialog(userDialog.representedGroup.groupId)"> @click="showGroupDialog(userDialog.representedGroup.groupId)">
<span <span
v-if="userDialog.representedGroup.ownerId === userDialog.id" v-if="userDialog.representedGroup.ownerId === userDialog.id"
style="margin-right: 5px" style="margin-right: 6px"
>👑</span >👑</span
> >
<span style="margin-right: 5px" v-text="userDialog.representedGroup.name"></span> <span style="margin-right: 6px" v-text="userDialog.representedGroup.name"></span>
<span>({{ userDialog.representedGroup.memberCount }})</span> <span>({{ userDialog.representedGroup.memberCount }})</span>
</span> </span>
</div> </div>
@@ -248,12 +243,12 @@
size="icon-sm" size="icon-sm"
variant="ghost" variant="ghost"
v-if="userDialog.id === currentUser.id" v-if="userDialog.id === currentUser.id"
style="margin-left: 5px; padding: 0" style="margin-left: 6px; padding: 0"
@click="showBioDialog" @click="showBioDialog"
><Pencil class="h-3 w-3" /> ><Pencil class="h-3 w-3" />
</Button> </Button>
</div> </div>
<div style="margin-top: 5px" class="flex items-center"> <div style="margin-top: 6px" class="flex items-center">
<TooltipWrapper v-for="(link, index) in userDialog.ref.bioLinks" :key="index"> <TooltipWrapper v-for="(link, index) in userDialog.ref.bioLinks" :key="index">
<template #content> <template #content>
<span v-text="link"></span> <span v-text="link"></span>
@@ -265,7 +260,7 @@
width: 16px; width: 16px;
height: 16px; height: 16px;
vertical-align: middle; vertical-align: middle;
margin-right: 5px; margin-right: 6px;
cursor: pointer; cursor: pointer;
" "
@click.stop="openExternalLink(link)" @click.stop="openExternalLink(link)"
@@ -570,12 +565,12 @@
<Spinner v-if="userDialog.isMutualFriendsLoading" /> <Spinner v-if="userDialog.isMutualFriendsLoading" />
<RefreshCw v-else /> <RefreshCw v-else />
</Button> </Button>
<span style="margin-left: 5px">{{ <span style="margin-left: 6px">{{
t('dialog.user.groups.total_count', { count: userDialog.mutualFriends.length }) t('dialog.user.groups.total_count', { count: userDialog.mutualFriends.length })
}}</span> }}</span>
</div> </div>
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
<span style="margin-right: 5px">{{ t('dialog.user.groups.sort_by') }}</span> <span style="margin-right: 6px">{{ t('dialog.user.groups.sort_by') }}</span>
<Select <Select
:model-value="userDialogMutualFriendSortingKey" :model-value="userDialogMutualFriendSortingKey"
:disabled="userDialog.isMutualFriendsLoading" :disabled="userDialog.isMutualFriendsLoading"
@@ -596,7 +591,7 @@
</div> </div>
<ul <ul
class="flex flex-wrap items-start" class="flex flex-wrap items-start"
style="margin-top: 10px; overflow: auto; max-height: 250px; min-width: 130px"> style="margin-top: 8px; overflow: auto; max-height: 250px; min-width: 130px">
<li <li
v-for="user in userDialog.mutualFriends" v-for="user in userDialog.mutualFriends"
:key="user.id" :key="user.id"
@@ -627,13 +622,13 @@
<Spinner v-if="userDialog.isGroupsLoading" /> <Spinner v-if="userDialog.isGroupsLoading" />
<RefreshCw v-else /> <RefreshCw v-else />
</Button> </Button>
<span style="margin-left: 5px">{{ <span style="margin-left: 6px">{{
t('dialog.user.groups.total_count', { count: userDialog.userGroups.groups.length }) t('dialog.user.groups.total_count', { count: userDialog.userGroups.groups.length })
}}</span> }}</span>
<template v-if="userDialogGroupEditMode"> <template v-if="userDialogGroupEditMode">
<span <span
style=" style="
margin-left: 10px; margin-left: 8px;
font-size: 10px; font-size: 10px;
" "
@@ -643,7 +638,7 @@
</div> </div>
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
<template v-if="!userDialogGroupEditMode"> <template v-if="!userDialogGroupEditMode">
<span style="margin-right: 5px">{{ t('dialog.user.groups.sort_by') }}</span> <span style="margin-right: 6px">{{ t('dialog.user.groups.sort_by') }}</span>
<Select <Select
:model-value="userDialogGroupSortingKey" :model-value="userDialogGroupSortingKey"
:disabled="userDialog.isGroupsLoading" :disabled="userDialog.isGroupsLoading"
@@ -682,14 +677,14 @@
</Button> </Button>
</div> </div>
</div> </div>
<div style="margin-top: 10px"> <div style="margin-top: 8px">
<template v-if="userDialogGroupEditMode"> <template v-if="userDialogGroupEditMode">
<div <div
class="flex flex-wrap items-start" class="flex flex-wrap items-start"
style="margin-top: 10px; margin-bottom: 15px; max-height: unset"> style="margin-top: 8px; margin-bottom: 16px; max-height: unset">
<!-- Bulk actions dropdown (shown only in edit mode) --> <!-- Bulk actions dropdown (shown only in edit mode) -->
<Select :model-value="bulkGroupActionValue" @update:modelValue="handleBulkGroupAction"> <Select :model-value="bulkGroupActionValue" @update:modelValue="handleBulkGroupAction">
<SelectTrigger size="sm" style="margin-right: 5px; margin-bottom: 5px" @click.stop> <SelectTrigger size="sm" style="margin-right: 6px; margin-bottom: 6px" @click.stop>
<SelectValue :placeholder="t('dialog.group.actions.manage_selected')" /> <SelectValue :placeholder="t('dialog.group.actions.manage_selected')" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -712,7 +707,7 @@
<Button <Button
size="sm" size="sm"
variant="outline" variant="outline"
style="padding: 7px 15px; margin-bottom: 5px" style="padding: 7px 16px; margin-bottom: 6px"
@click="selectAllGroups"> @click="selectAllGroups">
{{ {{
userDialogGroupAllSelected userDialogGroupAllSelected
@@ -729,8 +724,8 @@
<!-- Manual checkbox --> <!-- Manual checkbox -->
<div <div
style=" style="
margin-left: 5px; margin-left: 6px;
margin-right: 5px; margin-right: 6px;
transform: scale(0.8); transform: scale(0.8);
transform-origin: left center; transform-origin: left center;
" "
@@ -740,7 +735,7 @@
@update:modelValue="() => toggleGroupSelection(group.id)" /> @update:modelValue="() => toggleGroupSelection(group.id)" />
</div> </div>
<div style="margin-right: 3px; margin-left: 5px" @click.stop> <div style="margin-right: 3px; margin-left: 6px" @click.stop>
<Button <Button
size="icon-sm" size="icon-sm"
variant="ghost" variant="ghost"
@@ -762,7 +757,7 @@
<DownloadIcon /> <DownloadIcon />
</Button> </Button>
</div> </div>
<div style="margin-right: 10px" @click.stop> <div style="margin-right: 8px" @click.stop>
<Button <Button
size="icon-sm" size="icon-sm"
variant="outline" variant="outline"
@@ -791,7 +786,7 @@
v-if="group.isRepresenting" v-if="group.isRepresenting"
side="top" side="top"
:content="t('dialog.group.members.representing')"> :content="t('dialog.group.members.representing')">
<Tag style="margin-right: 5px" /> <Tag style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="group.myMember?.visibility !== 'visible'" side="top"> <TooltipWrapper v-if="group.myMember?.visibility !== 'visible'" side="top">
<template #content> <template #content>
@@ -800,7 +795,7 @@
{{ group.myMember.visibility }}</span {{ group.myMember.visibility }}</span
> >
</template> </template>
<Eye style="margin-right: 5px" /> <Eye style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<span>({{ group.memberCount }})</span> <span>({{ group.memberCount }})</span>
</span> </span>
@@ -840,11 +835,11 @@
setGroupSubscription(group.id, !group.myMember.isSubscribedToAnnouncements) setGroupSubscription(group.id, !group.myMember.isSubscribedToAnnouncements)
"> ">
<span v-if="group.myMember.isSubscribedToAnnouncements" <span v-if="group.myMember.isSubscribedToAnnouncements"
><BellOff style="margin-left: 5px" /> ><BellOff style="margin-left: 6px" />
{{ t('dialog.group.tags.subscribed') }}</span {{ t('dialog.group.tags.subscribed') }}</span
> >
<span v-else <span v-else
><Bell style="margin-left: 5px" /> ><Bell style="margin-left: 6px" />
{{ t('dialog.group.tags.unsubscribed') }}</span {{ t('dialog.group.tags.unsubscribed') }}</span
> >
</Button> --> </Button> -->
@@ -854,7 +849,7 @@
size="icon-sm" size="icon-sm"
variant="outline" variant="outline"
v-if="shiftHeld" v-if="shiftHeld"
style="margin-left: 5px" style="margin-left: 6px"
@click.stop="leaveGroup(group.id)"> @click.stop="leaveGroup(group.id)">
<LogOut /> <LogOut />
</Button> </Button>
@@ -863,7 +858,7 @@
size="icon-sm" size="icon-sm"
variant="outline" variant="outline"
v-else v-else
style="margin-left: 5px" style="margin-left: 6px"
@click.stop="leaveGroupPrompt(group.id)"> @click.stop="leaveGroupPrompt(group.id)">
<LogOut /> <LogOut />
</Button> </Button>
@@ -876,7 +871,7 @@
<span style="font-weight: bold; font-size: 16px">{{ <span style="font-weight: bold; font-size: 16px">{{
t('dialog.user.groups.own_groups') t('dialog.user.groups.own_groups')
}}</span> }}</span>
<span style="font-size: 12px; margin-left: 5px" <span style="font-size: 12px; margin-left: 6px"
>{{ userDialog.userGroups.ownGroups.length }}/{{ >{{ userDialog.userGroups.ownGroups.length }}/{{
// @ts-ignore // @ts-ignore
cachedConfig?.constants?.GROUPS?.MAX_OWNED cachedConfig?.constants?.GROUPS?.MAX_OWNED
@@ -884,7 +879,7 @@
> >
<div <div
class="flex flex-wrap items-start" class="flex flex-wrap items-start"
style="margin-top: 10px; margin-bottom: 15px; min-height: 60px"> style="margin-top: 8px; margin-bottom: 16px; min-height: 60px">
<div <div
v-for="group in userDialog.userGroups.ownGroups" v-for="group in userDialog.userGroups.ownGroups"
:key="group.id" :key="group.id"
@@ -905,7 +900,7 @@
v-if="group.isRepresenting" v-if="group.isRepresenting"
side="top" side="top"
:content="t('dialog.group.members.representing')"> :content="t('dialog.group.members.representing')">
<Tag style="margin-right: 5px" /> <Tag style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="group.memberVisibility !== 'visible'" side="top"> <TooltipWrapper v-if="group.memberVisibility !== 'visible'" side="top">
<template #content> <template #content>
@@ -914,7 +909,7 @@
{{ group.memberVisibility }}</span {{ group.memberVisibility }}</span
> >
</template> </template>
<Eye style="margin-right: 5px" /> <Eye style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<span>({{ group.memberCount }})</span> <span>({{ group.memberCount }})</span>
</span> </span>
@@ -926,12 +921,12 @@
<span style="font-weight: bold; font-size: 16px">{{ <span style="font-weight: bold; font-size: 16px">{{
t('dialog.user.groups.mutual_groups') t('dialog.user.groups.mutual_groups')
}}</span> }}</span>
<span style="font-size: 12px; margin-left: 5px">{{ <span style="font-size: 12px; margin-left: 6px">{{
userDialog.userGroups.mutualGroups.length userDialog.userGroups.mutualGroups.length
}}</span> }}</span>
<div <div
class="flex flex-wrap items-start" class="flex flex-wrap items-start"
style="margin-top: 10px; margin-bottom: 15px; min-height: 60px"> style="margin-top: 8px; margin-bottom: 16px; min-height: 60px">
<div <div
v-for="group in userDialog.userGroups.mutualGroups" v-for="group in userDialog.userGroups.mutualGroups"
:key="group.id" :key="group.id"
@@ -952,7 +947,7 @@
v-if="group.isRepresenting" v-if="group.isRepresenting"
side="top" side="top"
:content="t('dialog.group.members.representing')"> :content="t('dialog.group.members.representing')">
<Tag style="margin-right: 5px" /> <Tag style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="group.memberVisibility !== 'visible'" side="top"> <TooltipWrapper v-if="group.memberVisibility !== 'visible'" side="top">
<template #content> <template #content>
@@ -961,7 +956,7 @@
{{ group.memberVisibility }}</span {{ group.memberVisibility }}</span
> >
</template> </template>
<Eye style="margin-right: 5px" /> <Eye style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<span>({{ group.memberCount }})</span> <span>({{ group.memberCount }})</span>
</span> </span>
@@ -971,7 +966,7 @@
</template> </template>
<template v-if="userDialog.userGroups.remainingGroups.length > 0"> <template v-if="userDialog.userGroups.remainingGroups.length > 0">
<span style="font-weight: bold; font-size: 16px">{{ t('dialog.user.groups.groups') }}</span> <span style="font-weight: bold; font-size: 16px">{{ t('dialog.user.groups.groups') }}</span>
<span style="font-size: 12px; margin-left: 5px"> <span style="font-size: 12px; margin-left: 6px">
{{ userDialog.userGroups.remainingGroups.length }} {{ userDialog.userGroups.remainingGroups.length }}
<template v-if="currentUser.id === userDialog.id"> <template v-if="currentUser.id === userDialog.id">
/ /
@@ -985,7 +980,7 @@
</span> </span>
<div <div
class="flex flex-wrap items-start" class="flex flex-wrap items-start"
style="margin-top: 10px; margin-bottom: 15px; min-height: 60px"> style="margin-top: 8px; margin-bottom: 16px; min-height: 60px">
<div <div
v-for="group in userDialog.userGroups.remainingGroups" v-for="group in userDialog.userGroups.remainingGroups"
:key="group.id" :key="group.id"
@@ -1006,7 +1001,7 @@
v-if="group.isRepresenting" v-if="group.isRepresenting"
side="top" side="top"
:content="t('dialog.group.members.representing')"> :content="t('dialog.group.members.representing')">
<Tag style="margin-right: 5px" /> <Tag style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="group.memberVisibility !== 'visible'" side="top"> <TooltipWrapper v-if="group.memberVisibility !== 'visible'" side="top">
<template #content> <template #content>
@@ -1015,7 +1010,7 @@
{{ group.memberVisibility }}</span {{ group.memberVisibility }}</span
> >
</template> </template>
<Eye style="margin-right: 5px" /> <Eye style="margin-right: 6px" />
</TooltipWrapper> </TooltipWrapper>
<span>({{ group.memberCount }})</span> <span>({{ group.memberCount }})</span>
</div> </div>
@@ -1039,7 +1034,7 @@
<Spinner v-if="userDialog.isWorldsLoading" /> <Spinner v-if="userDialog.isWorldsLoading" />
<RefreshCw v-else /> <RefreshCw v-else />
</Button> </Button>
<span style="margin-left: 5px">{{ <span style="margin-left: 6px">{{
t('dialog.user.worlds.total_count', { count: userDialog.worlds.length }) t('dialog.user.worlds.total_count', { count: userDialog.worlds.length })
}}</span> }}</span>
</div> </div>
@@ -1080,7 +1075,7 @@
</Select> </Select>
</div> </div>
</div> </div>
<div class="flex flex-wrap items-start" style="margin-top: 10px; min-height: 60px"> <div class="flex flex-wrap items-start" style="margin-top: 8px; min-height: 60px">
<template v-if="userDialog.worlds.length"> <template v-if="userDialog.worlds.length">
<div <div
v-for="world in userDialog.worlds" v-for="world in userDialog.worlds"
@@ -1136,7 +1131,7 @@
:items="favoriteWorldTabs" :items="favoriteWorldTabs"
:unmount-on-hide="false" :unmount-on-hide="false"
class="zero-margin-tabs" class="zero-margin-tabs"
style="margin-top: 10px; height: 50vh"> style="margin-top: 8px; height: 50vh">
<template <template
v-for="(list, index) in userDialog.userFavoriteWorlds" v-for="(list, index) in userDialog.userFavoriteWorlds"
:key="`favorite-worlds-label-${index}`" :key="`favorite-worlds-label-${index}`"
@@ -1144,11 +1139,11 @@
<span> <span>
<i <i
class="x-status-icon" class="x-status-icon"
style="margin-right: 6px" style="margin-right: 8px"
:class="userFavoriteWorldsStatus(list[1])"> :class="userFavoriteWorldsStatus(list[1])">
</i> </i>
<span style="font-weight: bold; font-size: 14px" v-text="list[0]"></span> <span style="font-weight: bold; font-size: 14px" v-text="list[0]"></span>
<span style="font-size: 10px; margin-left: 5px" <span style="font-size: 10px; margin-left: 6px"
>{{ list[2].length }}/{{ favoriteLimits.maxFavoritesPerGroup.world }}</span >{{ list[2].length }}/{{ favoriteLimits.maxFavoritesPerGroup.world }}</span
> >
</span> </span>
@@ -1159,7 +1154,7 @@
v-slot:[String(index)]> v-slot:[String(index)]>
<div <div
class="flex flex-wrap items-start" class="flex flex-wrap items-start"
style="margin-top: 10px; margin-bottom: 15px; min-height: 60px; max-height: none"> style="margin-top: 8px; margin-bottom: 16px; min-height: 60px; max-height: none">
<div <div
v-for="world in list[2]" v-for="world in list[2]"
:key="world.favoriteId" :key="world.favoriteId"
@@ -1217,7 +1212,7 @@
<Spinner v-if="userDialog.isAvatarsLoading" /> <Spinner v-if="userDialog.isAvatarsLoading" />
<RefreshCw v-else /> <RefreshCw v-else />
</Button> </Button>
<span style="margin-left: 5px">{{ <span style="margin-left: 6px">{{
t('dialog.user.avatars.total_count', { count: userDialogAvatars.length }) t('dialog.user.avatars.total_count', { count: userDialogAvatars.length })
}}</span> }}</span>
</div> </div>
@@ -1267,7 +1262,7 @@
</div> </div>
<div <div
class="flex flex-wrap items-start" class="flex flex-wrap items-start"
style="margin-top: 10px; min-height: 60px; max-height: 50vh; overflow: auto"> style="margin-top: 8px; min-height: 60px; max-height: 50vh; overflow: auto">
<template v-if="filteredUserDialogAvatars.length"> <template v-if="filteredUserDialogAvatars.length">
<div <div
v-for="avatar in filteredUserDialogAvatars" v-for="avatar in filteredUserDialogAvatars"
@@ -19,7 +19,7 @@
@click="showFullscreenImageDialog(userDialog.ref.currentAvatarImageUrl)" @click="showFullscreenImageDialog(userDialog.ref.currentAvatarImageUrl)"
loading="lazy" /> loading="lazy" />
</div> </div>
<div style="flex: 1; display: flex; align-items: flex-start; margin-left: 15px"> <div class="ml-4" style="flex: 1; display: flex; align-items: flex-start">
<div style="flex: 1"> <div style="flex: 1">
<div> <div>
<TooltipWrapper v-if="userDialog.ref.status" side="top"> <TooltipWrapper v-if="userDialog.ref.status" side="top">
@@ -47,13 +47,13 @@
</template> </template>
<span <span
class="font-bold" class="font-bold"
style="margin-left: 5px; margin-right: 5px; cursor: pointer" style="margin-left: 6px; margin-right: 6px; cursor: pointer"
v-text="userDialog.ref.displayName" v-text="userDialog.ref.displayName"
@click="copyUserDisplayName(userDialog.ref.displayName)"></span> @click="copyUserDisplayName(userDialog.ref.displayName)"></span>
<TooltipWrapper v-if="userDialog.ref.pronouns" side="top" :content="t('dialog.user.pronouns')"> <TooltipWrapper v-if="userDialog.ref.pronouns" side="top" :content="t('dialog.user.pronouns')">
<span <span
class="x-grey" class="x-grey"
style="margin-right: 5px; font-family: monospace; font-size: 12px" style="margin-right: 6px; font-family: monospace; font-size: 12px"
v-text="userDialog.ref.pronouns"></span> v-text="userDialog.ref.pronouns"></span>
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-for="item in userDialog.ref.$languages" :key="item.key" side="top"> <TooltipWrapper v-for="item in userDialog.ref.$languages" :key="item.key" side="top">
@@ -63,13 +63,13 @@
<span <span
class="flags" class="flags"
:class="languageClass(item.key)" :class="languageClass(item.key)"
style="display: inline-block; margin-right: 5px"></span> style="display: inline-block; margin-right: 6px"></span>
</TooltipWrapper> </TooltipWrapper>
<template v-if="userDialog.ref.id === currentUser.id"> <template v-if="userDialog.ref.id === currentUser.id">
<br /> <br />
<span <span
class="x-grey" class="x-grey"
style="margin-right: 10px; font-family: monospace; font-size: 12px; cursor: pointer" style="margin-right: 8px; font-family: monospace; font-size: 12px; cursor: pointer"
v-text="currentUser.username" v-text="currentUser.username"
@click="copyUserDisplayName(currentUser.username)"></span> @click="copyUserDisplayName(currentUser.username)"></span>
</template> </template>
@@ -181,8 +181,8 @@
width: 32px; width: 32px;
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
object-fit: cover; object-fit: cover;
margin-top: 5px; margin-top: 6px;
margin-right: 5px; margin-right: 6px;
" "
:class="{ grayscale: badge.hidden }" :class="{ grayscale: badge.hidden }"
loading="lazy" /> loading="lazy" />
@@ -208,7 +208,7 @@
</span> </span>
<template v-if="userDialog.id === currentUser.id"> <template v-if="userDialog.id === currentUser.id">
<br /> <br />
<label class="inline-flex items-center gap-2" style="margin-top: 5px"> <label class="inline-flex items-center gap-2" style="margin-top: 6px">
<Checkbox <Checkbox
v-model="badge.hidden" v-model="badge.hidden"
@update:modelValue="toggleBadgeVisibility(badge)" /> @update:modelValue="toggleBadgeVisibility(badge)" />
@@ -233,7 +233,7 @@
</div> </div>
</div> </div>
<div v-if="userDialog.ref.userIcon" style="flex: none; margin-right: 10px"> <div v-if="userDialog.ref.userIcon" style="flex: none; margin-right: 8px">
<img <img
class="cursor-pointer" class="cursor-pointer"
:src="userImage(userDialog.ref, true, '256', true)" :src="userImage(userDialog.ref, true, '256', true)"
+2 -2
View File
@@ -4,14 +4,14 @@
<DialogHeader> <DialogHeader>
<DialogTitle>{{ t('dialog.vrcx_updater.header') }}</DialogTitle> <DialogTitle>{{ t('dialog.vrcx_updater.header') }}</DialogTitle>
</DialogHeader> </DialogHeader>
<div style="margin-top: 15px"> <div class="mt-4">
<template v-if="updateInProgress"> <template v-if="updateInProgress">
<Progress :model-value="updateProgress" class="w-full" /> <Progress :model-value="updateProgress" class="w-full" />
<div class="mt-2 text-xs" v-text="updateProgressText()"></div> <div class="mt-2 text-xs" v-text="updateProgressText()"></div>
<br /> <br />
</template> </template>
<template v-else> <template v-else>
<div v-if="VRCXUpdateDialog.updatePending" style="margin-bottom: 15px"> <div v-if="VRCXUpdateDialog.updatePending" style="margin-bottom: 16px">
<span>{{ pendingVRCXInstall }}</span> <span>{{ pendingVRCXInstall }}</span>
<br /> <br />
<span>{{ t('dialog.vrcx_updater.ready_for_update') }}</span> <span>{{ t('dialog.vrcx_updater.ready_for_update') }}</span>
@@ -19,14 +19,14 @@
<Checkbox v-model="setWorldTagsDialog.debugAllowed" /> <Checkbox v-model="setWorldTagsDialog.debugAllowed" />
<span>{{ t('dialog.set_world_tags.enable_debugging') }}</span> <span>{{ t('dialog.set_world_tags.enable_debugging') }}</span>
</label> </label>
<div style="font-size: 12px; margin-top: 10px">{{ t('dialog.set_world_tags.author_tags') }}<br /></div> <div class="mt-2" style="font-size: 12px">{{ t('dialog.set_world_tags.author_tags') }}<br /></div>
<InputGroupTextareaField <InputGroupTextareaField
v-model="setWorldTagsDialog.authorTags" v-model="setWorldTagsDialog.authorTags"
:rows="2" :rows="2"
placeholder="" placeholder=""
style="margin-top: 10px"
input-class="resize-none" /> input-class="resize-none mt-2" />
<div style="font-size: 12px; margin-top: 10px">{{ t('dialog.set_world_tags.content_tags') }}<br /></div> <div class="mt-2" style="font-size: 12px">{{ t('dialog.set_world_tags.content_tags') }}<br /></div>
<label class="inline-flex items-center gap-2"> <label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.contentHorror" /> <Checkbox v-model="setWorldTagsDialog.contentHorror" />
<span>{{ t('dialog.set_world_tags.content_horror') }}</span> <span>{{ t('dialog.set_world_tags.content_horror') }}</span>
@@ -51,7 +51,7 @@
<Checkbox v-model="setWorldTagsDialog.contentSex" /> <Checkbox v-model="setWorldTagsDialog.contentSex" />
<span>{{ t('dialog.set_world_tags.content_sex') }}</span> <span>{{ t('dialog.set_world_tags.content_sex') }}</span>
</label> </label>
<div style="font-size: 12px; margin-top: 10px"> <div class="mt-2" style="font-size: 12px">
{{ t('dialog.set_world_tags.default_content_settings') }}<br /> {{ t('dialog.set_world_tags.default_content_settings') }}<br />
</div> </div>
<label class="inline-flex items-center gap-2"> <label class="inline-flex items-center gap-2">
@@ -7,16 +7,16 @@
<div> <div>
<InputGroupAction <InputGroupAction
class="mt-1.5"
v-for="(domain, index) in urlList" v-for="(domain, index) in urlList"
:key="index" :key="index"
v-model="urlList[index]" v-model="urlList[index]"
size="sm" size="sm">
style="margin-top: 5px">
<template #actions> <template #actions>
<Button variant="ghost" @click="urlList.splice(index, 1)"><Trash2 /></Button> <Button variant="ghost" @click="urlList.splice(index, 1)"><Trash2 /></Button>
</template> </template>
</InputGroupAction> </InputGroupAction>
<Button size="sm" variant="outline" style="margin-top: 5px" @click="urlList.push('')"> <Button size="sm" variant="outline" style="margin-top: 6px" @click="urlList.push('')">
{{ t('dialog.allowed_video_player_domains.add_domain') }} {{ t('dialog.allowed_video_player_domains.add_domain') }}
</Button> </Button>
</div> </div>
@@ -17,10 +17,10 @@
@click="showFullscreenImageDialog(worldDialog.ref.imageUrl)" @click="showFullscreenImageDialog(worldDialog.ref.imageUrl)"
loading="lazy" /> loading="lazy" />
</div> </div>
<div style="flex: 1; display: flex; align-items: flex-start; margin-left: 15px"> <div class="ml-4" style="flex: 1; display: flex; align-items: flex-start">
<div style="flex: 1"> <div style="flex: 1">
<div> <div>
<span class="font-bold" style="margin-right: 5px; cursor: pointer" @click="copyWorldName"> <span class="font-bold mr-1.5" style="cursor: pointer" @click="copyWorldName">
<Home <Home
v-if=" v-if="
currentUser.$homeLocation && currentUser.$homeLocation &&
@@ -30,7 +30,7 @@
{{ worldDialog.ref.name }} {{ worldDialog.ref.name }}
</span> </span>
</div> </div>
<div style="margin-top: 5px"> <div class="mt-1.5">
<span <span
class="cursor-pointer x-grey" class="cursor-pointer x-grey"
style="font-family: monospace" style="font-family: monospace"
@@ -38,26 +38,20 @@
v-text="worldDialog.ref.authorName" /> v-text="worldDialog.ref.authorName" />
</div> </div>
<div> <div>
<Badge <Badge class="mr-1.5 mt-1.5" v-if="worldDialog.ref.$isLabs" variant="outline">
v-if="worldDialog.ref.$isLabs"
variant="outline"
style="margin-right: 5px; margin-top: 5px">
{{ t('dialog.world.tags.labs') }} {{ t('dialog.world.tags.labs') }}
</Badge> </Badge>
<Badge <Badge
class="mr-1.5 mt-1.5"
v-else-if="worldDialog.ref.releaseStatus === 'public'" v-else-if="worldDialog.ref.releaseStatus === 'public'"
variant="outline" variant="outline">
style="margin-right: 5px; margin-top: 5px">
{{ t('dialog.world.tags.public') }} {{ t('dialog.world.tags.public') }}
</Badge> </Badge>
<Badge v-else variant="outline" style="margin-right: 5px; margin-top: 5px"> <Badge class="mr-1.5 mt-1.5" v-else variant="outline">
{{ t('dialog.world.tags.private') }} {{ t('dialog.world.tags.private') }}
</Badge> </Badge>
<TooltipWrapper v-if="worldDialog.isPC" side="top" content="PC"> <TooltipWrapper v-if="worldDialog.isPC" side="top" content="PC">
<Badge <Badge class="text-platform-pc border-platform-pc! mr-1.5 mt-1.5" variant="outline">
class="text-platform-pc border-platform-pc!"
variant="outline"
style="margin-right: 5px; margin-top: 5px">
<Monitor class="h-4 w-4 text-platform-pc" /> <Monitor class="h-4 w-4 text-platform-pc" />
<span <span
v-if="worldDialog.fileAnalysis.standalonewindows?._fileSize" v-if="worldDialog.fileAnalysis.standalonewindows?._fileSize"
@@ -69,9 +63,8 @@
<TooltipWrapper v-if="worldDialog.isQuest" side="top" content="Quest"> <TooltipWrapper v-if="worldDialog.isQuest" side="top" content="Quest">
<Badge <Badge
class="text-platform-quest border-platform-quest!" class="text-platform-quest border-platform-quest! mr-1.5 mt-1.5"
variant="outline" variant="outline">
style="margin-right: 5px; margin-top: 5px">
<Smartphone class="h-4 w-4 text-platform-quest" /> <Smartphone class="h-4 w-4 text-platform-quest" />
<span <span
v-if="worldDialog.fileAnalysis.android?._fileSize" v-if="worldDialog.fileAnalysis.android?._fileSize"
@@ -82,10 +75,7 @@
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="worldDialog.isIos" side="top" content="iOS"> <TooltipWrapper v-if="worldDialog.isIos" side="top" content="iOS">
<Badge <Badge class="text-platform-ios border-platform-ios mr-1.5 mt-1.5" variant="outline">
class="text-platform-ios border-platform-ios"
variant="outline"
style="margin-right: 5px; margin-top: 5px">
<Apple class="h-4 w-4 text-platform-ios" /> <Apple class="h-4 w-4 text-platform-ios" />
<span <span
v-if="worldDialog.fileAnalysis.ios?._fileSize" v-if="worldDialog.fileAnalysis.ios?._fileSize"
@@ -95,29 +85,19 @@
</Badge> </Badge>
</TooltipWrapper> </TooltipWrapper>
<Badge <Badge class="mr-1.5 mt-1.5" v-if="worldDialog.avatarScalingDisabled" variant="outline">
v-if="worldDialog.avatarScalingDisabled"
variant="outline"
style="margin-right: 5px; margin-top: 5px">
{{ t('dialog.world.tags.avatar_scaling_disabled') }} {{ t('dialog.world.tags.avatar_scaling_disabled') }}
</Badge> </Badge>
<Badge <Badge class="mr-1.5 mt-1.5" v-if="worldDialog.focusViewDisabled" variant="outline">
v-if="worldDialog.focusViewDisabled"
variant="outline"
style="margin-right: 5px; margin-top: 5px">
{{ t('dialog.world.tags.focus_view_disabled') }} {{ t('dialog.world.tags.focus_view_disabled') }}
</Badge> </Badge>
<Badge <Badge class="mr-1.5 mt-1.5" v-if="worldDialog.ref.unityPackageUrl" variant="outline">
v-if="worldDialog.ref.unityPackageUrl"
variant="outline"
style="margin-right: 5px; margin-top: 5px">
{{ t('dialog.world.tags.future_proofing') }} {{ t('dialog.world.tags.future_proofing') }}
</Badge> </Badge>
<Badge <Badge
v-if="worldDialog.inCache" v-if="worldDialog.inCache"
variant="outline" variant="outline"
class="cursor-pointer" class="cursor-pointer mr-1.5 mt-1.5"
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" />
| {{ t('dialog.world.tags.cache') }} | {{ t('dialog.world.tags.cache') }}
@@ -125,10 +105,7 @@
</div> </div>
<div> <div>
<template v-for="tag in worldDialog.ref.tags" :key="tag"> <template v-for="tag in worldDialog.ref.tags" :key="tag">
<Badge <Badge class="mr-1.5 mt-1.5" v-if="tag.startsWith('content_')" variant="outline">
v-if="tag.startsWith('content_')"
variant="outline"
style="margin-right: 5px; margin-top: 5px">
<span v-if="tag === 'content_horror'"> <span v-if="tag === 'content_horror'">
{{ t('dialog.world.tags.content_horror') }} {{ t('dialog.world.tags.content_horror') }}
</span> </span>
@@ -150,7 +127,7 @@
</Badge> </Badge>
</template> </template>
</div> </div>
<div style="margin-top: 5px; display: flex; align-items: center"> <div style="margin-top: 6px; display: flex; align-items: center">
<span <span
v-show="worldDialog.ref.name !== worldDialog.ref.description" v-show="worldDialog.ref.name !== worldDialog.ref.description"
style="font-size: 12px; flex: 1; margin-right: 0.5em" style="font-size: 12px; flex: 1; margin-right: 0.5em"
@@ -334,13 +311,13 @@
<div class="flex items-center text-sm"> <div class="flex items-center text-sm">
<User /> <User />
{{ t('dialog.world.instances.public_count', { count: worldDialog.ref.publicOccupants }) }} {{ t('dialog.world.instances.public_count', { count: worldDialog.ref.publicOccupants }) }}
<User style="margin-left: 10px" /> <User style="margin-left: 8px" />
{{ {{
t('dialog.world.instances.private_count', { t('dialog.world.instances.private_count', {
count: worldDialog.ref.privateOccupants count: worldDialog.ref.privateOccupants
}) })
}} }}
<Check style="margin-left: 10px" /> <Check style="margin-left: 8px" />
{{ {{
t('dialog.world.instances.capacity_count', { t('dialog.world.instances.capacity_count', {
count: worldDialog.ref.recommendedCapacity, count: worldDialog.ref.recommendedCapacity,
@@ -351,7 +328,7 @@
<div v-for="room in worldDialog.rooms" :key="room.id"> <div v-for="room in worldDialog.rooms" :key="room.id">
<template <template
v-if="isAgeGatedInstancesVisible || !(room.ageGate || room.location?.includes('~ageGate'))"> v-if="isAgeGatedInstancesVisible || !(room.ageGate || room.location?.includes('~ageGate'))">
<div style="margin: 5px 0"> <div style="margin: 6px 0">
<div class="flex items-center"> <div class="flex items-center">
<LocationWorld <LocationWorld
class="text-sm" class="text-sm"
@@ -376,7 +353,7 @@
<div <div
v-if="room.$location.userId || room.users.length" v-if="room.$location.userId || room.users.length"
class="flex flex-wrap items-start" class="flex flex-wrap items-start"
style="margin: 10px 0; max-height: unset"> style="margin: 8px 0; max-height: unset">
<div <div
v-if="room.$location.userId" v-if="room.$location.userId"
class="box-border flex items-center p-1.5 text-[13px] cursor-pointer w-[167px] hover:rounded-[25px_5px_5px_25px]" class="box-border flex items-center p-1.5 text-[13px] cursor-pointer w-[167px] hover:rounded-[25px_5px_5px_25px]"
@@ -582,7 +559,7 @@
<TooltipWrapper <TooltipWrapper
v-if="Object.keys(worldDialog.fileAnalysis).length" v-if="Object.keys(worldDialog.fileAnalysis).length"
side="top" side="top"
style="margin-left: 5px"> style="margin-left: 6px">
<template #content> <template #content>
<template <template
v-for="(created_at, platform) in worldDialogPlatformCreatedAt" v-for="(created_at, platform) in worldDialogPlatformCreatedAt"
@@ -619,7 +596,7 @@
<span class="block truncate font-medium leading-[18px]" style="display: inline"> <span class="block truncate font-medium leading-[18px]" style="display: inline">
{{ t('dialog.world.info.publication_date') }} {{ t('dialog.world.info.publication_date') }}
</span> </span>
<TooltipWrapper v-if="isTimeInLabVisible" side="top" style="margin-left: 5px"> <TooltipWrapper v-if="isTimeInLabVisible" side="top" style="margin-left: 6px">
<template #content> <template #content>
<span> <span>
{{ t('dialog.world.info.time_in_labs') }} {{ t('dialog.world.info.time_in_labs') }}
+2 -2
View File
@@ -5,7 +5,7 @@
.options-container { .options-container {
margin-top: 30px; margin-top: 30px;
padding: 0 10px 10px 10px; padding: 0 8px 8px 8px;
} }
.options-container .header-bar { .options-container .header-bar {
@@ -25,7 +25,7 @@
.options-container-item { .options-container-item {
font-size: 12px; font-size: 12px;
margin-top: 5px; margin-top: 6px;
display: flex; display: flex;
align-items: center; align-items: center;
} }
@@ -2,12 +2,12 @@
<div id="chart" class="x-container"> <div id="chart" class="x-container">
<div ref="instanceActivityRef" class="pt-12"> <div ref="instanceActivityRef" class="pt-12">
<BackToTop :target="instanceActivityRef" :right="30" :bottom="30" :teleport="false" /> <BackToTop :target="instanceActivityRef" :right="30" :bottom="30" :teleport="false" />
<div class="options-container instance-activity" style="margin-top: 0"> <div class="options-container instance-activity mt-0">
<div> <div>
<span>{{ t('view.charts.instance_activity.header') }}</span> <span>{{ t('view.charts.instance_activity.header') }}</span>
<HoverCard> <HoverCard>
<HoverCardTrigger as-child> <HoverCardTrigger as-child>
<Info style="margin-left: 4px; font-size: 12px; opacity: 0.7" /> <Info class="ml-1" style="font-size: 12px; opacity: 0.7" />
</HoverCardTrigger> </HoverCardTrigger>
<HoverCardContent side="bottom" align="start" class="w-75"> <HoverCardContent side="bottom" align="start" class="w-75">
<div class="tips-popover"> <div class="tips-popover">
@@ -21,12 +21,7 @@
<div> <div>
<TooltipWrapper :content="t('view.charts.instance_activity.refresh')" side="top"> <TooltipWrapper :content="t('view.charts.instance_activity.refresh')" side="top">
<Button <Button class="rounded-full mr-1.5" size="icon" variant="ghost" @click="reloadData">
class="rounded-full"
size="icon"
variant="ghost"
style="margin-right: 5px"
@click="reloadData">
<RefreshCcw /> <RefreshCcw />
</Button> </Button>
</TooltipWrapper> </TooltipWrapper>
@@ -37,7 +32,7 @@
<TooltipWrapper <TooltipWrapper
:content="t('view.charts.instance_activity.settings.header')" :content="t('view.charts.instance_activity.settings.header')"
side="top"> side="top">
<Button class="rounded-full" size="icon" variant="ghost" style="margin-right: 5px"> <Button class="rounded-full mr-1.5" size="icon" variant="ghost">
<Settings /> <Settings />
</Button> </Button>
</TooltipWrapper> </TooltipWrapper>
@@ -215,6 +210,9 @@
setInstanceActivityHeight(); setInstanceActivityHeight();
}); });
/**
*
*/
function setInstanceActivityHeight() { function setInstanceActivityHeight() {
if (instanceActivityRef.value) { if (instanceActivityRef.value) {
const availableHeight = window.innerHeight - 110; const availableHeight = window.innerHeight - 110;
@@ -259,6 +257,10 @@
} }
}); });
/**
*
* @param value
*/
function handleBarWidthCommit(value) { function handleBarWidthCommit(value) {
changeBarWidth(value?.[0] ?? barWidthDraft.value, () => handleEchartsRerender()); changeBarWidth(value?.[0] ?? barWidthDraft.value, () => handleEchartsRerender());
} }
@@ -303,6 +305,10 @@
return fromDate(selectedDate.value ?? new Date(), calendarTimeZone); return fromDate(selectedDate.value ?? new Date(), calendarTimeZone);
}); });
/**
*
* @param dateValue
*/
function isCalendarDateDisabled(dateValue) { function isCalendarDateDisabled(dateValue) {
try { try {
return getDatePickerDisabledDate(toDate(dateValue, calendarTimeZone)); return getDatePickerDisabledDate(toDate(dateValue, calendarTimeZone));
@@ -311,6 +317,10 @@
} }
} }
/**
*
* @param dateValue
*/
function handleCalendarModelUpdate(dateValue) { function handleCalendarModelUpdate(dateValue) {
if (!dateValue) return; if (!dateValue) return;
selectedDate.value = toDate(dateValue, calendarTimeZone); selectedDate.value = toDate(dateValue, calendarTimeZone);
@@ -430,6 +440,10 @@
} }
}; };
/**
*
* @param params
*/
function handleYAxisLabelClick(params) { function handleYAxisLabelClick(params) {
const targetActivity = activityData.value[params?.dataIndex]; const targetActivity = activityData.value[params?.dataIndex];
if (!targetActivity) { if (!targetActivity) {
@@ -463,6 +477,9 @@
} }
} }
/**
*
*/
function getYAxisData() { function getYAxisData() {
return worldNameArray.value.map((worldName, index) => { return worldNameArray.value.map((worldName, index) => {
const activityItem = activityData.value[index]; const activityItem = activityData.value[index];
@@ -479,6 +496,9 @@
}); });
} }
/**
*
*/
function initEcharts() { function initEcharts() {
const chartsHeight = activityData.value.length * (barWidth.value + 10) + 200; const chartsHeight = activityData.value.length * (barWidth.value + 10) + 200;
const chartDom = activityChartRef.value; const chartDom = activityChartRef.value;
@@ -533,6 +553,9 @@
} }
afterInit(); afterInit();
} }
/**
*
*/
function getNewOption() { function getNewOption() {
const getTooltip = (params) => { const getTooltip = (params) => {
const activityDataArray = activityData.value; const activityDataArray = activityData.value;
@@ -560,7 +583,7 @@
return ` return `
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<div style="width: 10px; height: 55px; background-color: ${color}; margin-right: 5px;"></div> <div style="width: 10px; height: 55px; background-color: ${color}; margin-right: 6px;"></div>
<div> <div>
<div>${name} #${location.instanceName} ${location.accessTypeName}</div> <div>${name} #${location.instanceName} ${location.accessTypeName}</div>
<div>${formattedJoinDateTime} - ${formattedLeftDateTime}</div> <div>${formattedJoinDateTime} - ${formattedLeftDateTime}</div>
@@ -673,10 +696,16 @@
return echartsOption; return echartsOption;
} }
/**
*
*/
function handleEchartsRerender() { function handleEchartsRerender() {
initEcharts(); initEcharts();
handleSettingsChange(); handleSettingsChange();
} }
/**
*
*/
function handleSettingsChange() { function handleSettingsChange() {
handleChangeSettings(activityDetailChartRef); handleChangeSettings(activityDetailChartRef);
@@ -716,12 +745,12 @@
} }
.tips-popover { .tips-popover {
& > div { & > div {
margin-bottom: 5px; margin-bottom: 6px;
font-size: 12px; font-size: 12px;
} }
& > div:last-child { & > div:last-child {
@extend %flex; @extend %flex;
margin-top: 10px; margin-top: 8px;
i { i {
margin-right: 3px; margin-right: 3px;
} }
@@ -1,6 +1,6 @@
<template> <template>
<div style="width: 100%"> <div style="width: 100%">
<div style="height: 25px; margin-top: 60px"> <div class="mt-15" style="height: 25px">
<transition name="el-fade-in-linear"> <transition name="el-fade-in-linear">
<Location <Location
v-show="!isLoading" v-show="!isLoading"
@@ -106,6 +106,9 @@
} }
}); });
/**
*
*/
function initResizeObserver() { function initResizeObserver() {
resizeObserver.value = new ResizeObserver((entries) => { resizeObserver.value = new ResizeObserver((entries) => {
if (!echartsInstance) { if (!echartsInstance) {
@@ -126,6 +129,9 @@
}); });
} }
/**
*
*/
async function initEcharts() { async function initEcharts() {
if (!activityDetailChartRef.value || !props.activityDetailData || props.activityDetailData.length === 0) { if (!activityDetailChartRef.value || !props.activityDetailData || props.activityDetailData.length === 0) {
isLoading.value = false; isLoading.value = false;
@@ -183,6 +189,10 @@
setTimeout(afterInit, 50); setTimeout(afterInit, 50);
} }
/**
*
* @param params
*/
function handleClickYAxisLabel(params) { function handleClickYAxisLabel(params) {
const userData = usersFirstActivity.value[params.dataIndex]; const userData = usersFirstActivity.value[params.dataIndex];
if (userData?.user_id) { if (userData?.user_id) {
@@ -190,6 +200,9 @@
} }
} }
/**
*
*/
function getNewOption() { function getNewOption() {
if (!props.activityDetailData || props.activityDetailData.length === 0) { if (!props.activityDetailData || props.activityDetailData.length === 0) {
return { return {
@@ -346,7 +359,7 @@
return ` return `
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<div style="width: 10px; height: 55px; background-color: ${color}; margin-right: 5px;"></div> <div style="width: 10px; height: 55px; background-color: ${color}; margin-right: 6px;"></div>
<div> <div>
<div>${instanceData.display_name} ${friendOrFavIcon(instanceData.display_name)}</div> <div>${instanceData.display_name} ${friendOrFavIcon(instanceData.display_name)}</div>
<div>${formattedJoinDateTime} - ${formattedLeftDateTime}</div> <div>${formattedJoinDateTime} - ${formattedLeftDateTime}</div>
+9 -9
View File
@@ -1683,7 +1683,7 @@
} }
.favorites-dropdown { .favorites-dropdown {
padding: 10px; padding: 8px;
} }
.group-section { .group-section {
@@ -1752,7 +1752,7 @@
.group-item__visibility { .group-item__visibility {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 6px;
} }
.group-item__visibility-text { .group-item__visibility-text {
@@ -1792,7 +1792,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 6px; gap: 8px;
font-size: 14px; font-size: 14px;
} }
@@ -1912,7 +1912,7 @@
box-sizing: border-box; box-sizing: border-box;
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: calc(var(--radius-lg) * var(--favorites-card-scale, 1)); border-radius: calc(var(--radius-lg) * var(--favorites-card-scale, 1));
padding: var(--favorites-card-padding-y, 8px) var(--favorites-card-padding-x, 10px); padding: var(--favorites-card-padding-y, 8px) var(--favorites-card-padding-x, 8px);
cursor: pointer; cursor: pointer;
transition: background-color 0.15s ease; transition: background-color 0.15s ease;
width: 100%; width: 100%;
@@ -1928,7 +1928,7 @@
:deep(.favorites-search-card__content) { :deep(.favorites-search-card__content) {
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--favorites-card-content-gap, 10px); gap: var(--favorites-card-content-gap, 8px);
flex: 1; flex: 1;
min-width: 0; min-width: 0;
} }
@@ -1982,7 +1982,7 @@
:deep(.favorites-search-card__title) { :deep(.favorites-search-card__title) {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6px; gap: 8px;
} }
:deep(.favorites-search-card__badges) { :deep(.favorites-search-card__badges) {
@@ -2015,7 +2015,7 @@
:deep(.favorites-search-card__action-group) { :deep(.favorites-search-card__action-group) {
display: flex; display: flex;
gap: var(--favorites-card-action-group-gap, 6px); gap: var(--favorites-card-action-group-gap, 8px);
width: 100%; width: 100%;
} }
@@ -2026,7 +2026,7 @@
:deep(.favorites-search-card__action--checkbox) { :deep(.favorites-search-card__action--checkbox) {
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
margin-right: var(--favorites-card-checkbox-margin, 10px); margin-right: var(--favorites-card-checkbox-margin, 8px);
} }
:deep(.favorites-search-card__action--checkbox [data-slot='checkbox']) { :deep(.favorites-search-card__action--checkbox [data-slot='checkbox']) {
@@ -2058,7 +2058,7 @@
justify-content: space-between; justify-content: space-between;
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
margin-bottom: 6px; margin-bottom: 8px;
} }
.favorites-dropdown__control-value { .favorites-dropdown__control-value {
+9 -9
View File
@@ -1323,7 +1323,7 @@
} }
.favorites-dropdown { .favorites-dropdown {
padding: 10px; padding: 8px;
} }
.group-section { .group-section {
@@ -1392,7 +1392,7 @@
.group-item__visibility { .group-item__visibility {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 6px;
} }
.group-item__visibility-text { .group-item__visibility-text {
@@ -1430,7 +1430,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 6px; gap: 8px;
font-size: 14px; font-size: 14px;
} }
@@ -1539,7 +1539,7 @@
box-sizing: border-box; box-sizing: border-box;
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: calc(var(--radius-lg) * var(--favorites-card-scale, 1)); border-radius: calc(var(--radius-lg) * var(--favorites-card-scale, 1));
padding: var(--favorites-card-padding-y, 8px) var(--favorites-card-padding-x, 10px); padding: var(--favorites-card-padding-y, 8px) var(--favorites-card-padding-x, 8px);
cursor: pointer; cursor: pointer;
transition: background-color 0.15s ease; transition: background-color 0.15s ease;
width: 100%; width: 100%;
@@ -1558,7 +1558,7 @@
:deep(.favorites-search-card__content) { :deep(.favorites-search-card__content) {
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--favorites-card-content-gap, 10px); gap: var(--favorites-card-content-gap, 8px);
flex: 1; flex: 1;
min-width: 0; min-width: 0;
} }
@@ -1612,7 +1612,7 @@
:deep(.favorites-search-card__title) { :deep(.favorites-search-card__title) {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6px; gap: 8px;
} }
:deep(.favorites-search-card__badges) { :deep(.favorites-search-card__badges) {
@@ -1645,7 +1645,7 @@
:deep(.favorites-search-card__action-group) { :deep(.favorites-search-card__action-group) {
display: flex; display: flex;
gap: var(--favorites-card-action-group-gap, 6px); gap: var(--favorites-card-action-group-gap, 8px);
width: 100%; width: 100%;
} }
@@ -1656,7 +1656,7 @@
:deep(.favorites-search-card__action--checkbox) { :deep(.favorites-search-card__action--checkbox) {
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
margin-right: var(--favorites-card-checkbox-margin, 10px); margin-right: var(--favorites-card-checkbox-margin, 8px);
} }
:deep(.favorites-search-card__action--checkbox [data-slot='checkbox']) { :deep(.favorites-search-card__action--checkbox [data-slot='checkbox']) {
@@ -1698,7 +1698,7 @@
justify-content: space-between; justify-content: space-between;
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
margin-bottom: 6px; margin-bottom: 8px;
} }
.favorites-dropdown__control-value { .favorites-dropdown__control-value {
+9 -9
View File
@@ -1545,7 +1545,7 @@
} }
.favorites-dropdown { .favorites-dropdown {
padding: 10px; padding: 8px;
} }
.favorites-groups-panel { .favorites-groups-panel {
@@ -1623,7 +1623,7 @@
.group-item__visibility { .group-item__visibility {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 6px;
} }
.group-item__visibility-text { .group-item__visibility-text {
@@ -1666,7 +1666,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 6px; gap: 8px;
font-size: 14px; font-size: 14px;
} }
@@ -1828,7 +1828,7 @@
box-sizing: border-box; box-sizing: border-box;
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: calc(var(--radius-lg) * var(--favorites-card-scale, 1)); border-radius: calc(var(--radius-lg) * var(--favorites-card-scale, 1));
padding: var(--favorites-card-padding-y, 8px) var(--favorites-card-padding-x, 10px); padding: var(--favorites-card-padding-y, 8px) var(--favorites-card-padding-x, 8px);
cursor: pointer; cursor: pointer;
transition: background-color 0.15s ease; transition: background-color 0.15s ease;
width: 100%; width: 100%;
@@ -1847,7 +1847,7 @@
:deep(.favorites-search-card__content) { :deep(.favorites-search-card__content) {
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--favorites-card-content-gap, 10px); gap: var(--favorites-card-content-gap, 8px);
flex: 1; flex: 1;
min-width: 0; min-width: 0;
} }
@@ -1901,7 +1901,7 @@
:deep(.favorites-search-card__title) { :deep(.favorites-search-card__title) {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6px; gap: 8px;
} }
:deep(.favorites-search-card__badges) { :deep(.favorites-search-card__badges) {
@@ -1934,7 +1934,7 @@
:deep(.favorites-search-card__action-group) { :deep(.favorites-search-card__action-group) {
display: flex; display: flex;
gap: var(--favorites-card-action-group-gap, 6px); gap: var(--favorites-card-action-group-gap, 8px);
width: 100%; width: 100%;
} }
@@ -1945,7 +1945,7 @@
:deep(.favorites-search-card__action--checkbox) { :deep(.favorites-search-card__action--checkbox) {
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
margin-right: var(--favorites-card-checkbox-margin, 10px); margin-right: var(--favorites-card-checkbox-margin, 8px);
} }
:deep(.favorites-search-card__action--checkbox [data-slot='checkbox']) { :deep(.favorites-search-card__action--checkbox [data-slot='checkbox']) {
@@ -1980,7 +1980,7 @@
justify-content: space-between; justify-content: space-between;
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
margin-bottom: 6px; margin-bottom: 8px;
} }
.favorites-dropdown__control-value { .favorites-dropdown__control-value {
@@ -1,5 +1,5 @@
<template> <template>
<DropdownMenu v-model:open="moveDropdownOpen" style="margin-left: 5px"> <DropdownMenu class="ml-1.5" v-model:open="moveDropdownOpen">
<DropdownMenuTrigger as-child> <DropdownMenuTrigger as-child>
<Button class="rounded-full w-6 h-6 text-xs" size="icon-sm" variant="ghost" <Button class="rounded-full w-6 h-6 text-xs" size="icon-sm" variant="ghost"
><ArrowLeft class="h-4 w-4" ><ArrowLeft class="h-4 w-4"
@@ -11,10 +11,11 @@
</span> </span>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItem <DropdownMenuItem
class="my-2 mx-0"
v-for="groupAPI in favoriteGroupList" v-for="groupAPI in favoriteGroupList"
:key="groupAPI.name" :key="groupAPI.name"
v-if="isLocalFavorite || groupAPI?.name !== currentGroup?.name" v-if="isLocalFavorite || groupAPI?.name !== currentGroup?.name"
style="display: block; margin: 10px 0" style="display: block"
:disabled="groupAPI.count >= groupAPI.capacity" :disabled="groupAPI.count >= groupAPI.capacity"
@click="handleDropdownItemClick(groupAPI)"> @click="handleDropdownItemClick(groupAPI)">
{{ groupAPI.displayName }} ({{ groupAPI.count }} / {{ groupAPI.capacity }}) {{ groupAPI.displayName }} ({{ groupAPI.count }} / {{ groupAPI.capacity }})
@@ -74,6 +75,10 @@
}); });
const moveDropdownOpen = ref(false); const moveDropdownOpen = ref(false);
/**
*
* @param groupAPI
*/
function handleDropdownItemClick(groupAPI) { function handleDropdownItemClick(groupAPI) {
moveDropdownOpen.value = false; moveDropdownOpen.value = false;
if (props.isLocalFavorite) { if (props.isLocalFavorite) {
@@ -87,6 +92,11 @@
} }
} }
/**
*
* @param ref
* @param group
*/
function moveFavorite(ref, group) { function moveFavorite(ref, group) {
favoriteRequest.deleteFavorite({ objectId: ref.id }).then(() => { favoriteRequest.deleteFavorite({ objectId: ref.id }).then(() => {
favoriteRequest.addFavorite({ favoriteRequest.addFavorite({
@@ -97,6 +107,10 @@
}); });
} }
/**
*
* @param groupAPI
*/
function addFavoriteAvatar(groupAPI) { function addFavoriteAvatar(groupAPI) {
return favoriteRequest return favoriteRequest
.addFavorite({ .addFavorite({
@@ -110,6 +124,10 @@
}); });
} }
/**
*
* @param groupAPI
*/
function addFavoriteWorld(groupAPI) { function addFavoriteWorld(groupAPI) {
return favoriteRequest return favoriteRequest
.addFavorite({ .addFavorite({
@@ -5,7 +5,7 @@
<DialogTitle>{{ t('dialog.avatar_export.header') }}</DialogTitle> <DialogTitle>{{ t('dialog.avatar_export.header') }}</DialogTitle>
</DialogHeader> </DialogHeader>
<div style="margin-bottom: 10px" class="flex flex-col gap-2"> <div class="flex flex-col gap-2 mb-2">
<label v-for="option in exportSelectOptions" :key="option.value" class="inline-flex items-center gap-2"> <label v-for="option in exportSelectOptions" :key="option.value" class="inline-flex items-center gap-2">
<Checkbox <Checkbox
:model-value="exportSelectedOptions.includes(option.label)" :model-value="exportSelectedOptions.includes(option.label)"
@@ -35,9 +35,9 @@
</Select> </Select>
<Select <Select
class="ml-2"
:model-value="avatarExportLocalFavoriteGroupSelection" :model-value="avatarExportLocalFavoriteGroupSelection"
@update:modelValue="handleAvatarExportLocalFavoriteGroupSelect" @update:modelValue="handleAvatarExportLocalFavoriteGroupSelect">
style="margin-left: 10px">
<SelectTrigger size="sm"> <SelectTrigger size="sm">
<SelectValue placeholder="Select Group" /> <SelectValue placeholder="Select Group" />
</SelectTrigger> </SelectTrigger>
@@ -56,8 +56,7 @@
v-model="avatarExportContent" v-model="avatarExportContent"
:rows="15" :rows="15"
readonly readonly
style="margin-top: 15px" input-class="resize-none mt-4"
input-class="resize-none"
@click="handleCopyAvatarExportData" /> @click="handleCopyAvatarExportData" />
</DialogContent> </DialogContent>
</Dialog> </Dialog>
@@ -20,18 +20,14 @@
</Button> </Button>
</div> </div>
</div> </div>
<InputGroupTextareaField <InputGroupTextareaField v-model="avatarImportDialog.input" :rows="10" input-class="resize-none mt-2" />
v-model="avatarImportDialog.input" <div class="mt-1.5" style="display: flex; align-items: center; justify-content: space-between">
:rows="10"
style="margin-top: 10px"
input-class="resize-none" />
<div style="display: flex; align-items: center; justify-content: space-between; margin-top: 5px">
<div> <div>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<Select <Select
class="mr-1.5"
:model-value="avatarImportFavoriteGroupSelection" :model-value="avatarImportFavoriteGroupSelection"
@update:modelValue="handleAvatarImportGroupSelect" @update:modelValue="handleAvatarImportGroupSelect">
style="margin-right: 5px">
<SelectTrigger size="sm"> <SelectTrigger size="sm">
<SelectValue :placeholder="t('dialog.avatar_import.select_group_placeholder')" /> <SelectValue :placeholder="t('dialog.avatar_import.select_group_placeholder')" />
</SelectTrigger> </SelectTrigger>
@@ -49,9 +45,9 @@
</Select> </Select>
<Select <Select
class="ml-2"
:model-value="avatarImportLocalFavoriteGroupSelection" :model-value="avatarImportLocalFavoriteGroupSelection"
@update:modelValue="handleAvatarImportLocalGroupSelect" @update:modelValue="handleAvatarImportLocalGroupSelect">
style="margin-left: 10px">
<SelectTrigger size="sm"> <SelectTrigger size="sm">
<SelectValue :placeholder="t('dialog.avatar_import.select_group_placeholder')" /> <SelectValue :placeholder="t('dialog.avatar_import.select_group_placeholder')" />
</SelectTrigger> </SelectTrigger>
@@ -64,7 +60,7 @@
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
<span v-if="avatarImportDialog.avatarImportFavoriteGroup" style="margin-left: 5px"> <span class="ml-1.5" v-if="avatarImportDialog.avatarImportFavoriteGroup">
{{ avatarImportTable.data.length }} / {{ avatarImportTable.data.length }} /
{{ {{
avatarImportDialog.avatarImportFavoriteGroup.capacity - avatarImportDialog.avatarImportFavoriteGroup.capacity -
@@ -88,7 +84,7 @@
</Button> </Button>
</div> </div>
</div> </div>
<span v-if="avatarImportDialog.importProgress" style="margin: 10px"> <span class="m-2" v-if="avatarImportDialog.importProgress">
<Spinner class="inline-block ml-2 mr-2" /> <Spinner class="inline-block ml-2 mr-2" />
{{ t('dialog.avatar_import.import_progress') }} {{ t('dialog.avatar_import.import_progress') }}
{{ avatarImportDialog.importProgress }}/{{ avatarImportDialog.importProgressTotal }} {{ avatarImportDialog.importProgress }}/{{ avatarImportDialog.importProgressTotal }}
@@ -98,7 +94,7 @@
<Button size="sm" variant="secondary" @click="avatarImportDialog.errors = ''"> <Button size="sm" variant="secondary" @click="avatarImportDialog.errors = ''">
{{ t('dialog.avatar_import.clear_errors') }} {{ t('dialog.avatar_import.clear_errors') }}
</Button> </Button>
<h2 style="font-weight: bold; margin: 5px 0"> <h2 class="my-1.5 mx-0" style="font-weight: bold">
{{ t('dialog.avatar_import.errors') }} {{ t('dialog.avatar_import.errors') }}
</h2> </h2>
<pre style="white-space: pre-wrap; font-size: 12px" v-text="avatarImportDialog.errors"></pre> <pre style="white-space: pre-wrap; font-size: 12px" v-text="avatarImportDialog.errors"></pre>
@@ -109,7 +105,7 @@
:loading="avatarImportDialog.loading" :loading="avatarImportDialog.loading"
:table-style="tableStyle" :table-style="tableStyle"
:show-pagination="false" :show-pagination="false"
style="margin-top: 10px" /> style="margin-top: 8px" />
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</template> </template>
@@ -212,6 +208,9 @@
} }
); );
/**
*
*/
async function processAvatarImportList() { async function processAvatarImportList() {
const D = avatarImportDialog.value; const D = avatarImportDialog.value;
D.loading = true; D.loading = true;
@@ -253,21 +252,35 @@
D.progressTotal = 0; D.progressTotal = 0;
} }
/**
*
* @param ref
*/
function deleteItemAvatarImport(ref) { function deleteItemAvatarImport(ref) {
removeFromArray(avatarImportTable.value.data, ref); removeFromArray(avatarImportTable.value.data, ref);
avatarImportDialog.value.avatarIdList.delete(ref.id); avatarImportDialog.value.avatarIdList.delete(ref.id);
} }
/**
*
*/
function resetAvatarImport() { function resetAvatarImport() {
avatarImportDialog.value.input = ''; avatarImportDialog.value.input = '';
avatarImportDialog.value.errors = ''; avatarImportDialog.value.errors = '';
} }
/**
*
*/
function clearAvatarImportTable() { function clearAvatarImportTable() {
avatarImportTable.value.data = []; avatarImportTable.value.data = [];
avatarImportDialog.value.avatarIdList = new Set(); avatarImportDialog.value.avatarIdList = new Set();
} }
/**
*
* @param group
*/
function selectAvatarImportGroup(group) { function selectAvatarImportGroup(group) {
avatarImportDialog.value.avatarImportLocalFavoriteGroup = null; avatarImportDialog.value.avatarImportLocalFavoriteGroup = null;
avatarImportDialog.value.avatarImportFavoriteGroup = group; avatarImportDialog.value.avatarImportFavoriteGroup = group;
@@ -275,6 +288,10 @@
avatarImportLocalFavoriteGroupSelection.value = ''; avatarImportLocalFavoriteGroupSelection.value = '';
} }
/**
*
* @param group
*/
function selectAvatarImportLocalGroup(group) { function selectAvatarImportLocalGroup(group) {
avatarImportDialog.value.avatarImportFavoriteGroup = null; avatarImportDialog.value.avatarImportFavoriteGroup = null;
avatarImportDialog.value.avatarImportLocalFavoriteGroup = group; avatarImportDialog.value.avatarImportLocalFavoriteGroup = group;
@@ -282,20 +299,37 @@
avatarImportLocalFavoriteGroupSelection.value = group ?? ''; avatarImportLocalFavoriteGroupSelection.value = group ?? '';
} }
/**
*
* @param value
*/
function handleAvatarImportGroupSelect(value) { function handleAvatarImportGroupSelect(value) {
avatarImportFavoriteGroupSelection.value = value; avatarImportFavoriteGroupSelection.value = value;
const group = favoriteAvatarGroups.value.find((g) => g.name === value) ?? null; const group = favoriteAvatarGroups.value.find((g) => g.name === value) ?? null;
selectAvatarImportGroup(group); selectAvatarImportGroup(group);
} }
/**
*
* @param value
*/
function handleAvatarImportLocalGroupSelect(value) { function handleAvatarImportLocalGroupSelect(value) {
avatarImportLocalFavoriteGroupSelection.value = value; avatarImportLocalFavoriteGroupSelection.value = value;
selectAvatarImportLocalGroup(value || null); selectAvatarImportLocalGroup(value || null);
} }
/**
*
*/
function cancelAvatarImport() { function cancelAvatarImport() {
avatarImportDialog.value.loading = false; avatarImportDialog.value.loading = false;
} }
/**
*
* @param ref
* @param group
* @param message
*/
function addFavoriteAvatar(ref, group, message) { function addFavoriteAvatar(ref, group, message) {
return favoriteRequest return favoriteRequest
.addFavorite({ .addFavorite({
@@ -310,6 +344,9 @@
return args; return args;
}); });
} }
/**
*
*/
async function importAvatarImportTable() { async function importAvatarImportTable() {
const D = avatarImportDialog.value; const D = avatarImportDialog.value;
if (!D.avatarImportFavoriteGroup && !D.avatarImportLocalFavoriteGroup) { if (!D.avatarImportFavoriteGroup && !D.avatarImportLocalFavoriteGroup) {
@@ -24,9 +24,9 @@
</Select> </Select>
<Select <Select
class="mt-4"
:model-value="friendExportLocalFavoriteGroupSelection" :model-value="friendExportLocalFavoriteGroupSelection"
@update:modelValue="handleFriendExportLocalGroupSelect" @update:modelValue="handleFriendExportLocalGroupSelect">
style="margin-top: 15px">
<SelectTrigger size="sm"> <SelectTrigger size="sm">
<SelectValue placeholder="Select Group" /> <SelectValue placeholder="Select Group" />
</SelectTrigger> </SelectTrigger>
@@ -45,8 +45,7 @@
v-model="friendExportContent" v-model="friendExportContent"
:rows="15" :rows="15"
readonly readonly
style="margin-top: 15px" input-class="resize-none mt-4"
input-class="resize-none"
@click="handleCopyFriendExportData" /> @click="handleCopyFriendExportData" />
</DialogContent> </DialogContent>
</Dialog> </Dialog>
@@ -23,8 +23,8 @@
<InputGroupTextareaField <InputGroupTextareaField
v-model="friendImportDialog.input" v-model="friendImportDialog.input"
:rows="10" :rows="10"
style="margin-top: 10px"
input-class="resize-none" /> input-class="resize-none mt-2" />
<div> <div>
<div class="mb-2"> <div class="mb-2">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
@@ -47,10 +47,10 @@
</SelectContent> </SelectContent>
</Select> </Select>
<Select <Select class="ml-2"
:model-value="friendImportLocalFavoriteGroupSelection" :model-value="friendImportLocalFavoriteGroupSelection"
@update:modelValue="handleFriendImportLocalGroupSelect" @update:modelValue="handleFriendImportLocalGroupSelect"
style="margin-left: 10px"> >
<SelectTrigger size="sm"> <SelectTrigger size="sm">
<SelectValue :placeholder="t('dialog.world_import.select_local_group_placeholder')" /> <SelectValue :placeholder="t('dialog.world_import.select_local_group_placeholder')" />
</SelectTrigger> </SelectTrigger>
@@ -63,7 +63,7 @@
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
<span v-if="friendImportDialog.friendImportFavoriteGroup" style="margin-left: 5px"> <span class="ml-1.5" v-if="friendImportDialog.friendImportFavoriteGroup">
{{ friendImportTable.data.length }} / {{ friendImportTable.data.length }} /
{{ {{
friendImportDialog.friendImportFavoriteGroup.capacity - friendImportDialog.friendImportFavoriteGroup.capacity -
@@ -92,7 +92,7 @@
</Button> </Button>
</div> </div>
</div> </div>
<span v-if="friendImportDialog.importProgress" style="margin: 10px"> <span class="m-2" v-if="friendImportDialog.importProgress">
<Spinner class="inline-block ml-2 mr-2" /> <Spinner class="inline-block ml-2 mr-2" />
{{ t('dialog.friend_import.import_progress') }} {{ friendImportDialog.importProgress }}/{{ {{ t('dialog.friend_import.import_progress') }} {{ friendImportDialog.importProgress }}/{{
friendImportDialog.importProgressTotal friendImportDialog.importProgressTotal
@@ -103,7 +103,7 @@
<Button size="sm" variant="secondary" @click="friendImportDialog.errors = ''"> <Button size="sm" variant="secondary" @click="friendImportDialog.errors = ''">
{{ t('dialog.friend_import.clear_errors') }} {{ t('dialog.friend_import.clear_errors') }}
</Button> </Button>
<h2 style="font-weight: bold; margin: 5px 0">{{ t('dialog.friend_import.errors') }}</h2> <h2 class="my-1.5 mx-0" style="font-weight: bold">{{ t('dialog.friend_import.errors') }}</h2>
<pre style="white-space: pre-wrap; font-size: 12px" v-text="friendImportDialog.errors"></pre> <pre style="white-space: pre-wrap; font-size: 12px" v-text="friendImportDialog.errors"></pre>
</template> </template>
<DataTableLayout <DataTableLayout
@@ -112,7 +112,7 @@
:loading="friendImportDialog.loading" :loading="friendImportDialog.loading"
:table-style="tableStyle" :table-style="tableStyle"
:show-pagination="false" :show-pagination="false"
style="margin-top: 10px" /> style="margin-top: 8px" />
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</template> </template>
@@ -5,7 +5,7 @@
<DialogTitle>{{ t('dialog.world_export.header') }}</DialogTitle> <DialogTitle>{{ t('dialog.world_export.header') }}</DialogTitle>
</DialogHeader> </DialogHeader>
<div style="margin-bottom: 10px" class="flex flex-col gap-2"> <div class="flex flex-col gap-2 mb-2">
<label v-for="option in exportSelectOptions" :key="option.value" class="inline-flex items-center gap-2"> <label v-for="option in exportSelectOptions" :key="option.value" class="inline-flex items-center gap-2">
<Checkbox <Checkbox
:model-value="exportSelectedOptions.includes(option.label)" :model-value="exportSelectedOptions.includes(option.label)"
@@ -35,9 +35,9 @@
</Select> </Select>
<Select <Select
class="ml-2"
:model-value="worldExportLocalFavoriteGroupSelection" :model-value="worldExportLocalFavoriteGroupSelection"
@update:modelValue="handleWorldExportLocalGroupSelect" @update:modelValue="handleWorldExportLocalGroupSelect">
style="margin-left: 10px">
<SelectTrigger size="sm"> <SelectTrigger size="sm">
<SelectValue placeholder="Select Group" /> <SelectValue placeholder="Select Group" />
</SelectTrigger> </SelectTrigger>
@@ -58,8 +58,7 @@
v-model="worldExportContent" v-model="worldExportContent"
:rows="15" :rows="15"
readonly readonly
style="margin-top: 15px" input-class="resize-none mt-4"
input-class="resize-none"
@click="handleCopyWorldExportData" /> @click="handleCopyWorldExportData" />
</DialogContent> </DialogContent>
</Dialog> </Dialog>
@@ -20,11 +20,7 @@
</Button> </Button>
</div> </div>
</div> </div>
<InputGroupTextareaField <InputGroupTextareaField v-model="worldImportDialog.input" :rows="10" input-class="resize-none mt-2" />
v-model="worldImportDialog.input"
:rows="10"
style="margin-top: 10px"
input-class="resize-none" />
<div> <div>
<div class="mb-2"> <div class="mb-2">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
@@ -48,9 +44,9 @@
</Select> </Select>
<Select <Select
class="ml-2"
:model-value="worldImportLocalFavoriteGroupSelection" :model-value="worldImportLocalFavoriteGroupSelection"
@update:modelValue="handleWorldImportLocalGroupSelect" @update:modelValue="handleWorldImportLocalGroupSelect">
style="margin-left: 10px">
<SelectTrigger size="sm"> <SelectTrigger size="sm">
<SelectValue :placeholder="t('dialog.world_import.select_local_group_placeholder')" /> <SelectValue :placeholder="t('dialog.world_import.select_local_group_placeholder')" />
</SelectTrigger> </SelectTrigger>
@@ -63,7 +59,7 @@
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
<span v-if="worldImportDialog.worldImportFavoriteGroup" style="margin-left: 5px"> <span class="ml-1.5" v-if="worldImportDialog.worldImportFavoriteGroup">
{{ worldImportTable.data.length }} / {{ worldImportTable.data.length }} /
{{ {{
worldImportDialog.worldImportFavoriteGroup.capacity - worldImportDialog.worldImportFavoriteGroup.capacity -
@@ -92,7 +88,7 @@
</Button> </Button>
</div> </div>
</div> </div>
<span v-if="worldImportDialog.importProgress" style="margin: 10px"> <span class="m-2" v-if="worldImportDialog.importProgress">
<Spinner class="inline-block ml-2 mr-2" /> <Spinner class="inline-block ml-2 mr-2" />
{{ t('dialog.world_import.import_progress') }} {{ t('dialog.world_import.import_progress') }}
{{ worldImportDialog.importProgress }}/{{ worldImportDialog.importProgressTotal }} {{ worldImportDialog.importProgress }}/{{ worldImportDialog.importProgressTotal }}
@@ -102,7 +98,7 @@
<Button size="sm" variant="secondary" @click="worldImportDialog.errors = ''"> <Button size="sm" variant="secondary" @click="worldImportDialog.errors = ''">
{{ t('dialog.world_import.clear_errors') }} {{ t('dialog.world_import.clear_errors') }}
</Button> </Button>
<h2 style="font-weight: bold; margin: 5px 0"> <h2 class="my-1.5 mx-0" style="font-weight: bold">
{{ t('dialog.world_import.errors') }} {{ t('dialog.world_import.errors') }}
</h2> </h2>
<pre style="white-space: pre-wrap; font-size: 12px" v-text="worldImportDialog.errors"></pre> <pre style="white-space: pre-wrap; font-size: 12px" v-text="worldImportDialog.errors"></pre>
@@ -113,7 +109,7 @@
:loading="worldImportDialog.loading" :loading="worldImportDialog.loading"
:table-style="tableStyle" :table-style="tableStyle"
:show-pagination="false" :show-pagination="false"
style="margin-top: 10px" /> style="margin-top: 8px" />
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</template> </template>
@@ -218,11 +214,17 @@
} }
); );
/**
*
*/
function resetWorldImport() { function resetWorldImport() {
worldImportDialog.value.input = ''; worldImportDialog.value.input = '';
worldImportDialog.value.errors = ''; worldImportDialog.value.errors = '';
} }
/**
*
*/
async function processWorldImportList() { async function processWorldImportList() {
const D = worldImportDialog.value; const D = worldImportDialog.value;
D.loading = true; D.loading = true;
@@ -263,16 +265,27 @@
D.progressTotal = 0; D.progressTotal = 0;
} }
/**
*
* @param ref
*/
function deleteItemWorldImport(ref) { function deleteItemWorldImport(ref) {
removeFromArray(worldImportTable.value.data, ref); removeFromArray(worldImportTable.value.data, ref);
worldImportDialog.value.worldIdList.delete(ref.id); worldImportDialog.value.worldIdList.delete(ref.id);
} }
/**
*
*/
function clearWorldImportTable() { function clearWorldImportTable() {
worldImportTable.value.data = []; worldImportTable.value.data = [];
worldImportDialog.value.worldIdList = new Set(); worldImportDialog.value.worldIdList = new Set();
} }
/**
*
* @param group
*/
function selectWorldImportGroup(group) { function selectWorldImportGroup(group) {
worldImportDialog.value.worldImportLocalFavoriteGroup = null; worldImportDialog.value.worldImportLocalFavoriteGroup = null;
worldImportDialog.value.worldImportFavoriteGroup = group; worldImportDialog.value.worldImportFavoriteGroup = group;
@@ -280,6 +293,10 @@
worldImportLocalFavoriteGroupSelection.value = ''; worldImportLocalFavoriteGroupSelection.value = '';
} }
/**
*
* @param group
*/
function selectWorldImportLocalGroup(group) { function selectWorldImportLocalGroup(group) {
worldImportDialog.value.worldImportFavoriteGroup = null; worldImportDialog.value.worldImportFavoriteGroup = null;
worldImportDialog.value.worldImportLocalFavoriteGroup = group; worldImportDialog.value.worldImportLocalFavoriteGroup = group;
@@ -287,21 +304,35 @@
worldImportLocalFavoriteGroupSelection.value = group ?? ''; worldImportLocalFavoriteGroupSelection.value = group ?? '';
} }
/**
*
* @param value
*/
function handleWorldImportGroupSelect(value) { function handleWorldImportGroupSelect(value) {
worldImportFavoriteGroupSelection.value = value; worldImportFavoriteGroupSelection.value = value;
const group = favoriteWorldGroups.value.find((g) => g.name === value) ?? null; const group = favoriteWorldGroups.value.find((g) => g.name === value) ?? null;
selectWorldImportGroup(group); selectWorldImportGroup(group);
} }
/**
*
* @param value
*/
function handleWorldImportLocalGroupSelect(value) { function handleWorldImportLocalGroupSelect(value) {
worldImportLocalFavoriteGroupSelection.value = value; worldImportLocalFavoriteGroupSelection.value = value;
selectWorldImportLocalGroup(value || null); selectWorldImportLocalGroup(value || null);
} }
/**
*
*/
function cancelWorldImport() { function cancelWorldImport() {
worldImportDialog.value.loading = false; worldImportDialog.value.loading = false;
} }
/**
*
*/
async function importWorldImportTable() { async function importWorldImportTable() {
const D = worldImportDialog.value; const D = worldImportDialog.value;
if (!D.worldImportFavoriteGroup && !D.worldImportLocalFavoriteGroup) { if (!D.worldImportFavoriteGroup && !D.worldImportLocalFavoriteGroup) {
@@ -338,6 +369,12 @@
} }
} }
/**
*
* @param ref
* @param group
* @param message
*/
function addFavoriteWorld(ref, group, message) { function addFavoriteWorld(ref, group, message) {
return favoriteRequest return favoriteRequest
.addFavorite({ .addFavorite({
+3 -2
View File
@@ -8,7 +8,7 @@
:total-items="totalItems" :total-items="totalItems"
:on-page-size-change="handlePageSizeChange"> :on-page-size-change="handlePageSizeChange">
<template #toolbar> <template #toolbar>
<div style="margin: 0 0 10px; display: flex; align-items: center"> <div class="mt-0 mx-0 mb-2" style="display: flex; align-items: center">
<div style="flex: none; display: flex; align-items: center" class="mr-2"> <div style="flex: none; display: flex; align-items: center" class="mr-2">
<Popover v-model:open="popoverOpen"> <Popover v-model:open="popoverOpen">
<PopoverTrigger as-child> <PopoverTrigger as-child>
@@ -72,10 +72,11 @@
</ToggleGroupItem> </ToggleGroupItem>
</ToggleGroup> </ToggleGroup>
<InputGroupField <InputGroupField
class="ml-2"
v-model="feedTable.search" v-model="feedTable.search"
:placeholder="t('view.feed.search_placeholder')" :placeholder="t('view.feed.search_placeholder')"
clearable clearable
style="flex: 0.4; margin-left: 10px" style="flex: 0.4"
@keyup.enter="feedTableLookup" @keyup.enter="feedTableLookup"
@change="feedTableLookup" /> @change="feedTableLookup" />
</div> </div>
+3 -3
View File
@@ -68,7 +68,7 @@
<Button variant="outline" @click="showBulkUnfriendSelectionConfirm"> <Button variant="outline" @click="showBulkUnfriendSelectionConfirm">
{{ t('view.friend_list.bulk_unfriend_selection') }} {{ t('view.friend_list.bulk_unfriend_selection') }}
</Button> </Button>
<!-- el-button(size="small" @click="showBulkUnfriendAllConfirm" style="margin-right:5px") Bulk Unfriend All--> <!-- el-button(size="small" @click="showBulkUnfriendAllConfirm") Bulk Unfriend All-->
</div> </div>
<div class="flex items-center mr-2"> <div class="flex items-center mr-2">
<span class="name mr-2 text-xs">{{ t('view.friend_list.bulk_unfriend') }}</span> <span class="name mr-2 text-xs">{{ t('view.friend_list.bulk_unfriend') }}</span>
@@ -98,12 +98,12 @@
<DialogHeader> <DialogHeader>
<DialogTitle>{{ t('view.friend_list.load_dialog_title') }}</DialogTitle> <DialogTitle>{{ t('view.friend_list.load_dialog_title') }}</DialogTitle>
</DialogHeader> </DialogHeader>
<div style="margin-bottom: 10px" v-text="t('view.friend_list.load_dialog_message')"></div> <div style="margin-bottom: 8px" v-text="t('view.friend_list.load_dialog_message')"></div>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<Progress :model-value="friendsListLoadingPercent" class="h-4 w-full" /> <Progress :model-value="friendsListLoadingPercent" class="h-4 w-full" />
<span class="text-xs w-10 text-right">{{ friendsListLoadingPercent }}%</span> <span class="text-xs w-10 text-right">{{ friendsListLoadingPercent }}%</span>
</div> </div>
<div style="margin-top: 10px; text-align: right"> <div style="margin-top: 8px; text-align: right">
<span>{{ friendsListLoadingCurrent }} / {{ friendsListLoadingTotal }}</span> <span>{{ friendsListLoadingCurrent }} / {{ friendsListLoadingTotal }}</span>
</div> </div>
<DialogFooter> <DialogFooter>
+18 -2
View File
@@ -8,7 +8,7 @@
:total-items="totalItems" :total-items="totalItems"
:on-page-size-change="handlePageSizeChange"> :on-page-size-change="handlePageSizeChange">
<template #toolbar> <template #toolbar>
<div style="margin: 0 0 10px; display: flex; align-items: center"> <div class="mt-0 mx-0 mb-2" style="display: flex; align-items: center">
<Select <Select
multiple multiple
:model-value=" :model-value="
@@ -37,9 +37,10 @@
</SelectContent> </SelectContent>
</Select> </Select>
<InputGroupField <InputGroupField
class="ml-2"
v-model="friendLogTable.filters[1].value" v-model="friendLogTable.filters[1].value"
:placeholder="t('view.friend_log.search_placeholder')" :placeholder="t('view.friend_log.search_placeholder')"
style="flex: 0.4; margin-left: 10px" /> style="flex: 0.4" />
</div> </div>
</template> </template>
</DataTableLayout> </DataTableLayout>
@@ -142,13 +143,24 @@
); );
const { t } = useI18n(); const { t } = useI18n();
/**
*
*/
function saveTableFilters() { function saveTableFilters() {
configRepository.setString('VRCX_friendLogTableFilters', JSON.stringify(friendLogTable.value.filters[0].value)); configRepository.setString('VRCX_friendLogTableFilters', JSON.stringify(friendLogTable.value.filters[0].value));
} }
/**
*
* @param value
*/
function handleFriendLogFilterChange(value) { function handleFriendLogFilterChange(value) {
friendLogTable.value.filters[0].value = Array.isArray(value) ? value : []; friendLogTable.value.filters[0].value = Array.isArray(value) ? value : [];
saveTableFilters(); saveTableFilters();
} }
/**
*
* @param row
*/
function deleteFriendLogPrompt(row) { function deleteFriendLogPrompt(row) {
modalStore modalStore
.confirm({ .confirm({
@@ -158,6 +170,10 @@
.then(({ ok }) => ok && deleteFriendLog(row)) .then(({ ok }) => ok && deleteFriendLog(row))
.catch(() => {}); .catch(() => {});
} }
/**
*
* @param row
*/
function deleteFriendLog(row) { function deleteFriendLog(row) {
removeFromArray(friendLogTable.value.data, row); removeFromArray(friendLogTable.value.data, row);
database.deleteFriendLogHistory(row.rowId); database.deleteFriendLogHistory(row.rowId);
@@ -429,6 +429,10 @@
}); });
}); });
/**
*
* @param groupKey
*/
function toggleGroupCollapse(groupKey) { function toggleGroupCollapse(groupKey) {
if (collapsedGroups.has(groupKey)) { if (collapsedGroups.has(groupKey)) {
collapsedGroups.delete(groupKey); collapsedGroups.delete(groupKey);
@@ -898,6 +902,9 @@
} }
}); });
/**
*
*/
async function loadInitialSettings() { async function loadInitialSettings() {
try { try {
const [storedScale, storedSpacing, storedShowSameInstance] = await Promise.all([ const [storedScale, storedSpacing, storedShowSameInstance] = await Promise.all([
@@ -954,7 +961,7 @@
display: flex; display: flex;
gap: 20px; gap: 20px;
align-items: center; align-items: center;
padding: 6px 2px 0 2px; padding: 8px 2px 0 2px;
} }
.friend-view__tabs { .friend-view__tabs {
@@ -1002,7 +1009,7 @@
} }
.friend-view__virtual-row--header { .friend-view__virtual-row--header {
padding: 4px 10px; padding: 4px 8px;
padding-bottom: calc(var(--friend-card-gap, 14px) - 4px); padding-bottom: calc(var(--friend-card-gap, 14px) - 4px);
} }
@@ -1044,7 +1051,7 @@
.friend-view__scale-control { .friend-view__scale-control {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px;
min-width: 160px; min-width: 160px;
} }
@@ -337,7 +337,7 @@
} }
.friend-card__signature { .friend-card__signature {
margin-top: calc(6px * var(--card-spacing)); margin-top: calc(8px * var(--card-spacing));
font-size: calc(13px * var(--card-scale)); font-size: calc(13px * var(--card-scale));
line-height: 1.4; line-height: 1.4;
overflow: hidden; overflow: hidden;
@@ -352,7 +352,7 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
min-height: calc(40px * var(--card-scale)); min-height: calc(40px * var(--card-scale));
padding: calc(6px * var(--card-scale)) calc(10px * var(--card-scale)); padding: calc(8px * var(--card-scale)) calc(8px * var(--card-scale));
border-radius: calc(var(--radius-lg) * var(--card-scale)); border-radius: calc(var(--radius-lg) * var(--card-scale));
font-size: calc(12px * var(--card-scale)); font-size: calc(12px * var(--card-scale));
line-height: 1.3; line-height: 1.3;
+24 -3
View File
@@ -8,8 +8,8 @@
:total-items="totalItems" :total-items="totalItems"
:on-page-size-change="handlePageSizeChange"> :on-page-size-change="handlePageSizeChange">
<template #toolbar> <template #toolbar>
<div style="margin: 0 0 10px; display: flex; align-items: center"> <div class="mt-0 mx-0 mb-2" style="display: flex; align-items: center">
<div style="flex: none; margin-right: 10px; display: flex; align-items: center"> <div class="mr-2" style="flex: none; display: flex; align-items: center">
<TooltipWrapper side="bottom" :content="t('view.feed.favorites_only_tooltip')"> <TooltipWrapper side="bottom" :content="t('view.feed.favorites_only_tooltip')">
<div> <div>
<Toggle <Toggle
@@ -55,10 +55,11 @@
</SelectContent> </SelectContent>
</Select> </Select>
<InputGroupField <InputGroupField
class="ml-2"
v-model="gameLogTable.search" v-model="gameLogTable.search"
:placeholder="t('view.game_log.search_placeholder')" :placeholder="t('view.game_log.search_placeholder')"
clearable clearable
style="flex: 0.4; margin-left: 10px" style="flex: 0.4"
@keyup.enter="gameLogTableLookup" @keyup.enter="gameLogTableLookup"
@change="gameLogTableLookup" /> @change="gameLogTableLookup" />
</div> </div>
@@ -90,6 +91,10 @@
const vrcxStore = useVrcxStore(); const vrcxStore = useVrcxStore();
const modalStore = useModalStore(); const modalStore = useModalStore();
/**
*
* @param row
*/
function getGameLogCreatedAt(row) { function getGameLogCreatedAt(row) {
if (typeof row?.created_at === 'string' && row.created_at.length > 0) { if (typeof row?.created_at === 'string' && row.created_at.length > 0) {
return row.created_at; return row.created_at;
@@ -112,6 +117,10 @@
paginationHeight: 52 paginationHeight: 52
}); });
/**
*
* @param row
*/
function deleteGameLogEntryPrompt(row) { function deleteGameLogEntryPrompt(row) {
modalStore modalStore
.confirm({ .confirm({
@@ -122,6 +131,10 @@
.catch(() => {}); .catch(() => {});
} }
/**
*
* @param row
*/
function deleteGameLogEntry(row) { function deleteGameLogEntry(row) {
removeFromArray(gameLogTableData.value, row); removeFromArray(gameLogTableData.value, row);
database.deleteGameLogEntry(row); database.deleteGameLogEntry(row);
@@ -133,6 +146,10 @@
onDeletePrompt: deleteGameLogEntryPrompt onDeletePrompt: deleteGameLogEntryPrompt
}); });
/**
*
* @param value
*/
function handleGameLogFilterChange(value) { function handleGameLogFilterChange(value) {
gameLogTable.value.filter = Array.isArray(value) ? value : []; gameLogTable.value.filter = Array.isArray(value) ? value : [];
gameLogTableLookup(); gameLogTableLookup();
@@ -140,6 +157,10 @@
const pageSizes = computed(() => appearanceSettingsStore.tablePageSizes); const pageSizes = computed(() => appearanceSettingsStore.tablePageSizes);
/**
*
* @param row
*/
function getGameLogRowId(row) { function getGameLogRowId(row) {
if (row?.rowId != null) return `row:${row.rowId}`; if (row?.rowId != null) return `row:${row.rowId}`;
+4 -4
View File
@@ -1,6 +1,6 @@
<template> <template>
<div class="x-login-container"> <div class="x-login-container">
<div style="position: absolute; top: 0; left: 0; margin: 5px"> <div class="m-1.5" style="position: absolute; top: 0; left: 0">
<LoginSettingsDialog /> <LoginSettingsDialog />
<TooltipWrapper v-if="!noUpdater" side="top" :content="t('view.login.updater')"> <TooltipWrapper v-if="!noUpdater" side="top" :content="t('view.login.updater')">
<Button class="rounded-full mr-2 text-xs" size="icon-sm" variant="ghost" @click="showVRCXUpdateDialog" <Button class="rounded-full mr-2 text-xs" size="icon-sm" variant="ghost" @click="showVRCXUpdateDialog"
@@ -29,7 +29,7 @@
<div class="x-login"> <div class="x-login">
<div class="x-login-form-container"> <div class="x-login-form-container">
<div> <div>
<h2 style="font-weight: bold; text-align: center; margin: 0">{{ t('view.login.login') }}</h2> <h2 class="m-0" style="font-weight: bold; text-align: center">{{ t('view.login.login') }}</h2>
<form id="login-form" @submit.prevent="onSubmit"> <form id="login-form" @submit.prevent="onSubmit">
<FieldGroup class="gap-3"> <FieldGroup class="gap-3">
<VeeField v-slot="{ field, errors }" name="username"> <VeeField v-slot="{ field, errors }" name="username">
@@ -95,10 +95,10 @@
<hr v-if="Object.keys(savedCredentials).length !== 0" class="x-vertical-divider" /> <hr v-if="Object.keys(savedCredentials).length !== 0" class="x-vertical-divider" />
<div v-if="Object.keys(savedCredentials).length !== 0"> <div v-if="Object.keys(savedCredentials).length !== 0">
<h2 style="font-weight: bold; text-align: center; margin: 0"> <h2 class="m-0" style="font-weight: bold; text-align: center">
{{ t('view.login.savedAccounts') }} {{ t('view.login.savedAccounts') }}
</h2> </h2>
<div class="x-scroll-wrapper" style="margin-top: 10px"> <div class="x-scroll-wrapper mt-2">
<div class="x-saved-account-list"> <div class="x-saved-account-list">
<div <div
v-for="user in savedCredentials" v-for="user in savedCredentials"
+28 -2
View File
@@ -57,8 +57,7 @@
v-model="notificationTable.filters[1].value" v-model="notificationTable.filters[1].value"
:placeholder="t('view.notification.search_placeholder')" :placeholder="t('view.notification.search_placeholder')"
clearable clearable
class="flex-[0.4]" class="flex-[0.4] my-0 mx-2" />
style="margin: 0 10px" />
<TooltipWrapper side="bottom" :content="t('view.notification.refresh_tooltip')"> <TooltipWrapper side="bottom" :content="t('view.notification.refresh_tooltip')">
<Button <Button
class="rounded-full" class="rounded-full"
@@ -139,6 +138,10 @@
paginationHeight: 52 paginationHeight: 52
}); });
/**
*
* @param row
*/
function getNotificationCreatedAt(row) { function getNotificationCreatedAt(row) {
if (typeof row?.created_at === 'string' && row.created_at.length > 0) { if (typeof row?.created_at === 'string' && row.created_at.length > 0) {
return row.created_at; return row.created_at;
@@ -149,6 +152,10 @@
return ''; return '';
} }
/**
*
* @param row
*/
function getNotificationCreatedAtTs(row) { function getNotificationCreatedAtTs(row) {
const createdAtRaw = row?.created_at ?? row?.createdAt; const createdAtRaw = row?.created_at ?? row?.createdAt;
if (typeof createdAtRaw === 'number') { if (typeof createdAtRaw === 'number') {
@@ -263,6 +270,9 @@
const sendInviteRequestResponseDialogVisible = ref(false); const sendInviteRequestResponseDialogVisible = ref(false);
/**
*
*/
function saveTableFilters() { function saveTableFilters() {
configRepository.setString( configRepository.setString(
'VRCX_notificationTableFilters', 'VRCX_notificationTableFilters',
@@ -270,15 +280,27 @@
); );
} }
/**
*
* @param value
*/
function handleNotificationFilterChange(value) { function handleNotificationFilterChange(value) {
notificationTable.value.filters[0].value = Array.isArray(value) ? value : []; notificationTable.value.filters[0].value = Array.isArray(value) ? value : [];
saveTableFilters(); saveTableFilters();
} }
/**
*
* @param url
*/
function getSmallThumbnailUrl(url) { function getSmallThumbnailUrl(url) {
return convertFileUrlToImageUrl(url); return convertFileUrlToImageUrl(url);
} }
/**
*
* @param invite
*/
function showSendInviteResponseDialog(invite) { function showSendInviteResponseDialog(invite) {
sendInviteResponseDialog.value.invite = invite; sendInviteResponseDialog.value.invite = invite;
sendInviteResponseDialog.value.messageSlot = {}; sendInviteResponseDialog.value.messageSlot = {};
@@ -287,6 +309,10 @@
sendInviteResponseDialogVisible.value = true; sendInviteResponseDialogVisible.value = true;
} }
/**
*
* @param invite
*/
function showSendInviteRequestResponseDialog(invite) { function showSendInviteRequestResponseDialog(invite) {
sendInviteResponseDialog.value.invite = invite; sendInviteResponseDialog.value.invite = invite;
sendInviteResponseDialog.value.messageSlot = {}; sendInviteResponseDialog.value.messageSlot = {};
@@ -11,7 +11,7 @@
</template> </template>
<DataTableLayout <DataTableLayout
style="margin-top: 10px" style="margin-top: 8px"
:table="inviteRequestResponseTable" :table="inviteRequestResponseTable"
:loading="false" :loading="false"
:show-pagination="false" :show-pagination="false"
@@ -102,10 +102,18 @@
initialSorting: [{ id: 'slot', desc: false }] initialSorting: [{ id: 'slot', desc: false }]
}); });
/**
*
* @param row
*/
function handleInviteRequestResponseRowClick(row) { function handleInviteRequestResponseRowClick(row) {
showSendInviteResponseConfirmDialog(row?.original); showSendInviteResponseConfirmDialog(row?.original);
} }
/**
*
* @param row
*/
function showEditAndSendInviteResponseDialog(row) { function showEditAndSendInviteResponseDialog(row) {
emit('update:sendInviteResponseDialog', { ...props.sendInviteResponseDialog, messageSlot: row }); emit('update:sendInviteResponseDialog', { ...props.sendInviteResponseDialog, messageSlot: row });
editAndSendInviteResponseDialog.value = { editAndSendInviteResponseDialog.value = {
@@ -114,15 +122,25 @@
}; };
} }
/**
*
* @param row
*/
function showSendInviteResponseConfirmDialog(row) { function showSendInviteResponseConfirmDialog(row) {
emit('update:sendInviteResponseDialog', { ...props.sendInviteResponseDialog, messageSlot: row }); emit('update:sendInviteResponseDialog', { ...props.sendInviteResponseDialog, messageSlot: row });
sendInviteResponseConfirmDialog.value.visible = true; sendInviteResponseConfirmDialog.value.visible = true;
} }
/**
*
*/
function closeInviteDialog() { function closeInviteDialog() {
cancelSendInviteRequestResponse(); cancelSendInviteRequestResponse();
} }
/**
*
*/
function closeResponseConfirmDialog() { function closeResponseConfirmDialog() {
sendInviteResponseConfirmDialog.value.visible = false; sendInviteResponseConfirmDialog.value.visible = false;
editAndSendInviteResponseDialog.value.visible = false; editAndSendInviteResponseDialog.value.visible = false;
@@ -132,6 +150,9 @@
// inviteMessagesRequest.refreshInviteMessageTableData(arg); // inviteMessagesRequest.refreshInviteMessageTableData(arg);
// } // }
/**
*
*/
function cancelSendInviteRequestResponse() { function cancelSendInviteRequestResponse() {
emit('update:sendInviteRequestResponseDialogVisible', false); emit('update:sendInviteRequestResponseDialogVisible', false);
} }
@@ -9,7 +9,7 @@
</template> </template>
<DataTableLayout <DataTableLayout
style="margin-top: 10px" style="margin-top: 8px"
:table="inviteResponseTable" :table="inviteResponseTable"
:loading="false" :loading="false"
:show-pagination="false" :show-pagination="false"
@@ -101,23 +101,40 @@
initialSorting: [{ id: 'slot', desc: false }] initialSorting: [{ id: 'slot', desc: false }]
}); });
/**
*
* @param row
*/
function handleInviteResponseRowClick(row) { function handleInviteResponseRowClick(row) {
showSendInviteResponseConfirmDialog(row?.original); showSendInviteResponseConfirmDialog(row?.original);
} }
/**
*
*/
function closeInviteDialog() { function closeInviteDialog() {
cancelSendInviteResponse(); cancelSendInviteResponse();
} }
/**
*
*/
function cancelSendInviteResponse() { function cancelSendInviteResponse() {
emit('update:sendInviteResponseDialogVisible', false); emit('update:sendInviteResponseDialogVisible', false);
} }
/**
*
*/
function closeResponseConfirmDialog() { function closeResponseConfirmDialog() {
sendInviteResponseConfirmDialog.value.visible = false; sendInviteResponseConfirmDialog.value.visible = false;
editAndSendInviteResponseDialog.value.visible = false; editAndSendInviteResponseDialog.value.visible = false;
} }
/**
*
* @param row
*/
function showEditAndSendInviteResponseDialog(row) { function showEditAndSendInviteResponseDialog(row) {
emit('update:sendInviteResponseDialog', { ...props.sendInviteResponseDialog, messageSlot: row }); emit('update:sendInviteResponseDialog', { ...props.sendInviteResponseDialog, messageSlot: row });
editAndSendInviteResponseDialog.value = { editAndSendInviteResponseDialog.value = {
@@ -125,6 +142,10 @@
visible: true visible: true
}; };
} }
/**
*
* @param row
*/
function showSendInviteResponseConfirmDialog(row) { function showSendInviteResponseConfirmDialog(row) {
emit('update:sendInviteResponseDialog', { ...props.sendInviteResponseDialog, messageSlot: row }); emit('update:sendInviteResponseDialog', { ...props.sendInviteResponseDialog, messageSlot: row });
sendInviteResponseConfirmDialog.value.visible = true; sendInviteResponseConfirmDialog.value.visible = true;
+18 -27
View File
@@ -12,7 +12,7 @@
style="flex: none; width: 160px; height: 120px; border-radius: var(--radius-md)" style="flex: none; width: 160px; height: 120px; border-radius: var(--radius-md)"
@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 class="ml-2" style="display: flex; flex-direction: column; min-width: 320px; width: 100%">
<div class="flex items-center"> <div class="flex items-center">
<span <span
class="cursor-pointer" class="cursor-pointer"
@@ -41,27 +41,24 @@
@click="showUserDialog(currentInstanceWorld.ref.authorId)" @click="showUserDialog(currentInstanceWorld.ref.authorId)"
v-text="currentInstanceWorld.ref.authorName"></span> v-text="currentInstanceWorld.ref.authorName"></span>
</div> </div>
<div style="margin-top: 5px"> <div class="mt-1.5">
<Badge v-if="currentInstanceWorld.ref.$isLabs" variant="outline" style="margin-right: 5px"> <Badge class="mr-1.5" v-if="currentInstanceWorld.ref.$isLabs" variant="outline">
{{ t('dialog.world.tags.labs') }} {{ t('dialog.world.tags.labs') }}
</Badge> </Badge>
<Badge <Badge
class="mr-1.5"
v-else-if="currentInstanceWorld.ref.releaseStatus === 'public'" v-else-if="currentInstanceWorld.ref.releaseStatus === 'public'"
variant="outline" variant="outline">
style="margin-right: 5px">
{{ t('dialog.world.tags.public') }} {{ t('dialog.world.tags.public') }}
</Badge> </Badge>
<Badge <Badge
class="mr-1.5"
v-else-if="currentInstanceWorld.ref.releaseStatus === 'private'" v-else-if="currentInstanceWorld.ref.releaseStatus === 'private'"
variant="outline" variant="outline">
style="margin-right: 5px">
{{ t('dialog.world.tags.private') }} {{ t('dialog.world.tags.private') }}
</Badge> </Badge>
<TooltipWrapper v-if="currentInstanceWorld.isPC" side="top" content="PC"> <TooltipWrapper v-if="currentInstanceWorld.isPC" side="top" content="PC">
<Badge <Badge class="text-platform-pc border-platform-pc! mr-1.5" variant="outline"
class="text-platform-pc border-platform-pc!"
variant="outline"
style="margin-right: 5px"
><Monitor class="h-4 w-4" /> ><Monitor class="h-4 w-4" />
<span <span
v-if="currentInstanceWorld.fileAnalysis.standalonewindows?._fileSize" v-if="currentInstanceWorld.fileAnalysis.standalonewindows?._fileSize"
@@ -71,10 +68,7 @@
</Badge> </Badge>
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="currentInstanceWorld.isQuest" side="top" content="Android"> <TooltipWrapper v-if="currentInstanceWorld.isQuest" side="top" content="Android">
<Badge <Badge class="text-platform-quest border-platform-quest! mr-1.5" variant="outline"
class="text-platform-quest border-platform-quest!"
variant="outline"
style="margin-right: 5px"
><Smartphone class="h-4 w-4" /> ><Smartphone class="h-4 w-4" />
<span <span
v-if="currentInstanceWorld.fileAnalysis.android?._fileSize" v-if="currentInstanceWorld.fileAnalysis.android?._fileSize"
@@ -84,10 +78,7 @@
</Badge> </Badge>
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="currentInstanceWorld.isIos" side="top" content="iOS"> <TooltipWrapper v-if="currentInstanceWorld.isIos" side="top" content="iOS">
<Badge <Badge class="text-platform-ios border-platform-ios mr-1.5" variant="outline"
class="text-platform-ios border-platform-ios"
variant="outline"
style="margin-right: 5px"
><Apple class="h-4 w-4 text-platform-ios" /> ><Apple class="h-4 w-4 text-platform-ios" />
<span <span
v-if="currentInstanceWorld.fileAnalysis.ios?._fileSize" v-if="currentInstanceWorld.fileAnalysis.ios?._fileSize"
@@ -97,18 +88,18 @@
</Badge> </Badge>
</TooltipWrapper> </TooltipWrapper>
<Badge <Badge
class="mr-1.5 mt-1.5"
v-if="currentInstanceWorld.avatarScalingDisabled" v-if="currentInstanceWorld.avatarScalingDisabled"
variant="outline" variant="outline">
style="margin-right: 5px; margin-top: 5px">
{{ t('dialog.world.tags.avatar_scaling_disabled') }} {{ t('dialog.world.tags.avatar_scaling_disabled') }}
</Badge> </Badge>
<Badge v-if="currentInstanceWorld.inCache" variant="outline" style="margin-right: 5px"> <Badge class="mr-1.5" v-if="currentInstanceWorld.inCache" variant="outline">
<span>{{ currentInstanceWorld.cacheSize }} {{ t('dialog.world.tags.cache') }}</span> <span>{{ currentInstanceWorld.cacheSize }} {{ t('dialog.world.tags.cache') }}</span>
</Badge> </Badge>
</div> </div>
<div style="margin-top: 5px"> <div class="mt-1.5">
<LocationWorld :locationobject="currentInstanceLocation" :currentuserid="currentUser.id" /> <LocationWorld :locationobject="currentInstanceLocation" :currentuserid="currentUser.id" />
<span v-if="lastLocation.playerList.size > 0" style="margin-left: 5px"> <span class="ml-1.5" v-if="lastLocation.playerList.size > 0">
{{ lastLocation.playerList.size }} {{ lastLocation.playerList.size }}
<template v-if="lastLocation.friendList.size > 0" <template v-if="lastLocation.friendList.size > 0"
>({{ lastLocation.friendList.size }})</template >({{ lastLocation.friendList.size }})</template
@@ -116,14 +107,14 @@
&nbsp;&horbar; <Timer v-if="lastLocation.date" :epoch="lastLocation.date" /> &nbsp;&horbar; <Timer v-if="lastLocation.date" :epoch="lastLocation.date" />
</span> </span>
</div> </div>
<div style="margin-top: 5px"> <div class="mt-1.5">
<span <span
v-show="currentInstanceWorld.ref.name !== currentInstanceWorld.ref.description" v-show="currentInstanceWorld.ref.name !== currentInstanceWorld.ref.description"
class="inline-block max-w-full align-middle text-xs break-words" class="inline-block max-w-full align-middle text-xs break-words"
v-text="currentInstanceWorld.ref.description"></span> v-text="currentInstanceWorld.ref.description"></span>
</div> </div>
</div> </div>
<div style="display: flex; flex-direction: column; margin-left: 20px"> <div class="ml-5" style="display: flex; flex-direction: column">
<div class="box-border flex items-center p-1.5 text-[13px] cursor-default"> <div class="box-border flex items-center p-1.5 text-[13px] cursor-default">
<div class="flex-1 overflow-hidden"> <div class="flex-1 overflow-hidden">
<span class="block truncate font-medium leading-[18px]">{{ <span class="block truncate font-medium leading-[18px]">{{
@@ -162,7 +153,7 @@
</div> </div>
</div> </div>
<div v-if="photonLoggingEnabled" ref="playerListPhotonRef" style="margin-bottom: 10px"> <div class="mb-2" v-if="photonLoggingEnabled" ref="playerListPhotonRef">
<PhotonEventTable @show-chatbox-blacklist="showChatboxBlacklistDialog" /> <PhotonEventTable @show-chatbox-blacklist="showChatboxBlacklistDialog" />
</div> </div>
@@ -1,6 +1,6 @@
<template> <template>
<div class="mt-5"> <div class="mt-5">
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px; flex-wrap: wrap"> <div class="gap-2 mb-2" style="display: flex; align-items: center; flex-wrap: wrap">
<Select <Select
:model-value="photonEventTableTypeFilter" :model-value="photonEventTableTypeFilter"
multiple multiple
@@ -39,14 +39,14 @@
<TabsUnderline default-value="current" :items="photonTabs" :unmount-on-hide="false"> <TabsUnderline default-value="current" :items="photonTabs" :unmount-on-hide="false">
<template #current> <template #current>
<DataTableLayout <DataTableLayout
class="min-w-0 w-full" class="min-w-0 w-full mb-2"
:table="currentTable" :table="currentTable"
:loading="false" :loading="false"
:table-style="tableStyle" :table-style="tableStyle"
:page-sizes="pageSizes" :page-sizes="pageSizes"
:total-items="currentTotal" :total-items="currentTotal"
:on-page-size-change="handleCurrentPageSizeChange" :on-page-size-change="handleCurrentPageSizeChange"
style="margin-bottom: 10px" /> />
</template> </template>
<template #previous> <template #previous>
<DataTableLayout <DataTableLayout
@@ -57,7 +57,7 @@
:page-sizes="pageSizes" :page-sizes="pageSizes"
:total-items="previousTotal" :total-items="previousTotal"
:on-page-size-change="handlePreviousPageSizeChange" :on-page-size-change="handlePreviousPageSizeChange"
style="margin-bottom: 10px" /> style="margin-bottom: 8px" />
</template> </template>
</TabsUnderline> </TabsUnderline>
</div> </div>
@@ -7,11 +7,11 @@
<div v-if="chatboxBlacklistDialog.visible"> <div v-if="chatboxBlacklistDialog.visible">
<h2>{{ t('dialog.chatbox_blacklist.keyword_blacklist') }}</h2> <h2>{{ t('dialog.chatbox_blacklist.keyword_blacklist') }}</h2>
<InputGroupAction <InputGroupAction
class="mt-1.5"
v-for="(item, index) in chatboxBlacklist" v-for="(item, index) in chatboxBlacklist"
:key="index" :key="index"
v-model="chatboxBlacklist[index]" v-model="chatboxBlacklist[index]"
size="sm" size="sm"
style="margin-top: 5px"
@change="saveChatboxBlacklist"> @change="saveChatboxBlacklist">
<template #actions> <template #actions>
<Button <Button
@@ -23,7 +23,7 @@
</Button> </Button>
</template> </template>
</InputGroupAction> </InputGroupAction>
<Button size="sm" variant="outline" style="margin-top: 5px" @click="chatboxBlacklist.push('')"> <Button size="sm" variant="outline" style="margin-top: 6px" @click="chatboxBlacklist.push('')">
{{ t('dialog.chatbox_blacklist.add_item') }} {{ t('dialog.chatbox_blacklist.add_item') }}
</Button> </Button>
<br /> <br />
@@ -32,12 +32,12 @@
v-for="user in chatboxUserBlacklist" v-for="user in chatboxUserBlacklist"
:key="user[0]" :key="user[0]"
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px"> style="margin-right: 6px; margin-top: 6px">
<span>{{ user[1] }}</span> <span>{{ user[1] }}</span>
<button <button
type="button" type="button"
style=" style="
margin-left: 6px; margin-left: 8px;
border: none; border: none;
background: transparent; background: transparent;
padding: 0; padding: 0;
@@ -81,6 +81,10 @@
const emit = defineEmits(['deleteChatboxUserBlacklist']); const emit = defineEmits(['deleteChatboxUserBlacklist']);
/**
*
* @param userId
*/
function deleteChatboxUserBlacklist(userId) { function deleteChatboxUserBlacklist(userId) {
emit('deleteChatboxUserBlacklist', userId); emit('deleteChatboxUserBlacklist', userId);
} }
+18 -18
View File
@@ -1,6 +1,6 @@
<template> <template>
<div class="x-container"> <div class="x-container">
<div style="margin: 0 0 10px; display: flex; align-items: center"> <div class="mt-0 mx-0 mb-2" style="display: flex; align-items: center">
<InputGroupField <InputGroupField
:model-value="searchText" :model-value="searchText"
:placeholder="t('view.search.search_placeholder')" :placeholder="t('view.search.search_placeholder')"
@@ -15,18 +15,18 @@
</TooltipWrapper> </TooltipWrapper>
</div> </div>
<TabsUnderline <TabsUnderline
class="mt-4"
v-model="activeSearchTab" v-model="activeSearchTab"
:items="searchTabs" :items="searchTabs"
aria-label="Search tabs" aria-label="Search tabs"
:unmount-on-hide="false" :unmount-on-hide="false">
style="margin-top: 15px">
<template #user> <template #user>
<div style="min-height: 60px"> <div style="min-height: 60px">
<label class="inline-flex items-center gap-2" style="margin-left: 10px"> <label class="inline-flex items-center gap-2 ml-2">
<Checkbox v-model="searchUserByBio" /> <Checkbox v-model="searchUserByBio" />
<span>{{ t('view.search.user.search_by_bio') }}</span> <span>{{ t('view.search.user.search_by_bio') }}</span>
</label> </label>
<label class="inline-flex items-center gap-2" style="margin-left: 10px"> <label class="inline-flex items-center gap-2 ml-2">
<Checkbox v-model="searchUserSortByLastLoggedIn" /> <Checkbox v-model="searchUserSortByLastLoggedIn" />
<span>{{ t('view.search.user.sort_by_last_logged_in') }}</span> <span>{{ t('view.search.user.sort_by_last_logged_in') }}</span>
</label> </label>
@@ -59,7 +59,7 @@
</div> </div>
</div> </div>
</div> </div>
<ButtonGroup v-if="searchUserResults.length" style="margin-top: 15px"> <ButtonGroup class="mt-4" v-if="searchUserResults.length">
<Button <Button
variant="outline" variant="outline"
size="sm" size="sm"
@@ -85,7 +85,7 @@
<Select <Select
:model-value="searchWorldCategoryIndex" :model-value="searchWorldCategoryIndex"
@update:modelValue="handleSearchWorldCategorySelect" @update:modelValue="handleSearchWorldCategorySelect"
style="margin-bottom: 15px"> style="margin-bottom: 16px">
<SelectTrigger size="sm"> <SelectTrigger size="sm">
<SelectValue :placeholder="t('view.search.world.category')" /> <SelectValue :placeholder="t('view.search.world.category')" />
</SelectTrigger> </SelectTrigger>
@@ -100,7 +100,7 @@
</SelectGroup> </SelectGroup>
</SelectContent> </SelectContent>
</Select> </Select>
<label class="inline-flex items-center gap-2" style="margin-left: 10px"> <label class="inline-flex items-center gap-2" style="margin-left: 8px">
<Checkbox v-model="searchWorldLabs" /> <Checkbox v-model="searchWorldLabs" />
<span>{{ t('view.search.world.community_lab') }}</span> <span>{{ t('view.search.world.community_lab') }}</span>
</label> </label>
@@ -126,7 +126,7 @@
</div> </div>
</div> </div>
</div> </div>
<ButtonGroup v-if="searchWorldResults.length" style="margin-top: 15px"> <ButtonGroup v-if="searchWorldResults.length" style="margin-top: 16px">
<Button <Button
variant="outline" variant="outline"
size="sm" size="sm"
@@ -154,7 +154,7 @@
v-if="avatarRemoteDatabaseProviderList.length > 1" v-if="avatarRemoteDatabaseProviderList.length > 1"
:model-value="avatarRemoteDatabaseProvider" :model-value="avatarRemoteDatabaseProvider"
@update:modelValue="setAvatarProvider" @update:modelValue="setAvatarProvider"
style="margin-right: 5px"> style="margin-right: 6px">
<SelectTrigger size="sm"> <SelectTrigger size="sm">
<SelectValue :placeholder="t('view.search.avatar.search_provider')" /> <SelectValue :placeholder="t('view.search.avatar.search_provider')" />
</SelectTrigger> </SelectTrigger>
@@ -180,7 +180,7 @@
<RefreshCw v-else /> <RefreshCw v-else />
</Button> </Button>
</TooltipWrapper> </TooltipWrapper>
<span style="font-size: 14px; margin-left: 5px; margin-right: 5px">{{ <span style="font-size: 14px; margin-left: 6px; margin-right: 6px">{{
t('view.search.avatar.result_count', { t('view.search.avatar.result_count', {
count: searchAvatarResults.length count: searchAvatarResults.length
}) })
@@ -190,7 +190,7 @@
<RadioGroup <RadioGroup
:model-value="searchAvatarFilter" :model-value="searchAvatarFilter"
class="flex items-center gap-4" class="flex items-center gap-4"
style="margin: 5px" style="margin: 6px"
@update:modelValue="handleSearchAvatarFilterChange"> @update:modelValue="handleSearchAvatarFilterChange">
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<RadioGroupItem id="searchAvatarFilter-all" value="all" /> <RadioGroupItem id="searchAvatarFilter-all" value="all" />
@@ -211,7 +211,7 @@
<RadioGroup <RadioGroup
:model-value="searchAvatarFilterRemote" :model-value="searchAvatarFilterRemote"
class="flex items-center gap-4" class="flex items-center gap-4"
style="margin: 5px" style="margin: 6px"
@update:modelValue="handleSearchAvatarFilterRemoteChange"> @update:modelValue="handleSearchAvatarFilterRemoteChange">
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<RadioGroupItem id="searchAvatarFilterRemote-all" value="all" /> <RadioGroupItem id="searchAvatarFilterRemote-all" value="all" />
@@ -239,7 +239,7 @@
<Select <Select
:model-value="searchAvatarSort" :model-value="searchAvatarSort"
:disabled="searchAvatarFilterRemote !== 'local'" :disabled="searchAvatarFilterRemote !== 'local'"
style="margin: 5px" style="margin: 6px"
@update:modelValue="handleSearchAvatarSortChange"> @update:modelValue="handleSearchAvatarSortChange">
<SelectTrigger size="sm"> <SelectTrigger size="sm">
<SelectValue :placeholder="t('view.search.avatar.sort_name')" /> <SelectValue :placeholder="t('view.search.avatar.sort_name')" />
@@ -292,7 +292,7 @@
</div> </div>
</div> </div>
</div> </div>
<ButtonGroup v-if="searchAvatarPage.length" style="margin-top: 15px"> <ButtonGroup v-if="searchAvatarPage.length" style="margin-top: 16px">
<Button <Button
variant="outline" variant="outline"
size="sm" size="sm"
@@ -332,10 +332,10 @@
<div class="flex-1 overflow-hidden"> <div class="flex-1 overflow-hidden">
<span class="block truncate font-medium leading-[18px]"> <span class="block truncate font-medium leading-[18px]">
<span v-text="group.name"></span> <span v-text="group.name"></span>
<span style="margin-left: 5px; font-weight: normal">({{ group.memberCount }})</span> <span style="margin-left: 6px; font-weight: normal">({{ group.memberCount }})</span>
<span <span
style=" style="
margin-left: 5px; margin-left: 6px;
color: #909399; color: #909399;
font-weight: normal; font-weight: normal;
font-family: monospace; font-family: monospace;
@@ -348,7 +348,7 @@
</div> </div>
</div> </div>
</div> </div>
<ButtonGroup v-if="searchGroupResults.length" style="margin-top: 15px"> <ButtonGroup v-if="searchGroupResults.length" style="margin-top: 16px">
<Button <Button
variant="outline" variant="outline"
size="sm" size="sm"
+1 -1
View File
@@ -1,6 +1,6 @@
<template> <template>
<div class="x-container"> <div class="x-container">
<div class="options-container" style="margin-top: 0; padding: 5px"> <div class="options-container mt-0 p-1.5">
<span class="header">{{ t('view.settings.header') }}</span> <span class="header">{{ t('view.settings.header') }}</span>
</div> </div>
<TabsUnderline <TabsUnderline
@@ -25,6 +25,10 @@
const emit = defineEmits(['change']); const emit = defineEmits(['change']);
/**
*
* @param event
*/
function change(event) { function change(event) {
emit('change', event); emit('change', event);
} }
@@ -45,7 +49,7 @@
align-items: center; align-items: center;
} }
.simple-switch > .switch { .simple-switch > .switch {
margin-left: 10px; margin-left: 8px;
} }
.simple-switch .tooltip { .simple-switch .tooltip {
margin-left: 3px; margin-left: 3px;
@@ -76,7 +76,7 @@
</div> </div>
<div class="options-container"> <div class="options-container">
<span class="header">{{ t('view.profile.game_info.header') }}</span> <span class="header">{{ t('view.profile.game_info.header') }}</span>
<div class="px-2.5 overflow-y-auto overflow-x-hidden" style="margin-top: 10px"> <div class="px-2.5 overflow-y-auto overflow-x-hidden mt-2">
<div class="box-border flex items-center p-1.5 text-[13px] cursor-pointer"> <div class="box-border flex items-center p-1.5 text-[13px] cursor-pointer">
<div class="flex-1 overflow-hidden" @click="getVisits"> <div class="flex-1 overflow-hidden" @click="getVisits">
<span class="block truncate font-medium leading-[18px]">{{ <span class="block truncate font-medium leading-[18px]">{{
@@ -107,7 +107,7 @@
<div class="options-container"> <div class="options-container">
<span class="header">{{ t('view.settings.advanced.advanced.app_launcher.header') }}</span> <span class="header">{{ t('view.settings.advanced.advanced.app_launcher.header') }}</span>
<br /> <br />
<Button size="sm" variant="outline" style="margin-top: 5px" @click="openShortcutFolder()">{{ <Button class="mt-1.5" size="sm" variant="outline" @click="openShortcutFolder()">{{
t('view.settings.advanced.advanced.app_launcher.folder') t('view.settings.advanced.advanced.app_launcher.folder')
}}</Button> }}</Button>
<simple-switch <simple-switch
@@ -152,7 +152,7 @@
@change="changeTranslationAPI('VRCX_translationAPI')" /> @change="changeTranslationAPI('VRCX_translationAPI')" />
<div class="options-container-item"> <div class="options-container-item">
<Button size="sm" variant="outline" @click="showTranslationApiDialog"> <Button size="sm" variant="outline" @click="showTranslationApiDialog">
<Languages class="h-4 w-4" style="margin-right: 5px" /> <Languages class="h-4 w-4" style="margin-right: 6px" />
{{ t('view.settings.advanced.advanced.translation_api.translation_api_key') }} {{ t('view.settings.advanced.advanced.translation_api.translation_api_key') }}
</Button> </Button>
</div> </div>
@@ -505,18 +505,30 @@
const isLinux = computed(() => LINUX); const isLinux = computed(() => LINUX);
/**
*
*/
function openShortcutFolder() { function openShortcutFolder() {
AppApi.OpenShortcutFolder(); AppApi.OpenShortcutFolder();
} }
/**
*
*/
function showYouTubeApiDialog() { function showYouTubeApiDialog() {
isYouTubeApiDialogVisible.value = true; isYouTubeApiDialogVisible.value = true;
} }
/**
*
*/
function showTranslationApiDialog() { function showTranslationApiDialog() {
isTranslationApiDialogVisible.value = true; isTranslationApiDialogVisible.value = true;
} }
/**
*
*/
function refreshCacheSize() { function refreshCacheSize() {
cacheSize.cachedUsers = cachedUsers.size; cacheSize.cachedUsers = cachedUsers.size;
cacheSize.cachedWorlds = cachedWorlds.size; cacheSize.cachedWorlds = cachedWorlds.size;
@@ -526,6 +538,10 @@
cacheSize.cachedInstances = cachedInstances.size; cacheSize.cachedInstances = cachedInstances.size;
} }
/**
*
* @param configKey
*/
async function changeYouTubeApi(configKey = '') { async function changeYouTubeApi(configKey = '') {
if (configKey === 'VRCX_youtubeAPI') { if (configKey === 'VRCX_youtubeAPI') {
advancedSettingsStore.setYouTubeApi(); advancedSettingsStore.setYouTubeApi();
@@ -538,17 +554,27 @@
updateOpenVR(); updateOpenVR();
} }
/**
*
* @param configKey
*/
async function changeTranslationAPI(configKey = '') { async function changeTranslationAPI(configKey = '') {
if (configKey === 'VRCX_translationAPI') { if (configKey === 'VRCX_translationAPI') {
advancedSettingsStore.setTranslationApi(); advancedSettingsStore.setTranslationApi();
} }
} }
/**
*
*/
async function refreshConfigTreeData() { async function refreshConfigTreeData() {
await authRequest.getConfig(); await authRequest.getConfig();
configTreeData.value = cachedConfig.value; configTreeData.value = cachedConfig.value;
} }
/**
*
*/
function getVisits() { function getVisits() {
miscRequest.getVisits().then((args) => { miscRequest.getVisits().then((args) => {
visits.value = args.json; visits.value = args.json;
@@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<div class="options-container" style="margin-top: 0"> <div class="options-container mt-0">
<span class="header">{{ t('view.settings.appearance.appearance.header') }}</span> <span class="header">{{ t('view.settings.appearance.appearance.header') }}</span>
<div class="options-container-item"> <div class="options-container-item">
<span class="name">{{ t('view.settings.appearance.appearance.language') }}</span> <span class="name">{{ t('view.settings.appearance.appearance.language') }}</span>
@@ -23,8 +23,8 @@
{{ t('view.settings.appearance.appearance.font_family') }} {{ t('view.settings.appearance.appearance.font_family') }}
<TooltipWrapper <TooltipWrapper
class="ml-1.5"
side="top" side="top"
style="margin-left: 5px"
:content="t('view.settings.appearance.appearance.font_family_tooltip')"> :content="t('view.settings.appearance.appearance.font_family_tooltip')">
<Info /> <Info />
</TooltipWrapper> </TooltipWrapper>
@@ -443,6 +443,10 @@
initGetZoomLevel(); initGetZoomLevel();
/**
*
* @param value
*/
function handleSortFavoritesRadio(value) { function handleSortFavoritesRadio(value) {
const nextValue = value === 'true'; const nextValue = value === 'true';
if (nextValue !== sortFavorites.value) { if (nextValue !== sortFavorites.value) {
@@ -450,6 +454,10 @@
} }
} }
/**
*
* @param value
*/
function handleInstanceUsersSortAlphabeticalRadio(value) { function handleInstanceUsersSortAlphabeticalRadio(value) {
const nextValue = value === 'true'; const nextValue = value === 'true';
if (nextValue !== instanceUsersSortAlphabetical.value) { if (nextValue !== instanceUsersSortAlphabetical.value) {
@@ -457,6 +465,10 @@
} }
} }
/**
*
* @param value
*/
function handleDtHour12Radio(value) { function handleDtHour12Radio(value) {
const nextValue = value === 'true'; const nextValue = value === 'true';
if (nextValue !== dtHour12.value) { if (nextValue !== dtHour12.value) {
@@ -502,6 +514,9 @@
} }
}); });
/**
*
*/
function addTablePageSizeFromInput() { function addTablePageSizeFromInput() {
const raw = String(tablePageSizesSearchTerm.value ?? '').trim(); const raw = String(tablePageSizesSearchTerm.value ?? '').trim();
if (!raw) { if (!raw) {
@@ -515,6 +530,9 @@
tablePageSizesSearchTerm.value = ''; tablePageSizesSearchTerm.value = '';
} }
/**
*
*/
async function initGetZoomLevel() { async function initGetZoomLevel() {
const handleWheel = (event) => { const handleWheel = (event) => {
if (event.ctrlKey) { if (event.ctrlKey) {
@@ -528,10 +546,16 @@
getZoomLevel(); getZoomLevel();
} }
/**
*
*/
async function getZoomLevel() { async function getZoomLevel() {
zoomLevel.value = ((await AppApi.GetZoom()) + 10) * 10; zoomLevel.value = ((await AppApi.GetZoom()) + 10) * 10;
} }
/**
*
*/
function setZoomLevel() { function setZoomLevel() {
AppApi.SetZoom(zoomLevel.value / 10 - 10); AppApi.SetZoom(zoomLevel.value / 10 - 10);
} }
@@ -1,5 +1,5 @@
<template> <template>
<div class="options-container" style="margin-top: 0"> <div class="options-container mt-0">
<span class="header">{{ t('view.settings.discord_presence.discord_presence.header') }}</span> <span class="header">{{ t('view.settings.discord_presence.discord_presence.header') }}</span>
<div class="options-container-item"> <div class="options-container-item">
<span>{{ t('view.settings.discord_presence.discord_presence.description') }}</span> <span>{{ t('view.settings.discord_presence.discord_presence.description') }}</span>
@@ -1,8 +1,8 @@
<template> <template>
<div> <div>
<div class="options-container" style="margin-top: 0"> <div class="options-container mt-0">
<span class="header">{{ t('view.settings.general.general.header') }}</span> <span class="header">{{ t('view.settings.general.general.header') }}</span>
<div class="px-2.5 overflow-y-auto overflow-x-hidden" style="margin-top: 10px"> <div class="px-2.5 overflow-y-auto overflow-x-hidden mt-2">
<div class="box-border flex items-center p-1.5 text-[13px] cursor-default"> <div class="box-border flex items-center p-1.5 text-[13px] cursor-default">
<div class="flex-1 overflow-hidden"> <div class="flex-1 overflow-hidden">
<span class="block truncate font-medium leading-[18px]">{{ <span class="block truncate font-medium leading-[18px]">{{
@@ -57,12 +57,12 @@
<div v-if="!noUpdater" class="text-sm mt-2 flex flex-col align-baseline"> <div v-if="!noUpdater" class="text-sm mt-2 flex flex-col align-baseline">
<span class="name">{{ t('view.settings.general.vrcx_updater.update_action') }}</span> <span class="name">{{ t('view.settings.general.vrcx_updater.update_action') }}</span>
<ToggleGroup <ToggleGroup
class="mt-1.5"
type="single" type="single"
required required
variant="outline" variant="outline"
size="sm" size="sm"
:model-value="autoUpdateVRCX" :model-value="autoUpdateVRCX"
style="margin-top: 5px"
@update:model-value="setAutoUpdateVRCX"> @update:model-value="setAutoUpdateVRCX">
<ToggleGroupItem value="Off">{{ <ToggleGroupItem value="Off">{{
t('view.settings.general.vrcx_updater.auto_update_off') t('view.settings.general.vrcx_updater.auto_update_off')
@@ -124,7 +124,7 @@
<span class="header inline-flex items-center" <span class="header inline-flex items-center"
>{{ t('view.settings.general.favorites.header') }} >{{ t('view.settings.general.favorites.header') }}
<TooltipWrapper side="top" :content="t('view.settings.general.favorites.header_tooltip')"> <TooltipWrapper side="top" :content="t('view.settings.general.favorites.header_tooltip')">
<Info style="width: 12px; height: 12px; margin-left: 4px; vertical-align: middle; cursor: help" /> <Info class="ml-1" style="width: 12px; height: 12px; vertical-align: middle; cursor: help" />
</TooltipWrapper> </TooltipWrapper>
</span> </span>
<br /> <br />
@@ -132,7 +132,7 @@
:model-value="localFavoriteFriendsGroups" :model-value="localFavoriteFriendsGroups"
multiple multiple
@update:modelValue="setLocalFavoriteFriendsGroups"> @update:modelValue="setLocalFavoriteFriendsGroups">
<SelectTrigger style="margin-top: 8px"> <SelectTrigger class="mt-2">
<SelectValue :placeholder="t('view.settings.general.favorites.group_placeholder')" /> <SelectValue :placeholder="t('view.settings.general.favorites.group_placeholder')" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -253,6 +253,9 @@
() => import('../../dialogs/OpenSourceSoftwareNoticeDialog.vue') () => import('../../dialogs/OpenSourceSoftwareNoticeDialog.vue')
); );
/**
*
*/
function openOSSDialog() { function openOSSDialog() {
ossDialog.value = true; ossDialog.value = true;
} }
@@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<div class="options-container" style="margin-top: 0"> <div class="options-container mt-0">
<span class="header">{{ t('view.settings.notifications.notifications.header') }}</span> <span class="header">{{ t('view.settings.notifications.notifications.header') }}</span>
<div class="options-container-item"> <div class="options-container-item">
<Button size="sm" variant="outline" @click="showNotyFeedFiltersDialog">{{ <Button size="sm" variant="outline" @click="showNotyFeedFiltersDialog">{{
@@ -23,6 +23,7 @@
}}</span> }}</span>
<br /> <br />
<ToggleGroup <ToggleGroup
class="mt-1.5"
type="single" type="single"
required required
variant="outline" variant="outline"
@@ -34,7 +35,6 @@
!ovrtHudNotifications && !ovrtHudNotifications &&
!ovrtWristNotifications !ovrtWristNotifications
" "
style="margin-top: 5px"
@update:model-value=" @update:model-value="
setOverlayToast($event); setOverlayToast($event);
saveOpenVROption(); saveOpenVROption();
@@ -82,7 +82,7 @@
</div> </div>
</template> </template>
<div class="options-container-item"> <div class="options-container-item">
<span class="name" style="vertical-align: top; padding-top: 10px">{{ <span class="name" style="vertical-align: top; padding-top: 8px">{{
t('view.settings.notifications.notifications.steamvr_notifications.notification_opacity') t('view.settings.notifications.notifications.steamvr_notifications.notification_opacity')
}}</span> }}</span>
<div style="flex: 0 0 300px; width: 300px; max-width: 100%; padding-top: 16px"> <div style="flex: 0 0 300px; width: 300px; max-width: 100%; padding-top: 16px">
@@ -120,9 +120,7 @@
</template> </template>
<template v-else> <template v-else>
<simple-switch <simple-switch
:label=" :label="t('view.settings.notifications.notifications.steamvr_notifications.wayvr_notifications')"
t('view.settings.notifications.notifications.steamvr_notifications.wayvr_notifications')
"
:value="xsNotifications" :value="xsNotifications"
@change=" @change="
setXsNotifications(); setXsNotifications();
@@ -169,7 +167,7 @@
variant="outline" variant="outline"
size="sm" size="sm"
:model-value="desktopToast" :model-value="desktopToast"
style="margin-top: 5px" style="margin-top: 6px"
@update:model-value="setDesktopToast(String($event))"> @update:model-value="setDesktopToast(String($event))">
<ToggleGroupItem value="Never">{{ <ToggleGroupItem value="Never">{{
t('view.settings.notifications.notifications.conditions.never') t('view.settings.notifications.notifications.conditions.never')
@@ -214,7 +212,7 @@
variant="outline" variant="outline"
size="sm" size="sm"
:model-value="notificationTTS" :model-value="notificationTTS"
style="margin-top: 5px" style="margin-top: 6px"
@update:model-value="saveNotificationTTS"> @update:model-value="saveNotificationTTS">
<ToggleGroupItem value="Never">{{ <ToggleGroupItem value="Never">{{
t('view.settings.notifications.notifications.conditions.never') t('view.settings.notifications.notifications.conditions.never')
@@ -260,7 +258,7 @@
:label="t('view.settings.notifications.notifications.text_to_speech.tts_test_placeholder')" :label="t('view.settings.notifications.notifications.text_to_speech.tts_test_placeholder')"
:value="isTestTTSVisible" :value="isTestTTSVisible"
@change="isTestTTSVisible = !isTestTTSVisible" /> @change="isTestTTSVisible = !isTestTTSVisible" />
<div v-if="isTestTTSVisible" style="margin-top: 5px"> <div v-if="isTestTTSVisible" style="margin-top: 6px">
<InputGroupTextareaField <InputGroupTextareaField
v-model="notificationTTSTest" v-model="notificationTTSTest"
:placeholder="t('view.settings.notifications.notifications.text_to_speech.tts_test_placeholder')" :placeholder="t('view.settings.notifications.notifications.text_to_speech.tts_test_placeholder')"
@@ -372,10 +370,16 @@
} }
}); });
/**
*
*/
function showNotyFeedFiltersDialog() { function showNotyFeedFiltersDialog() {
feedFiltersDialogMode.value = 'noty'; feedFiltersDialogMode.value = 'noty';
} }
/**
*
*/
function showNotificationPositionDialog() { function showNotificationPositionDialog() {
isNotificationPositionDialogVisible.value = true; isNotificationPositionDialogVisible.value = true;
} }
@@ -1,6 +1,6 @@
<template> <template>
<!--//- Pictures | Screenshot Helper--> <!--//- Pictures | Screenshot Helper-->
<div class="options-container" style="margin-top: 0"> <div class="options-container mt-0">
<span class="header">{{ t('view.settings.advanced.advanced.screenshot_helper.header') }}</span> <span class="header">{{ t('view.settings.advanced.advanced.screenshot_helper.header') }}</span>
<div class="options-container-item"> <div class="options-container-item">
<span class="name">{{ t('view.settings.advanced.advanced.screenshot_helper.description') }}</span> <span class="name">{{ t('view.settings.advanced.advanced.screenshot_helper.description') }}</span>
@@ -41,7 +41,7 @@
<div class="options-container"> <div class="options-container">
<span class="header">{{ t('view.settings.advanced.advanced.user_generated_content.header') }}</span> <span class="header">{{ t('view.settings.advanced.advanced.user_generated_content.header') }}</span>
<br /> <br />
<div class="options-container-item" style="margin-bottom: 5px"> <div class="options-container-item mb-1.5">
<span class="name" style="min-width: 300px">{{ <span class="name" style="min-width: 300px">{{
t('view.settings.advanced.advanced.user_generated_content.description') t('view.settings.advanced.advanced.user_generated_content.description')
}}</span> }}</span>
@@ -61,7 +61,7 @@
<br /> <br />
<br /> <br />
<br /> <br />
<span class="sub-header" style="margin-right: 5px">{{ <span class="sub-header mr-1.5">{{
t('view.settings.advanced.advanced.save_instance_prints_to_file.header') t('view.settings.advanced.advanced.save_instance_prints_to_file.header')
}}</span> }}</span>
<TooltipWrapper <TooltipWrapper
@@ -87,7 +87,7 @@
@change="setSaveInstanceStickers()" @change="setSaveInstanceStickers()"
:long-label="true" /> :long-label="true" />
<br /> <br />
<span class="sub-header" style="margin-right: 5px" <span class="sub-header mr-1.5"
>{{ t('view.settings.advanced.advanced.save_instance_emoji_to_file.header') }} >{{ t('view.settings.advanced.advanced.save_instance_emoji_to_file.header') }}
</span> </span>
<TooltipWrapper <TooltipWrapper
@@ -1,5 +1,5 @@
<template> <template>
<div class="options-container" style="margin-top: 0"> <div class="options-container mt-0">
<span class="header">{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.header') }}</span> <span class="header">{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.header') }}</span>
<div class="options-container-item"> <div class="options-container-item">
<Button <Button
@@ -46,8 +46,7 @@
<RadioGroup <RadioGroup
:model-value="openVRAlways ? 'true' : 'false'" :model-value="openVRAlways ? 'true' : 'false'"
:disabled="!openVR" :disabled="!openVR"
class="gap-2 flex" class="gap-2 flex mt-2"
style="margin-top: 8px"
@update:modelValue="handleOpenVRAlwaysRadio"> @update:modelValue="handleOpenVRAlwaysRadio">
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<RadioGroupItem id="openVRAlways-false" value="false" /> <RadioGroupItem id="openVRAlways-false" value="false" />
@@ -64,8 +63,7 @@
<RadioGroup <RadioGroup
:model-value="overlaybutton ? 'true' : 'false'" :model-value="overlaybutton ? 'true' : 'false'"
:disabled="!openVR || !overlayWrist" :disabled="!openVR || !overlayWrist"
class="gap-2 flex" class="gap-2 flex mt-2"
style="margin-top: 8px"
@update:modelValue="handleOverlayButtonRadio"> @update:modelValue="handleOverlayButtonRadio">
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<RadioGroupItem id="overlaybutton-false" value="false" /> <RadioGroupItem id="overlaybutton-false" value="false" />
@@ -206,6 +204,10 @@
const { saveOpenVROption } = useVrStore(); const { saveOpenVROption } = useVrStore();
/**
*
* @param value
*/
function handleOpenVRAlwaysRadio(value) { function handleOpenVRAlwaysRadio(value) {
const nextValue = value === 'true'; const nextValue = value === 'true';
if (nextValue !== openVRAlways.value) { if (nextValue !== openVRAlways.value) {
@@ -214,6 +216,10 @@
} }
} }
/**
*
* @param value
*/
function handleOverlayButtonRadio(value) { function handleOverlayButtonRadio(value) {
const nextValue = value === 'true'; const nextValue = value === 'true';
if (nextValue !== overlaybutton.value) { if (nextValue !== overlaybutton.value) {
@@ -6,18 +6,20 @@
</DialogHeader> </DialogHeader>
<div> <div>
<InputGroupAction <InputGroupAction
class="mt-1.5"
v-for="(provider, index) in avatarRemoteDatabaseProviderList" v-for="(provider, index) in avatarRemoteDatabaseProviderList"
:key="index" :key="index"
v-model="avatarRemoteDatabaseProviderList[index]" v-model="avatarRemoteDatabaseProviderList[index]"
size="sm" size="sm"
style="margin-top: 5px"
@change="saveAvatarProviderList"> @change="saveAvatarProviderList">
<template #actions> <template #actions>
<Trash2 class="cursor-pointer opacity-80 hover:opacity-100" @click="removeAvatarProvider(provider)" /> <Trash2
class="cursor-pointer opacity-80 hover:opacity-100"
@click="removeAvatarProvider(provider)" />
</template> </template>
</InputGroupAction> </InputGroupAction>
<Button size="sm" style="margin-top: 5px" @click="avatarRemoteDatabaseProviderList.push('')"> <Button size="sm" style="margin-top: 6px" @click="avatarRemoteDatabaseProviderList.push('')">
{{ t('dialog.avatar_database_provider.add_provider') }} {{ t('dialog.avatar_database_provider.add_provider') }}
</Button> </Button>
</div> </div>
@@ -51,6 +53,9 @@
const emit = defineEmits(['update:isAvatarProviderDialogVisible']); const emit = defineEmits(['update:isAvatarProviderDialogVisible']);
/**
*
*/
function closeDialog() { function closeDialog() {
emit('update:isAvatarProviderDialogVisible', false); emit('update:isAvatarProviderDialogVisible', false);
} }
@@ -20,12 +20,12 @@
>. >.
</span> </span>
<VueShowdown <VueShowdown
class="changelog-markdown" class="changelog-markdown mt-2"
:markdown="changeLogDialog.changeLog" :markdown="changeLogDialog.changeLog"
flavor="github" flavor="github"
:options="showdownOptions" :options="showdownOptions"
@click="handleLinkClick" @click="handleLinkClick"
style="height: 62vh; overflow-y: auto; margin-top: 10px" /> style="height: 62vh; overflow-y: auto" />
</div> </div>
<DialogFooter> <DialogFooter>
<Button <Button
@@ -8,11 +8,7 @@
<div v-for="setting in currentOptions" :key="setting.key" class="mb-[5px] flex items-center"> <div v-for="setting in currentOptions" :key="setting.key" class="mb-[5px] flex items-center">
<span class="inline-block min-w-[190px] pr-2.5 text-right" <span class="inline-block min-w-[190px] pr-2.5 text-right"
>{{ setting.name >{{ setting.name
}}<TooltipWrapper }}<TooltipWrapper class="ml-1.5" v-if="setting.tooltip" side="top" :content="setting.tooltip">
v-if="setting.tooltip"
side="top"
style="margin-left: 5px"
:content="setting.tooltip">
<AlertTriangle class="inline-block" v-if="setting.tooltipWarning" /> <AlertTriangle class="inline-block" v-if="setting.tooltipWarning" />
<Info class="inline-block" v-else /> <Info class="inline-block" v-else />
</TooltipWrapper> </TooltipWrapper>
@@ -15,9 +15,8 @@
x="0px" x="0px"
y="0px" y="0px"
viewBox="80 80 80 100" viewBox="80 80 80 100"
style="margin-top: 24px"
xml:space="preserve" xml:space="preserve"
class="absolute inset-0 size-full"> class="absolute inset-0 size-full mt-6">
<path <path
style="fill: black" style="fill: black"
d="M291.89,5A3.11,3.11,0,0,1,295,8.11V160.64a3.11,3.11,0,0,1-3.11,3.11H8.11A3.11,3.11,0,0,1,5,160.64V8.11A3.11,3.11,0,0,1,8.11,5H291.89m0-5H8.11A8.11,8.11,0,0,0,0,8.11V160.64a8.11,8.11,0,0,0,8.11,8.11H291.89a8.11,8.11,0,0,0,8.11-8.11V8.11A8.11,8.11,0,0,0,291.89,0Z" /> d="M291.89,5A3.11,3.11,0,0,1,295,8.11V160.64a3.11,3.11,0,0,1-3.11,3.11H8.11A3.11,3.11,0,0,1,5,160.64V8.11A3.11,3.11,0,0,1,8.11,5H291.89m0-5H8.11A8.11,8.11,0,0,0,0,8.11V160.64a8.11,8.11,0,0,0,8.11,8.11H291.89a8.11,8.11,0,0,0,8.11-8.11V8.11A8.11,8.11,0,0,0,291.89,0Z" />
@@ -109,6 +108,9 @@
const emit = defineEmits(['update:isNotificationPositionDialogVisible']); const emit = defineEmits(['update:isNotificationPositionDialogVisible']);
/**
*
*/
function closeDialog() { function closeDialog() {
emit('update:isNotificationPositionDialogVisible', false); emit('update:isNotificationPositionDialogVisible', false);
} }
@@ -9,7 +9,7 @@
<span>{{ t('dialog.open_source.description') }}</span> <span>{{ t('dialog.open_source.description') }}</span>
</div> </div>
<div v-for="lib in openSourceSoftwareLicenses" :key="lib.name" style="margin-top: 15px"> <div class="mt-4" v-for="lib in openSourceSoftwareLicenses" :key="lib.name">
<p style="font-weight: bold">{{ lib.name }}</p> <p style="font-weight: bold">{{ lib.name }}</p>
<pre style="font-size: 12px; white-space: pre-line">{{ lib.licenseText }}</pre> <pre style="font-size: 12px; white-space: pre-line">{{ lib.licenseText }}</pre>
</div> </div>
@@ -35,6 +35,9 @@
const emit = defineEmits(['update:ossDialog']); const emit = defineEmits(['update:ossDialog']);
/**
*
*/
function closeDialog() { function closeDialog() {
emit('update:ossDialog', false); emit('update:ossDialog', false);
} }
@@ -12,10 +12,10 @@
:maxlength="32" :maxlength="32"
autofocus /> autofocus />
<InputGroupField <InputGroupField
class="mt-1.5"
v-model="enablePrimaryPasswordDialog.rePassword" v-model="enablePrimaryPasswordDialog.rePassword"
:placeholder="t('dialog.primary_password.re_input_placeholder')" :placeholder="t('dialog.primary_password.re_input_placeholder')"
type="password" type="password"
style="margin-top: 5px"
size="sm" size="sm"
:maxlength="32" /> :maxlength="32" />
<DialogFooter> <DialogFooter>
@@ -47,6 +47,9 @@
const { enablePrimaryPasswordDialog } = storeToRefs(authStore); const { enablePrimaryPasswordDialog } = storeToRefs(authStore);
const { setPrimaryPassword } = authStore; const { setPrimaryPassword } = authStore;
/**
*
*/
function handleSetPrimaryPassword() { function handleSetPrimaryPassword() {
setPrimaryPassword(enablePrimaryPasswordDialog.value.password); setPrimaryPassword(enablePrimaryPasswordDialog.value.password);
enablePrimaryPasswordDialog.value.visible = false; enablePrimaryPasswordDialog.value.visible = false;
@@ -10,46 +10,42 @@
{{ t('dialog.config_json.description2') }} {{ t('dialog.config_json.description2') }}
</div> </div>
<br /> <br />
<span style="margin-right: 5px">{{ t('dialog.config_json.cache_size') }}</span> <span class="mr-1.5">{{ t('dialog.config_json.cache_size') }}</span>
<span v-text="VRChatUsedCacheSize"></span> <span v-text="VRChatUsedCacheSize"></span>
<span>/</span> <span>/</span>
<span v-text="totalCacheSize"></span> <span v-text="totalCacheSize"></span>
<span>GB</span> <span>GB</span>
<TooltipWrapper side="top" :content="t('dialog.config_json.refresh')"> <TooltipWrapper side="top" :content="t('dialog.config_json.refresh')">
<Button <Button
class="rounded-full" class="rounded-full ml-1.5"
variant="outline" variant="outline"
size="icon-sm" size="icon-sm"
:disabled="VRChatCacheSizeLoading" :disabled="VRChatCacheSizeLoading"
style="margin-left: 5px"
@click="getVRChatCacheSize"> @click="getVRChatCacheSize">
<Spinner v-if="VRChatCacheSizeLoading" /> <Spinner v-if="VRChatCacheSizeLoading" />
<RefreshCw v-else /> <RefreshCw v-else />
</Button> </Button>
</TooltipWrapper> </TooltipWrapper>
<div style="margin-top: 10px"> <div class="mt-2">
<span style="margin-right: 5px">{{ t('dialog.config_json.delete_all_cache') }}</span> <span class="mr-1.5">{{ t('dialog.config_json.delete_all_cache') }}</span>
<Button <Button class="ml-1.5" size="sm" variant="outline" @click="showDeleteAllVRChatCacheConfirm">{{
size="sm" t('dialog.config_json.delete_cache')
variant="outline" }}</Button>
style="margin-left: 5px"
@click="showDeleteAllVRChatCacheConfirm"
>{{ t('dialog.config_json.delete_cache') }}</Button
>
</div> </div>
<div style="margin-top: 10px"> <div class="mt-2">
<span style="margin-right: 5px">{{ t('dialog.config_json.delete_old_cache') }}</span> <span class="mr-1.5">{{ t('dialog.config_json.delete_old_cache') }}</span>
<Button size="sm" variant="outline" style="margin-left: 5px" @click="sweepVRChatCache">{{ <Button class="ml-1.5" size="sm" variant="outline" @click="sweepVRChatCache">{{
t('dialog.config_json.sweep_cache') t('dialog.config_json.sweep_cache')
}}</Button> }}</Button>
</div> </div>
<div v-for="(item, value) in VRChatConfigList" :key="value" style="display: block; margin-top: 10px"> <div class="mt-2" v-for="(item, value) in VRChatConfigList" :key="value" style="display: block">
<span style="word-break: keep-all">{{ item.name }}:</span> <span style="word-break: keep-all">{{ item.name }}:</span>
<div style="display: flex"> <div style="display: flex">
<InputGroupAction <InputGroupAction
class="mt-1.5"
v-model="VRChatConfigFile[value]" v-model="VRChatConfigFile[value]"
:placeholder="item.default" :placeholder="item.default"
size="sm" size="sm"
@@ -57,7 +53,7 @@
:min="item.min" :min="item.min"
:max="item.max" :max="item.max"
@input="refreshDialogValues" @input="refreshDialogValues"
style="flex: 1; margin-top: 5px"> style="flex: 1">
<template #actions> <template #actions>
<Button <Button
size="icon-sm" size="icon-sm"
@@ -71,13 +67,13 @@
</div> </div>
</div> </div>
<div style="display: inline-block; margin-top: 10px"> <div style="display: inline-block; margin-top: 8px">
<span>{{ t('dialog.config_json.camera_resolution') }}</span> <span>{{ t('dialog.config_json.camera_resolution') }}</span>
<br /> <br />
<Select <Select
:model-value="vrchatCameraResolutionKey" :model-value="vrchatCameraResolutionKey"
@update:modelValue="(v) => (vrchatCameraResolutionKey = v)"> @update:modelValue="(v) => (vrchatCameraResolutionKey = v)">
<SelectTrigger size="sm" style="margin-top: 5px"> <SelectTrigger size="sm" style="margin-top: 6px">
<SelectValue :placeholder="getVRChatCameraResolution()" /> <SelectValue :placeholder="getVRChatCameraResolution()" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -94,13 +90,13 @@
</div> </div>
<br /> <br />
<div style="display: inline-block; margin-top: 10px"> <div style="display: inline-block; margin-top: 8px">
<span>{{ t('dialog.config_json.spout_resolution') }}</span> <span>{{ t('dialog.config_json.spout_resolution') }}</span>
<br /> <br />
<Select <Select
:model-value="vrchatSpoutResolutionKey" :model-value="vrchatSpoutResolutionKey"
@update:modelValue="(v) => (vrchatSpoutResolutionKey = v)"> @update:modelValue="(v) => (vrchatSpoutResolutionKey = v)">
<SelectTrigger size="sm" style="margin-top: 5px"> <SelectTrigger size="sm" style="margin-top: 6px">
<SelectValue :placeholder="getVRChatSpoutResolution()" /> <SelectValue :placeholder="getVRChatSpoutResolution()" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -117,13 +113,13 @@
</div> </div>
<br /> <br />
<div style="display: inline-block; margin-top: 10px"> <div style="display: inline-block; margin-top: 8px">
<span>{{ t('dialog.config_json.screenshot_resolution') }}</span> <span>{{ t('dialog.config_json.screenshot_resolution') }}</span>
<br /> <br />
<Select <Select
:model-value="vrchatScreenshotResolutionKey" :model-value="vrchatScreenshotResolutionKey"
@update:modelValue="(v) => (vrchatScreenshotResolutionKey = v)"> @update:modelValue="(v) => (vrchatScreenshotResolutionKey = v)">
<SelectTrigger size="sm" style="margin-top: 5px"> <SelectTrigger size="sm" style="margin-top: 6px">
<SelectValue :placeholder="getVRChatScreenshotResolution()" /> <SelectValue :placeholder="getVRChatScreenshotResolution()" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -140,13 +136,13 @@
</div> </div>
<br /> <br />
<label class="inline-flex items-center gap-2" style="margin-top: 5px; display: block"> <label class="inline-flex items-center gap-2" style="margin-top: 6px; display: block">
<Checkbox <Checkbox
v-model="VRChatConfigFile.picture_output_split_by_date" v-model="VRChatConfigFile.picture_output_split_by_date"
@update:modelValue="refreshDialogValues" /> @update:modelValue="refreshDialogValues" />
<span>{{ t('dialog.config_json.picture_sort_by_date') }}</span> <span>{{ t('dialog.config_json.picture_sort_by_date') }}</span>
</label> </label>
<label class="inline-flex items-center gap-2" style="margin-top: 5px; display: block"> <label class="inline-flex items-center gap-2" style="margin-top: 6px; display: block">
<Checkbox v-model="VRChatConfigFile.disableRichPresence" @update:modelValue="refreshDialogValues" /> <Checkbox v-model="VRChatConfigFile.disableRichPresence" @update:modelValue="refreshDialogValues" />
<span>{{ t('dialog.config_json.disable_discord_presence') }}</span> <span>{{ t('dialog.config_json.disable_discord_presence') }}</span>
</label> </label>
@@ -267,6 +263,10 @@
const VRCHAT_RESOLUTION_DEFAULT_KEY = '__default__'; const VRCHAT_RESOLUTION_DEFAULT_KEY = '__default__';
/**
*
* @param row
*/
function getVRChatResolutionKey(row) { function getVRChatResolutionKey(row) {
const width = Number(row?.width); const width = Number(row?.width);
const height = Number(row?.height); const height = Number(row?.height);
@@ -327,6 +327,9 @@
} }
}); });
/**
*
*/
function showDeleteAllVRChatCacheConfirm() { function showDeleteAllVRChatCacheConfirm() {
modalStore modalStore
.confirm({ .confirm({
@@ -341,6 +344,9 @@
.catch(() => {}); .catch(() => {});
} }
/**
*
*/
async function deleteAllVRChatCache() { async function deleteAllVRChatCache() {
try { try {
await AssetBundleManager.DeleteAllCache(); await AssetBundleManager.DeleteAllCache();
@@ -351,6 +357,10 @@
getVRChatCacheSize(); getVRChatCacheSize();
} }
/**
*
* @param value
*/
async function openConfigFolderBrowser(value) { async function openConfigFolderBrowser(value) {
const oldPath = VRChatConfigFile.value[value]; const oldPath = VRChatConfigFile.value[value];
const newPath = await folderSelectorDialog(oldPath); const newPath = await folderSelectorDialog(oldPath);
@@ -360,29 +370,47 @@
} }
} }
/**
*
*/
function refreshDialogValues() { function refreshDialogValues() {
loading.value = true; loading.value = true;
loading.value = false; loading.value = false;
} }
/**
*
* @param res
*/
function setVRChatSpoutResolution(res) { function setVRChatSpoutResolution(res) {
VRChatConfigFile.value.camera_spout_res_height = res.height; VRChatConfigFile.value.camera_spout_res_height = res.height;
VRChatConfigFile.value.camera_spout_res_width = res.width; VRChatConfigFile.value.camera_spout_res_width = res.width;
refreshDialogValues(); refreshDialogValues();
} }
/**
*
* @param res
*/
function setVRChatCameraResolution(res) { function setVRChatCameraResolution(res) {
VRChatConfigFile.value.camera_res_height = res.height; VRChatConfigFile.value.camera_res_height = res.height;
VRChatConfigFile.value.camera_res_width = res.width; VRChatConfigFile.value.camera_res_width = res.width;
refreshDialogValues(); refreshDialogValues();
} }
/**
*
* @param res
*/
function setVRChatScreenshotResolution(res) { function setVRChatScreenshotResolution(res) {
VRChatConfigFile.value.screenshot_res_height = res.height; VRChatConfigFile.value.screenshot_res_height = res.height;
VRChatConfigFile.value.screenshot_res_width = res.width; VRChatConfigFile.value.screenshot_res_width = res.width;
refreshDialogValues(); refreshDialogValues();
} }
/**
*
*/
function getVRChatCameraResolution() { function getVRChatCameraResolution() {
if (VRChatConfigFile.value.camera_res_height && VRChatConfigFile.value.camera_res_width) { if (VRChatConfigFile.value.camera_res_height && VRChatConfigFile.value.camera_res_width) {
const res = `${VRChatConfigFile.value.camera_res_width}x${VRChatConfigFile.value.camera_res_height}`; const res = `${VRChatConfigFile.value.camera_res_width}x${VRChatConfigFile.value.camera_res_height}`;
@@ -391,6 +419,9 @@
return '1920x1080 (1080p)'; return '1920x1080 (1080p)';
} }
/**
*
*/
function getVRChatSpoutResolution() { function getVRChatSpoutResolution() {
if (VRChatConfigFile.value.camera_spout_res_height && VRChatConfigFile.value.camera_spout_res_width) { if (VRChatConfigFile.value.camera_spout_res_height && VRChatConfigFile.value.camera_spout_res_width) {
const res = `${VRChatConfigFile.value.camera_spout_res_width}x${VRChatConfigFile.value.camera_spout_res_height}`; const res = `${VRChatConfigFile.value.camera_spout_res_width}x${VRChatConfigFile.value.camera_spout_res_height}`;
@@ -399,6 +430,9 @@
return '1920x1080 (1080p)'; return '1920x1080 (1080p)';
} }
/**
*
*/
function getVRChatScreenshotResolution() { function getVRChatScreenshotResolution() {
if (VRChatConfigFile.value.screenshot_res_height && VRChatConfigFile.value.screenshot_res_width) { if (VRChatConfigFile.value.screenshot_res_height && VRChatConfigFile.value.screenshot_res_width) {
const res = `${VRChatConfigFile.value.screenshot_res_width}x${VRChatConfigFile.value.screenshot_res_height}`; const res = `${VRChatConfigFile.value.screenshot_res_width}x${VRChatConfigFile.value.screenshot_res_height}`;
@@ -407,6 +441,9 @@
return '1920x1080 (1080p)'; return '1920x1080 (1080p)';
} }
/**
*
*/
function saveVRChatConfigFile() { function saveVRChatConfigFile() {
for (const item in VRChatConfigFile.value) { for (const item in VRChatConfigFile.value) {
if (item === 'picture_output_split_by_date') { if (item === 'picture_output_split_by_date') {
@@ -429,11 +466,17 @@
closeDialog(); closeDialog();
} }
/**
*
*/
function WriteVRChatConfigFile() { function WriteVRChatConfigFile() {
const json = JSON.stringify(VRChatConfigFile.value, null, '\t'); const json = JSON.stringify(VRChatConfigFile.value, null, '\t');
AppApi.WriteConfigFile(json); AppApi.WriteConfigFile(json);
} }
/**
*
*/
async function readVRChatConfigFile() { async function readVRChatConfigFile() {
const config = await AppApi.ReadConfigFileSafe(); const config = await AppApi.ReadConfigFileSafe();
if (config) { if (config) {
@@ -450,6 +493,9 @@
} }
} }
/**
*
*/
function closeDialog() { function closeDialog() {
isVRChatConfigDialogVisible.value = false; isVRChatConfigDialogVisible.value = false;
} }
+5 -5
View File
@@ -1,7 +1,7 @@
<template> <template>
<div class="x-aside-container"> <div class="x-aside-container">
<div style="display: flex; align-items: baseline"> <div style="display: flex; align-items: baseline">
<div class="search-container" style="flex: 1; padding: 10px; padding-left: 0"> <div class="search-container p-2 pl-0" style="flex: 1">
<button <button
type="button" type="button"
class="border-input dark:bg-input/30 flex h-9 w-full items-center gap-2 rounded-md border bg-transparent px-3 shadow-xs transition-[color,box-shadow] hover:border-ring cursor-pointer overflow-hidden" class="border-input dark:bg-input/30 flex h-9 w-full items-center gap-2 rounded-md border bg-transparent px-3 shadow-xs transition-[color,box-shadow] hover:border-ring cursor-pointer overflow-hidden"
@@ -209,7 +209,7 @@
variant="equal" variant="equal"
fill fill
class="zero-margin-tabs" class="zero-margin-tabs"
style="height: calc(100% - 70px); margin-top: 5px"> style="height: calc(100% - 70px); margin-top: 6px">
<template #label-friends> <template #label-friends>
<span>{{ t('side_panel.friends') }}</span> <span>{{ t('side_panel.friends') }}</span>
<span class="sidebar-tab-count"> ({{ onlineFriendCount }}/{{ friends.size }}) </span> <span class="sidebar-tab-count"> ({{ onlineFriendCount }}/{{ friends.size }}) </span>
@@ -380,16 +380,16 @@
display: flex; display: flex;
flex: none; flex: none;
flex-direction: column; flex-direction: column;
padding: 10px 5px 5px 5px; padding: 8px 6px 6px 6px;
order: 99; order: 99;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
padding-left: 10px; padding-left: 8px;
} }
.sidebar-tab-count { .sidebar-tab-count {
font-size: 12px; font-size: 12px;
margin-left: 10px; margin-left: 8px;
} }
.search-container { .search-container {
@@ -482,7 +482,7 @@
buildFriendRow(friend, `instance:${groupKey}:${friend?.id ?? idx}`, { buildFriendRow(friend, `instance:${groupKey}:${friend?.id ?? idx}`, {
isGroupByInstance: true, isGroupByInstance: true,
paddingBottom: idx === friendArr.length - 1 ? 5 : undefined, paddingBottom: idx === friendArr.length - 1 ? 5 : undefined,
itemStyle: idx === friendArr.length - 1 ? { marginBottom: '5px' } : undefined itemStyle: idx === friendArr.length - 1 ? { marginBottom: '6px' } : undefined
}) })
); );
}); });
+17 -17
View File
@@ -97,7 +97,7 @@
:src="image.versions[image.versions.length - 1].file.url" :src="image.versions[image.versions.length - 1].file.url"
loading="lazy" /> loading="lazy" />
</div> </div>
<div class="float-right" style="margin-top: 5px"> <div class="float-right" style="margin-top: 6px">
<Button <Button
class="rounded-full mr-2" class="rounded-full mr-2"
size="icon-sm" size="icon-sm"
@@ -169,7 +169,7 @@
:src="image.versions[image.versions.length - 1].file.url" :src="image.versions[image.versions.length - 1].file.url"
loading="lazy" /> loading="lazy" />
</div> </div>
<div class="float-right" style="margin-top: 5px"> <div class="float-right" style="margin-top: 6px">
<Button <Button
class="rounded-full mr-2" class="rounded-full mr-2"
size="icon-sm" size="icon-sm"
@@ -203,7 +203,7 @@
<br /> <br />
<br /> <br />
<div> <div>
<ButtonGroup style="margin-right: 10px"> <ButtonGroup style="margin-right: 8px">
<Button variant="outline" size="sm" @click="refreshEmojiTable"> <Button variant="outline" size="sm" @click="refreshEmojiTable">
<RefreshCw /> <RefreshCw />
{{ t('dialog.gallery_icons.refresh') }} {{ t('dialog.gallery_icons.refresh') }}
@@ -251,7 +251,7 @@
@click="openExternalLink('https://vrcemoji.com')"> @click="openExternalLink('https://vrcemoji.com')">
{{ t('dialog.gallery_icons.create_animated_emoji') }} {{ t('dialog.gallery_icons.create_animated_emoji') }}
</Button> </Button>
<span style="margin-right: 10px">{{ t('dialog.gallery_icons.emoji_animation_fps') }}</span> <span style="margin-right: 8px">{{ t('dialog.gallery_icons.emoji_animation_fps') }}</span>
<NumberField <NumberField
v-model="emojiAnimFps" v-model="emojiAnimFps"
:min="1" :min="1"
@@ -265,7 +265,7 @@
<NumberFieldIncrement /> <NumberFieldIncrement />
</NumberFieldContent> </NumberFieldContent>
</NumberField> </NumberField>
<span style="margin-right: 10px">{{ <span style="margin-right: 8px">{{
t('dialog.gallery_icons.emoji_animation_frame_count') t('dialog.gallery_icons.emoji_animation_frame_count')
}}</span> }}</span>
<NumberField <NumberField
@@ -281,7 +281,7 @@
<NumberFieldIncrement /> <NumberFieldIncrement />
</NumberFieldContent> </NumberFieldContent>
</NumberField> </NumberField>
<label class="inline-flex items-center gap-2" style="margin-left: 10px; margin-right: 10px"> <label class="inline-flex items-center gap-2" style="margin-left: 8px; margin-right: 8px">
<Checkbox v-model="emojiAnimLoopPingPong" /> <Checkbox v-model="emojiAnimLoopPingPong" />
<span>{{ t('dialog.gallery_icons.emoji_loop_pingpong') }}</span> <span>{{ t('dialog.gallery_icons.emoji_loop_pingpong') }}</span>
</label> </label>
@@ -306,18 +306,18 @@
:imageUrl="image.versions[image.versions.length - 1].file.url" :imageUrl="image.versions[image.versions.length - 1].file.url"
:size="200"></Emoji> :size="200"></Emoji>
</div> </div>
<div style="display: inline-block; margin: 5px"> <div style="display: inline-block; margin: 6px">
<span v-if="image.loopStyle === 'pingpong'"> <span v-if="image.loopStyle === 'pingpong'">
<RefreshCw style="margin-right: 5px" /> <RefreshCw style="margin-right: 6px" />
</span> </span>
<span style="margin-right: 5px">{{ image.animationStyle }}</span> <span style="margin-right: 6px">{{ image.animationStyle }}</span>
<span v-if="image.framesOverTime" style="margin-right: 5px" <span v-if="image.framesOverTime" style="margin-right: 6px"
>{{ image.framesOverTime }}fps</span >{{ image.framesOverTime }}fps</span
> >
<span v-if="image.frames" style="margin-right: 5px">{{ image.frames }}frames</span> <span v-if="image.frames" style="margin-right: 6px">{{ image.frames }}frames</span>
<br /> <br />
</div> </div>
<div class="float-right" style="margin-top: 5px"> <div class="float-right" style="margin-top: 6px">
<Button <Button
class="rounded-full mr-2" class="rounded-full mr-2"
size="icon-sm" size="icon-sm"
@@ -382,7 +382,7 @@
:src="image.versions[image.versions.length - 1].file.url" :src="image.versions[image.versions.length - 1].file.url"
loading="lazy" /> loading="lazy" />
</div> </div>
<div class="float-right" style="margin-top: 5px"> <div class="float-right" style="margin-top: 6px">
<Button <Button
class="rounded-full mr-2" class="rounded-full mr-2"
size="icon-sm" size="icon-sm"
@@ -434,10 +434,10 @@
v-model="printUploadNote" v-model="printUploadNote"
:rows="1" :rows="1"
:maxlength="32" :maxlength="32"
style="margin-left: 10px; width: 300px" style="margin-left: 8px; width: 300px"
:placeholder="t('dialog.gallery_icons.note')" :placeholder="t('dialog.gallery_icons.note')"
input-class="resize-none min-h-0" /> input-class="resize-none min-h-0" />
<label class="inline-flex items-center gap-2" style="margin-left: 10px; margin-right: 10px"> <label class="inline-flex items-center gap-2" style="margin-left: 8px; margin-right: 8px">
<Checkbox v-model="printCropBorder" /> <Checkbox v-model="printCropBorder" />
<span>{{ t('dialog.gallery_icons.crop_print_border') }}</span> <span>{{ t('dialog.gallery_icons.crop_print_border') }}</span>
</label> </label>
@@ -452,7 +452,7 @@
:src="image.files.image" :src="image.files.image"
loading="lazy" /> loading="lazy" />
</div> </div>
<div style="margin-top: 5px; width: 208px"> <div style="margin-top: 6px; width: 208px">
<span class="block truncate" v-if="image.note" v-text="image.note"></span> <span class="block truncate" v-if="image.note" v-text="image.note"></span>
<span v-else class="block">&nbsp;</span> <span v-else class="block">&nbsp;</span>
<Location <Location
@@ -519,7 +519,7 @@
:src="item.imageUrl" :src="item.imageUrl"
loading="lazy" /> loading="lazy" />
</div> </div>
<div style="margin-top: 5px; width: 208px"> <div style="margin-top: 6px; width: 208px">
<span class="block truncate" v-text="item.name"></span> <span class="block truncate" v-text="item.name"></span>
<span v-if="item.description" class="block truncate" v-text="item.description"></span> <span v-if="item.description" class="block truncate" v-text="item.description"></span>
<span v-else class="block">&nbsp;</span> <span v-else class="block">&nbsp;</span>
+66 -5
View File
@@ -56,7 +56,7 @@
style="width: 200px" style="width: 200px"
@input="screenshotMetadataSearch" /> @input="screenshotMetadataSearch" />
<Select :model-value="screenshotMetadataDialog.searchType" @update:modelValue="handleSearchTypeChange"> <Select :model-value="screenshotMetadataDialog.searchType" @update:modelValue="handleSearchTypeChange">
<SelectTrigger size="sm" style="width: 150px; margin-left: 10px"> <SelectTrigger class="ml-2" size="sm" style="width: 150px">
<SelectValue :placeholder="t('dialog.screenshot_metadata.search_type_placeholder')" /> <SelectValue :placeholder="t('dialog.screenshot_metadata.search_type_placeholder')" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -69,7 +69,7 @@
</Select> </Select>
</div> </div>
<template v-if="screenshotMetadataDialog.searchIndex !== null"> <template v-if="screenshotMetadataDialog.searchIndex !== null">
<span style="white-space: pre-wrap; font-size: 12px; margin-left: 10px">{{ <span class="ml-2" style="white-space: pre-wrap; font-size: 12px">{{
screenshotMetadataDialog.searchIndex + 1 + '/' + screenshotMetadataDialog.searchResults.length screenshotMetadataDialog.searchIndex + 1 + '/' + screenshotMetadataDialog.searchResults.length
}}</span> }}</span>
</template> </template>
@@ -81,12 +81,12 @@
<span v-text="screenshotMetadataDialog.metadata.note"></span> <span v-text="screenshotMetadataDialog.metadata.note"></span>
<br /> <br />
</template> </template>
<span v-if="screenshotMetadataDialog.metadata.dateTime" style="margin-right: 5px">{{ <span v-if="screenshotMetadataDialog.metadata.dateTime" style="margin-right: 6px">{{
formatDateFilter(screenshotMetadataDialog.metadata.dateTime, 'long') formatDateFilter(screenshotMetadataDialog.metadata.dateTime, 'long')
}}</span> }}</span>
<span <span
v-if="screenshotMetadataDialog.metadata.fileResolution" v-if="screenshotMetadataDialog.metadata.fileResolution"
style="margin-right: 5px" style="margin-right: 6px"
v-text="screenshotMetadataDialog.metadata.fileResolution"></span> v-text="screenshotMetadataDialog.metadata.fileResolution"></span>
<Badge v-if="screenshotMetadataDialog.metadata.fileSize" variant="outline">{{ <Badge v-if="screenshotMetadataDialog.metadata.fileSize" variant="outline">{{
screenshotMetadataDialog.metadata.fileSize screenshotMetadataDialog.metadata.fileSize
@@ -138,7 +138,7 @@
v-text="screenshotMetadataDialog.metadata.error"></pre> v-text="screenshotMetadataDialog.metadata.error"></pre>
<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: 6px">
<span class="cursor-pointer" @click="lookupUser(user)" v-text="user.displayName"></span> <span class="cursor-pointer" @click="lookupUser(user)" v-text="user.displayName"></span>
<span v-if="user.pos" v-text="'(' + user.pos.x + ', ' + user.pos.y + ', ' + user.pos.z + ')'"></span> <span v-if="user.pos" v-text="'(' + user.pos.x + ', ' + user.pos.y + ', ' + user.pos.z + ')'"></span>
<br /> <br />
@@ -222,10 +222,17 @@
} }
}; };
/**
*
*/
function goBack() { function goBack() {
router.push({ name: 'tools' }); router.push({ name: 'tools' });
} }
/**
*
* @param event
*/
function handleDrop(event) { function handleDrop(event) {
if (currentlyDroppingFile.value === null) { if (currentlyDroppingFile.value === null) {
return; return;
@@ -238,6 +245,9 @@
event.preventDefault(); event.preventDefault();
} }
/**
*
*/
async function getAndDisplayScreenshotFromFile() { async function getAndDisplayScreenshotFromFile() {
let filePath = ''; let filePath = '';
@@ -259,6 +269,9 @@
getAndDisplayScreenshot(filePath); getAndDisplayScreenshot(filePath);
} }
/**
*
*/
function getAndDisplayLastScreenshot() { function getAndDisplayLastScreenshot() {
screenshotMetadataResetSearch(); screenshotMetadataResetSearch();
AppApi.GetLastScreenshot().then((path) => { AppApi.GetLastScreenshot().then((path) => {
@@ -269,6 +282,10 @@
}); });
} }
/**
*
* @param path
*/
function copyImageToClipboard(path) { function copyImageToClipboard(path) {
if (!path) { if (!path) {
return; return;
@@ -277,6 +294,10 @@
toast.success('Image copied to clipboard'); toast.success('Image copied to clipboard');
}); });
} }
/**
*
* @param path
*/
function openImageFolder(path) { function openImageFolder(path) {
if (!path) { if (!path) {
return; return;
@@ -285,6 +306,10 @@
toast.success('Opened image folder'); toast.success('Opened image folder');
}); });
} }
/**
*
* @param path
*/
function deleteMetadata(path) { function deleteMetadata(path) {
if (!path) { if (!path) {
return; return;
@@ -299,6 +324,9 @@
getAndDisplayScreenshot(D.metadata.filePath, true); getAndDisplayScreenshot(D.metadata.filePath, true);
}); });
} }
/**
*
*/
function uploadScreenshotToGallery() { function uploadScreenshotToGallery() {
const D = screenshotMetadataDialog; const D = screenshotMetadataDialog;
if (D.metadata.fileSizeBytes > 10000000) { if (D.metadata.fileSizeBytes > 10000000) {
@@ -325,6 +353,9 @@
D.isUploading = false; D.isUploading = false;
}); });
} }
/**
*
*/
function screenshotMetadataSearch() { function screenshotMetadataSearch() {
const D = screenshotMetadataDialog; const D = screenshotMetadataDialog;
@@ -370,11 +401,19 @@
}, 500); }, 500);
} }
/**
*
* @param value
*/
function handleSearchTypeChange(value) { function handleSearchTypeChange(value) {
screenshotMetadataDialog.searchType = value; screenshotMetadataDialog.searchType = value;
screenshotMetadataSearch(); screenshotMetadataSearch();
} }
/**
*
* @param index
*/
function screenshotMetadataCarouselChange(index) { function screenshotMetadataCarouselChange(index) {
const D = screenshotMetadataDialog; const D = screenshotMetadataDialog;
const searchIndex = D.searchIndex; const searchIndex = D.searchIndex;
@@ -405,6 +444,9 @@
} }
} }
/**
*
*/
function screenshotMetadataResetSearch() { function screenshotMetadataResetSearch() {
const D = screenshotMetadataDialog; const D = screenshotMetadataDialog;
@@ -413,6 +455,10 @@
D.searchResults = null; D.searchResults = null;
} }
/**
*
* @param index
*/
function screenshotMetadataCarouselChangeSearch(index) { function screenshotMetadataCarouselChangeSearch(index) {
const D = screenshotMetadataDialog; const D = screenshotMetadataDialog;
let searchIndex = D.searchIndex; let searchIndex = D.searchIndex;
@@ -445,6 +491,10 @@
D.searchIndex = searchIndex; D.searchIndex = searchIndex;
} }
/**
*
* @param api
*/
function handleScreenshotMetadataCarouselInit(api) { function handleScreenshotMetadataCarouselInit(api) {
screenshotMetadataCarouselApi.value = api; screenshotMetadataCarouselApi.value = api;
api.on('select', handleCarouselSelect); api.on('select', handleCarouselSelect);
@@ -452,6 +502,9 @@
resetCarouselIndex(); resetCarouselIndex();
} }
/**
*
*/
function handleCarouselSelect() { function handleCarouselSelect() {
if (ignoreCarouselSelect.value || !screenshotMetadataCarouselApi.value) { if (ignoreCarouselSelect.value || !screenshotMetadataCarouselApi.value) {
return; return;
@@ -460,6 +513,9 @@
screenshotMetadataCarouselChange(index); screenshotMetadataCarouselChange(index);
} }
/**
*
*/
function resetCarouselIndex() { function resetCarouselIndex() {
const api = screenshotMetadataCarouselApi.value; const api = screenshotMetadataCarouselApi.value;
if (!api) { if (!api) {
@@ -472,6 +528,11 @@
}, 0); }, 0);
} }
/**
*
* @param path
* @param needsCarouselFiles
*/
async function getAndDisplayScreenshot(path, needsCarouselFiles = true) { async function getAndDisplayScreenshot(path, needsCarouselFiles = true) {
const metadata = await AppApi.GetScreenshotMetadata(path); const metadata = await AppApi.GetScreenshotMetadata(path);
displayScreenshotMetadata(metadata, needsCarouselFiles); displayScreenshotMetadata(metadata, needsCarouselFiles);
+2 -2
View File
@@ -1,6 +1,6 @@
<template> <template>
<div id="chart" class="x-container"> <div id="chart" class="x-container">
<div class="options-container" style="margin-top: 0"> <div class="options-container mt-0">
<span class="header">{{ t('view.tools.header') }}</span> <span class="header">{{ t('view.tools.header') }}</span>
<div class="tool-categories"> <div class="tool-categories">
@@ -539,7 +539,7 @@
} }
.category-title { .category-title {
margin-left: 5px; margin-left: 6px;
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
} }
@@ -333,7 +333,7 @@
height: 24px; height: 24px;
gap: 4px; gap: 4px;
cursor: pointer; cursor: pointer;
margin-left: 5px; margin-left: 6px;
} }
.event-card .event-content { .event-card .event-content {
@@ -56,20 +56,36 @@
const selectedDayKey = computed(() => dayjs(props.modelValue).format('YYYY-MM-DD')); const selectedDayKey = computed(() => dayjs(props.modelValue).format('YYYY-MM-DD'));
/**
*
* @param dateValue
*/
function toKey(dateValue) { function toKey(dateValue) {
return dayjs(toDate(dateValue, timeZone)).format('YYYY-MM-DD'); return dayjs(toDate(dateValue, timeZone)).format('YYYY-MM-DD');
} }
/**
*
* @param dateValue
*/
function eventCountFor(dateValue) { function eventCountFor(dateValue) {
const key = toKey(dateValue); const key = toKey(dateValue);
return props.eventsByDate?.[key]?.length ?? 0; return props.eventsByDate?.[key]?.length ?? 0;
} }
/**
*
* @param dateValue
*/
function hasFollowingFor(dateValue) { function hasFollowingFor(dateValue) {
const key = toKey(dateValue); const key = toKey(dateValue);
return Boolean(props.followingByDate?.[key]); return Boolean(props.followingByDate?.[key]);
} }
/**
*
* @param next
*/
function onUpdateModelValue(next) { function onUpdateModelValue(next) {
if (!next) return; if (!next) return;
internalValue.value = next; internalValue.value = next;
@@ -78,6 +94,10 @@
emit('update:modelValue', asDate); emit('update:modelValue', asDate);
} }
/**
*
* @param next
*/
function onUpdatePlaceholder(next) { function onUpdatePlaceholder(next) {
if (!next) return; if (!next) return;
placeholder.value = next; placeholder.value = next;
@@ -85,6 +105,10 @@
emit('update:modelValue', toDate(next, timeZone)); emit('update:modelValue', toDate(next, timeZone));
} }
/**
*
* @param dateValue
*/
function dayLabel(dateValue) { function dayLabel(dateValue) {
return dayjs(toDate(dateValue, timeZone)).format('D'); return dayjs(toDate(dateValue, timeZone)).format('D');
} }
@@ -195,7 +219,7 @@
justify-content: center; justify-content: center;
font-size: 12px; font-size: 12px;
z-index: 10; z-index: 10;
padding: 0 5px; padding: 0 6px;
line-height: 14px; line-height: 14px;
} }
@@ -6,8 +6,8 @@
</DialogHeader> </DialogHeader>
<TabsUnderline v-model="activeTab" :items="editInviteTabs" :unmount-on-hide="false" class="mt-2.5"> <TabsUnderline v-model="activeTab" :items="editInviteTabs" :unmount-on-hide="false" class="mt-2.5">
<template #message> <template #message>
<DataTableLayout <DataTableLayout class="mt-2"
style="margin-top: 10px; cursor: pointer" style="cursor: pointer"
:table="inviteMessageTanstackTable" :table="inviteMessageTanstackTable"
:loading="false" :loading="false"
:show-pagination="false" :show-pagination="false"
@@ -15,7 +15,7 @@
</template> </template>
<template #request> <template #request>
<DataTableLayout <DataTableLayout
style="margin-top: 10px; cursor: pointer" style="margin-top: 8px; cursor: pointer"
:table="inviteRequestTanstackTable" :table="inviteRequestTanstackTable"
:loading="false" :loading="false"
:show-pagination="false" :show-pagination="false"
@@ -23,7 +23,7 @@
</template> </template>
<template #requestResponse> <template #requestResponse>
<DataTableLayout <DataTableLayout
style="margin-top: 10px; cursor: pointer" style="margin-top: 8px; cursor: pointer"
:table="inviteRequestResponseTanstackTable" :table="inviteRequestResponseTanstackTable"
:loading="false" :loading="false"
:show-pagination="false" :show-pagination="false"
@@ -31,7 +31,7 @@
</template> </template>
<template #response> <template #response>
<DataTableLayout <DataTableLayout
style="margin-top: 10px; cursor: pointer" style="margin-top: 8px; cursor: pointer"
:table="inviteResponseTanstackTable" :table="inviteResponseTanstackTable"
:loading="false" :loading="false"
:show-pagination="false" :show-pagination="false"
@@ -6,11 +6,9 @@
</DialogHeader> </DialogHeader>
<InputGroupTextareaField <InputGroupTextareaField
v-model="exportAvatarsListCsv" v-model="exportAvatarsListCsv"
:rows="15" :rows="15"
readonly readonly
style="margin-top: 15px" input-class="resize-none mt-4"
input-class="resize-none"
@click="$event.target.tagName === 'TEXTAREA' && $event.target.select()" /> @click="$event.target.tagName === 'TEXTAREA' && $event.target.select()" />
</DialogContent> </DialogContent>
</Dialog> </Dialog>
@@ -11,8 +11,7 @@
v-model="discordNamesContent" v-model="discordNamesContent"
:rows="15" :rows="15"
readonly readonly
style="margin-top: 15px" input-class="resize-none mt-4" />
input-class="resize-none" />
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</template> </template>
@@ -10,8 +10,7 @@
v-model="exportFriendsListCsv" v-model="exportFriendsListCsv"
:rows="15" :rows="15"
readonly readonly
style="margin-top: 15px" input-class="resize-none mt-4"
input-class="resize-none"
@click="$event.target.tagName === 'TEXTAREA' && $event.target.select()" /> @click="$event.target.tagName === 'TEXTAREA' && $event.target.select()" />
</template> </template>
<template #json> <template #json>
@@ -19,7 +18,7 @@
v-model="exportFriendsListJson" v-model="exportFriendsListJson"
:rows="15" :rows="15"
readonly readonly
style="margin-top: 15px" style="margin-top: 16px"
input-class="resize-none" input-class="resize-none"
@click="$event.target.tagName === 'TEXTAREA' && $event.target.select()" /> @click="$event.target.tagName === 'TEXTAREA' && $event.target.select()" />
</template> </template>
@@ -79,6 +78,9 @@
} }
); );
/**
*
*/
function initExportFriendsListDialog() { function initExportFriendsListDialog() {
const { friends } = currentUser.value; const { friends } = currentUser.value;
if (Array.isArray(friends) === false) { if (Array.isArray(friends) === false) {
@@ -453,8 +453,8 @@
min-width: 200px; min-width: 200px;
padding-left: 4px; padding-left: 4px;
padding-right: 16px; padding-right: 16px;
margin-left: 10px; margin-left: 8px;
margin-right: 6px; margin-right: 8px;
overflow: auto; overflow: auto;
height: 50vh; height: 50vh;
@@ -465,7 +465,7 @@
} }
.timeline-group { .timeline-group {
padding: 0 20px 6px 10px; padding: 0 20px 8px 8px;
} }
.timeline-timestamp { .timeline-timestamp {
@@ -545,10 +545,10 @@
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
align-items: center; align-items: center;
margin-top: 10px; margin-top: 8px;
.featured-switch-text { .featured-switch-text {
font-size: 13px; font-size: 13px;
margin-right: 5px; margin-right: 6px;
} }
} }
@@ -589,10 +589,10 @@
.group-header { .group-header {
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
padding: 4px 12px 10px 12px; padding: 4px 12px 8px 12px;
cursor: pointer; cursor: pointer;
border-radius: var(--radius-md); border-radius: var(--radius-md);
margin: 0 -12px 10px -12px; margin: 0 -12px 8px -12px;
display: flex; display: flex;
align-items: center; align-items: center;
+6 -18
View File
@@ -15,28 +15,16 @@
{{ t('dialog.note_export.description8') }} <br /> {{ t('dialog.note_export.description8') }} <br />
</div> </div>
<Button <Button size="sm" class="mr-2 mt-2" variant="outline" :disabled="loading" @click="updateNoteExportDialog">
size="sm"
class="mr-2"
variant="outline"
:disabled="loading"
style="margin-top: 10px"
@click="updateNoteExportDialog">
{{ t('dialog.note_export.refresh') }} {{ t('dialog.note_export.refresh') }}
</Button> </Button>
<Button <Button size="sm" class="mr-2 mt-2" variant="outline" :disabled="loading" @click="exportNoteExport">
size="sm"
class="mr-2"
variant="outline"
:disabled="loading"
style="margin-top: 10px"
@click="exportNoteExport">
{{ t('dialog.note_export.export') }} {{ t('dialog.note_export.export') }}
</Button> </Button>
<Button v-if="loading" size="sm" variant="outline" style="margin-top: 10px" @click="cancelNoteExport"> <Button class="mt-2" v-if="loading" size="sm" variant="outline" @click="cancelNoteExport">
{{ t('dialog.note_export.cancel') }} {{ t('dialog.note_export.cancel') }}
</Button> </Button>
<span v-if="loading" style="margin: 10px"> <span class="m-2" v-if="loading">
<Spinner class="inline-block ml-2 mr-2" /> <Spinner class="inline-block ml-2 mr-2" />
{{ t('dialog.note_export.progress') }} {{ progress }}/{{ progressTotal }} {{ t('dialog.note_export.progress') }} {{ progress }}/{{ progressTotal }}
</span> </span>
@@ -45,7 +33,7 @@
<Button size="sm" variant="outline" @click="errors = ''"> <Button size="sm" variant="outline" @click="errors = ''">
{{ t('dialog.note_export.clear_errors') }} {{ t('dialog.note_export.clear_errors') }}
</Button> </Button>
<h2 style="font-weight: bold; margin: 0"> <h2 class="m-0" style="font-weight: bold">
{{ t('dialog.note_export.errors') }} {{ t('dialog.note_export.errors') }}
</h2> </h2>
<pre style="white-space: pre-wrap; font-size: 12px" v-text="errors"></pre> <pre style="white-space: pre-wrap; font-size: 12px" v-text="errors"></pre>
@@ -57,7 +45,7 @@
:loading="loading" :loading="loading"
:table-style="tableStyle" :table-style="tableStyle"
:show-pagination="false" :show-pagination="false"
style="margin-top: 10px" /> style="margin-top: 8px" />
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</template> </template>
@@ -4,32 +4,24 @@
<DialogHeader> <DialogHeader>
<DialogTitle>{{ t('dialog.registry_backup.header') }}</DialogTitle> <DialogTitle>{{ t('dialog.registry_backup.header') }}</DialogTitle>
</DialogHeader> </DialogHeader>
<div style="margin-top: 10px"> <div class="mt-2">
<div style="display: flex; align-items: center; justify-content: space-between; font-size: 12px"> <div style="display: flex; align-items: center; justify-content: space-between; font-size: 12px">
<span class="name" style="margin-right: 24px">{{ t('dialog.registry_backup.auto_backup') }}</span> <span class="name mr-6">{{ t('dialog.registry_backup.auto_backup') }}</span>
<Switch :model-value="vrcRegistryAutoBackup" @update:modelValue="setVrcRegistryAutoBackup" /> <Switch :model-value="vrcRegistryAutoBackup" @update:modelValue="setVrcRegistryAutoBackup" />
</div> </div>
<div <div
style=" class="mt-1.5"
display: flex; style="display: flex; align-items: center; justify-content: space-between; font-size: 12px">
align-items: center; <span class="name mr-6">{{ t('dialog.registry_backup.ask_to_restore') }}</span>
justify-content: space-between;
font-size: 12px;
margin-top: 5px;
">
<span class="name" style="margin-right: 24px">{{
t('dialog.registry_backup.ask_to_restore')
}}</span>
<Switch :model-value="vrcRegistryAskRestore" @update:modelValue="setVrcRegistryAskRestore" /> <Switch :model-value="vrcRegistryAskRestore" @update:modelValue="setVrcRegistryAskRestore" />
</div> </div>
<DataTableLayout <DataTableLayout
class="min-w-0 w-full" class="min-w-0 w-full mt-2"
:table="table" :table="table"
:loading="false" :loading="false"
:table-style="tableStyle" :table-style="tableStyle"
:show-pagination="false" :show-pagination="false" />
style="margin-top: 10px" /> <div class="mt-2" style="display: flex; align-items: center; justify-content: space-between">
<div style="display: flex; align-items: center; justify-content: space-between; margin-top: 10px">
<Button size="sm" variant="destructive" @click="deleteVrcRegistry">{{ <Button size="sm" variant="destructive" @click="deleteVrcRegistry">{{
t('dialog.registry_backup.reset') t('dialog.registry_backup.reset')
}}</Button> }}</Button>
@@ -111,11 +103,18 @@
} }
); );
/**
*
*/
async function updateRegistryBackupDialog() { async function updateRegistryBackupDialog() {
const backupsJson = await configRepository.getString('VRCX_VRChatRegistryBackups'); const backupsJson = await configRepository.getString('VRCX_VRChatRegistryBackups');
registryBackupTable.value.data = JSON.parse(backupsJson || '[]'); registryBackupTable.value.data = JSON.parse(backupsJson || '[]');
} }
/**
*
* @param row
*/
function restoreVrcRegistryBackup(row) { function restoreVrcRegistryBackup(row) {
modalStore modalStore
.confirm({ .confirm({
@@ -139,10 +138,18 @@
.catch(() => {}); .catch(() => {});
} }
/**
*
* @param row
*/
function saveVrcRegistryBackupToFile(row) { function saveVrcRegistryBackupToFile(row) {
downloadAndSaveJson(row.name, row.data); downloadAndSaveJson(row.name, row.data);
} }
/**
*
* @param row
*/
async function deleteVrcRegistryBackup(row) { async function deleteVrcRegistryBackup(row) {
const backups = registryBackupTable.value.data; const backups = registryBackupTable.value.data;
removeFromArray(backups, row); removeFromArray(backups, row);
@@ -150,6 +157,9 @@
await updateRegistryBackupDialog(); await updateRegistryBackupDialog();
} }
/**
*
*/
function deleteVrcRegistry() { function deleteVrcRegistry() {
modalStore modalStore
.confirm({ .confirm({
@@ -167,11 +177,18 @@
.catch(() => {}); .catch(() => {});
} }
/**
*
* @param name
*/
async function handleBackupVrcRegistry(name) { async function handleBackupVrcRegistry(name) {
await backupVrcRegistry(name); await backupVrcRegistry(name);
await updateRegistryBackupDialog(); await updateRegistryBackupDialog();
} }
/**
*
*/
function promptVrcRegistryBackupName() { function promptVrcRegistryBackupName() {
modalStore modalStore
.prompt({ .prompt({
@@ -188,6 +205,9 @@
.catch(() => {}); .catch(() => {});
} }
/**
*
*/
async function openJsonFileSelectorDialogElectron() { async function openJsonFileSelectorDialogElectron() {
return new Promise((resolve) => { return new Promise((resolve) => {
const fileInput = document.createElement('input'); const fileInput = document.createElement('input');
@@ -216,6 +236,9 @@
}); });
} }
/**
*
*/
async function restoreVrcRegistryFromFile() { async function restoreVrcRegistryFromFile() {
const filePath = await AppApi.OpenFileSelectorDialog(null, '.json', 'JSON Files (*.json)|*.json'); const filePath = await AppApi.OpenFileSelectorDialog(null, '.json', 'JSON Files (*.json)|*.json');
if (WINDOWS) { if (WINDOWS) {
@@ -256,10 +279,16 @@
} }
} }
/**
*
*/
function clearVrcRegistryDialog() { function clearVrcRegistryDialog() {
registryBackupTable.value.data = []; registryBackupTable.value.data = [];
} }
/**
*
*/
function closeAndClearDialog() { function closeAndClearDialog() {
closeDialog(); closeDialog();
// TODO: Element Plus had a distinct @closed event after animation. // TODO: Element Plus had a distinct @closed event after animation.
@@ -267,6 +296,9 @@
clearVrcRegistryDialog(); clearVrcRegistryDialog();
} }
/**
*
*/
function closeDialog() { function closeDialog() {
isRegistryBackupDialogVisible.value = false; isRegistryBackupDialogVisible.value = false;
} }