improve settings ui

This commit is contained in:
pa
2026-03-16 11:30:11 +09:00
parent 8e3c1e0054
commit dcec53cdc3
9 changed files with 881 additions and 897 deletions
+1 -1
View File
@@ -108,7 +108,7 @@
:value="it.value" :value="it.value"
:class="[ :class="[
'pt-4 outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ring-offset-background', 'pt-4 outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ring-offset-background',
fill ? 'min-h-0 flex-1' : '' fill ? 'min-h-0 flex-1 overflow-y-auto' : ''
]"> ]">
<slot :name="it.value" /> <slot :name="it.value" />
</TabsContent> </TabsContent>
+4 -4
View File
@@ -1,13 +1,13 @@
<template> <template>
<div class="x-container"> <div class="x-container flex flex-col overflow-hidden!">
<div class="options-container mt-0 p-1.5"> <div class="shrink-0 p-1.5">
<span class="header">{{ t('view.settings.header') }}</span> <span class="text-lg font-semibold text-foreground">{{ t('view.settings.header') }}</span>
</div> </div>
<TabsUnderline <TabsUnderline
default-value="general" default-value="general"
:items="settingsTabs" :items="settingsTabs"
:unmount-on-hide="false" :unmount-on-hide="false"
style="height: calc(100% - 51px)"> fill>
<template #general> <template #general>
<GeneralTab /> <GeneralTab />
</template> </template>
@@ -1,6 +1,11 @@
<template> <template>
<div class="flex flex-col gap-3.5"> <div class="flex flex-col gap-3.5">
<h3 v-if="title" class="text-base font-semibold pl-0.5 text-foreground m-0">{{ title }}</h3> <div v-if="title || $slots.description" class="flex flex-col gap-1.5 pl-0.5">
<h3 v-if="title" class="text-base font-semibold text-foreground m-0">{{ title }}</h3>
<div v-if="$slots.description" class="text-sm text-muted-foreground">
<slot name="description" />
</div>
</div>
<Card class="p-0"> <Card class="p-0">
<CardContent class="flex flex-col gap-1 py-4.5 px-5.5"> <CardContent class="flex flex-col gap-1 py-4.5 px-5.5">
<slot /> <slot />
+201 -295
View File
@@ -1,193 +1,183 @@
<template> <template>
<div> <div class="flex flex-col gap-10 py-2">
<div class="options-container mt-2!"> <SettingsGroup :title="t('view.settings.advanced.advanced.vrchat_settings.header')">
<div class="header">{{ t('view.settings.advanced.advanced.vrchat_settings.header') }}</div> <SettingsItem :label="t('view.settings.advanced.advanced.relaunch_vrchat.header')"
<span class="sub-header">{{ t('view.settings.advanced.advanced.relaunch_vrchat.header') }}</span> :description="t('view.settings.advanced.advanced.relaunch_vrchat.description')">
<simple-switch <Switch :model-value="relaunchVRChatAfterCrash" @update:modelValue="setRelaunchVRChatAfterCrash" />
:label="t('view.settings.advanced.advanced.relaunch_vrchat.description')" </SettingsItem>
:value="relaunchVRChatAfterCrash"
:long-label="true"
@change="setRelaunchVRChatAfterCrash" />
<span class="sub-header">{{ t('view.settings.advanced.advanced.vrchat_quit_fix.header') }}</span> <SettingsItem :label="t('view.settings.advanced.advanced.vrchat_quit_fix.header')"
<simple-switch :description="t('view.settings.advanced.advanced.vrchat_quit_fix.description')">
:label="t('view.settings.advanced.advanced.vrchat_quit_fix.description')" <Switch :model-value="vrcQuitFix" @update:modelValue="setVrcQuitFix" />
:value="vrcQuitFix" </SettingsItem>
:long-label="true"
@change="setVrcQuitFix" />
<span class="sub-header">{{ t('view.settings.advanced.advanced.auto_cache_management.header') }}</span> <SettingsItem :label="t('view.settings.advanced.advanced.auto_cache_management.header')"
<simple-switch :description="t('view.settings.advanced.advanced.auto_cache_management.description')">
:label="t('view.settings.advanced.advanced.auto_cache_management.description')" <Switch :model-value="autoSweepVRChatCache" @update:modelValue="setAutoSweepVRChatCache" />
:value="autoSweepVRChatCache" </SettingsItem>
:long-label="true"
@change="setAutoSweepVRChatCache" />
<span class="sub-header">{{ t('view.settings.advanced.advanced.self_invite.header') }}</span> <SettingsItem :label="t('view.settings.advanced.advanced.self_invite.header')"
<simple-switch :description="t('view.settings.advanced.advanced.self_invite.description')">
:label="t('view.settings.advanced.advanced.self_invite.description')" <Switch :model-value="selfInviteOverride" @update:modelValue="setSelfInviteOverride" />
:value="selfInviteOverride" </SettingsItem>
:long-label="true" </SettingsGroup>
@change="setSelfInviteOverride" />
</div> <SettingsGroup :title="t('view.settings.advanced.advanced.vrcx_settings.header')">
<div class="options-container"> <SettingsItem :label="t('view.settings.advanced.advanced.primary_password.header')"
<div class="header">{{ t('view.settings.advanced.advanced.vrcx_settings.header') }}</div> :description="t('view.settings.advanced.advanced.primary_password.description')">
<span class="sub-header">{{ t('view.settings.advanced.advanced.primary_password.header') }}</span> <Switch
<simple-switch :model-value="enablePrimaryPassword"
:label="t('view.settings.advanced.advanced.primary_password.description')"
:value="enablePrimaryPassword"
:disabled="!enablePrimaryPassword" :disabled="!enablePrimaryPassword"
:long-label="true" @update:modelValue="enablePrimaryPasswordChange" />
@change="enablePrimaryPasswordChange" /> </SettingsItem>
<div v-if="branch === 'Nightly'"> <template v-if="branch === 'Nightly'">
<span class="sub-header">{{ <SettingsItem :label="t('view.settings.advanced.advanced.anonymous_error_reporting.header')"
t('view.settings.advanced.advanced.anonymous_error_reporting.header') :description="t('view.settings.advanced.advanced.anonymous_error_reporting.description')">
}}</span> <Switch :model-value="sentryErrorReporting" @update:modelValue="setSentryErrorReporting()" />
<simple-switch </SettingsItem>
:label="t('view.settings.advanced.advanced.anonymous_error_reporting.description')" </template>
:value="sentryErrorReporting" </SettingsGroup>
:long-label="true"
@change="setSentryErrorReporting()" />
</div>
<span class="sub-header">{{ t('view.settings.general.logging.header') }}</span> <SettingsGroup :title="t('view.settings.general.logging.header')">
<simple-switch <SettingsItem :label="t('view.settings.advanced.advanced.cache_debug.udon_exception_logging')">
:label="t('view.settings.advanced.advanced.cache_debug.udon_exception_logging')" <Switch :model-value="udonExceptionLogging" @update:modelValue="setUdonExceptionLogging" />
:value="udonExceptionLogging" </SettingsItem>
@change="setUdonExceptionLogging" />
<simple-switch <SettingsItem :label="t('view.settings.general.logging.resource_load')">
:label="t('view.settings.general.logging.resource_load')" <Switch :model-value="logResourceLoad" @update:modelValue="setLogResourceLoad" />
:value="logResourceLoad" </SettingsItem>
@change="setLogResourceLoad" />
<simple-switch <SettingsItem :label="t('view.settings.general.logging.empty_avatar')">
:label="t('view.settings.general.logging.empty_avatar')" <Switch :model-value="logEmptyAvatars" @update:modelValue="setLogEmptyAvatars" />
:value="logEmptyAvatars" </SettingsItem>
@change="setLogEmptyAvatars" />
<simple-switch <SettingsItem :label="t('view.settings.general.logging.auto_login_delay')">
:label="t('view.settings.general.logging.auto_login_delay')" <Switch :model-value="autoLoginDelayEnabled" @update:modelValue="setAutoLoginDelayEnabled" />
:value="autoLoginDelayEnabled" </SettingsItem>
@change="setAutoLoginDelayEnabled" />
<div v-if="autoLoginDelayEnabled" class="options-container-item"> <SettingsItem v-if="autoLoginDelayEnabled"
:label="t('view.settings.general.logging.auto_login_delay_button')">
<Button size="sm" variant="outline" @click="promptAutoLoginDelaySeconds"> <Button size="sm" variant="outline" @click="promptAutoLoginDelaySeconds">
{{ t('view.settings.general.logging.auto_login_delay_button') }} {{ t('view.settings.general.logging.auto_login_delay_button') }}
</Button> </Button>
</div> </SettingsItem>
</div> </SettingsGroup>
<div class="options-container">
<span class="header">{{ t('view.profile.game_info.header') }}</span> <SettingsGroup :title="t('view.profile.game_info.header')">
<div class="px-2.5 overflow-y-auto overflow-x-hidden mt-2"> <div class="px-1 py-1">
<div class="box-border flex items-center p-1.5 text-[13px] cursor-pointer"> <div class="flex-1 cursor-pointer" @click="getVisits">
<div class="flex-1 overflow-hidden" @click="getVisits"> <span class="block truncate font-medium text-sm leading-[18px]">{{
<span class="block truncate font-medium leading-[18px]">{{
t('view.profile.game_info.online_users') t('view.profile.game_info.online_users')
}}</span> }}</span>
<span v-if="visits" class="block truncate text-xs">{{ <span v-if="visits" class="block truncate text-xs text-muted-foreground">{{
t('view.profile.game_info.user_online', { count: visits }) t('view.profile.game_info.user_online', { count: visits })
}}</span> }}</span>
<span v-else class="block truncate text-xs">{{ t('view.profile.game_info.refresh') }}</span> <span v-else class="block truncate text-xs text-muted-foreground">{{
t('view.profile.game_info.refresh')
}}</span>
</div> </div>
</div> </div>
</div> </SettingsGroup>
</div>
<div class="options-container"> <SettingsGroup :title="t('view.settings.advanced.advanced.remote_database.header')">
<span class="header">{{ t('view.settings.advanced.advanced.remote_database.header') }}</span> <SettingsItem :label="t('view.settings.advanced.advanced.remote_database.enable')">
<simple-switch <Switch
:label="t('view.settings.advanced.advanced.remote_database.enable')" :model-value="avatarRemoteDatabase"
:value="avatarRemoteDatabase" @update:modelValue="setAvatarRemoteDatabase(!avatarRemoteDatabase)" />
:long-label="true" </SettingsItem>
@change="setAvatarRemoteDatabase(!avatarRemoteDatabase)" />
<div class="options-container-item"> <SettingsItem :label="t('view.settings.advanced.advanced.remote_database.avatar_database_provider')">
<Button size="sm" variant="outline" @click="showAvatarProviderDialog">{{ <Button size="sm" variant="outline" @click="showAvatarProviderDialog">{{
t('view.settings.advanced.advanced.remote_database.avatar_database_provider') t('view.settings.advanced.advanced.remote_database.avatar_database_provider')
}}</Button> }}</Button>
</div> </SettingsItem>
</div> </SettingsGroup>
<template v-if="!isLinux"> <template v-if="!isLinux">
<div class="options-container"> <SettingsGroup :title="t('view.settings.advanced.advanced.app_launcher.header')">
<span class="header">{{ t('view.settings.advanced.advanced.app_launcher.header') }}</span> <SettingsItem :label="t('view.settings.advanced.advanced.app_launcher.folder')">
<br /> <Button size="sm" variant="outline" @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 </SettingsItem>
:label="t('view.settings.advanced.advanced.remote_database.enable')"
:value="enableAppLauncher" <SettingsItem :label="t('view.settings.advanced.advanced.remote_database.enable')"
:tooltip="t('view.settings.advanced.advanced.app_launcher.folder_tooltip')" :description="t('view.settings.advanced.advanced.app_launcher.folder_tooltip')">
:long-label="true" <Switch :model-value="enableAppLauncher" @update:modelValue="setEnableAppLauncher" />
@change="setEnableAppLauncher" /> </SettingsItem>
<simple-switch
:label="t('view.settings.advanced.advanced.app_launcher.auto_close')" <SettingsItem :label="t('view.settings.advanced.advanced.app_launcher.auto_close')">
:value="enableAppLauncherAutoClose" <Switch
:long-label="true" :model-value="enableAppLauncherAutoClose"
@change="setEnableAppLauncherAutoClose" /> @update:modelValue="setEnableAppLauncherAutoClose" />
<simple-switch </SettingsItem>
:label="t('view.settings.advanced.advanced.app_launcher.run_process_once')"
:value="enableAppLauncherRunProcessOnce" <SettingsItem :label="t('view.settings.advanced.advanced.app_launcher.run_process_once')">
:long-label="true" <Switch
@change="setEnableAppLauncherRunProcessOnce" /> :model-value="enableAppLauncherRunProcessOnce"
</div> @update:modelValue="setEnableAppLauncherRunProcessOnce" />
</SettingsItem>
</SettingsGroup>
</template> </template>
<div class="options-container">
<span class="header">{{ t('view.settings.advanced.advanced.youtube_api.header') }}</span> <SettingsGroup :title="t('view.settings.advanced.advanced.youtube_api.header')">
<simple-switch <SettingsItem :label="t('view.settings.advanced.advanced.youtube_api.enable')"
:label="t('view.settings.advanced.advanced.youtube_api.enable')" :description="t('view.settings.advanced.advanced.youtube_api.enable_tooltip')">
:value="youTubeApi" <Switch :model-value="youTubeApi" @update:modelValue="changeYouTubeApi('VRCX_youtubeAPI')" />
:tooltip="t('view.settings.advanced.advanced.youtube_api.enable_tooltip')" </SettingsItem>
:long-label="true"
@change="changeYouTubeApi('VRCX_youtubeAPI')" /> <SettingsItem :label="t('view.settings.advanced.advanced.youtube_api.youtube_api_key')">
<div class="options-container-item">
<Button size="sm" variant="outline" @click="showYouTubeApiDialog">{{ <Button size="sm" variant="outline" @click="showYouTubeApiDialog">{{
t('view.settings.advanced.advanced.youtube_api.youtube_api_key') t('view.settings.advanced.advanced.youtube_api.youtube_api_key')
}}</Button> }}</Button>
</div> </SettingsItem>
</div> </SettingsGroup>
<div class="options-container">
<span class="header">{{ t('view.settings.advanced.advanced.translation_api.header') }}</span> <SettingsGroup :title="t('view.settings.advanced.advanced.translation_api.header')">
<simple-switch <SettingsItem :label="t('view.settings.advanced.advanced.translation_api.enable')"
:label="t('view.settings.advanced.advanced.translation_api.enable')" :description="t('view.settings.advanced.advanced.translation_api.enable_tooltip')">
:value="translationApi" <Switch :model-value="translationApi" @update:modelValue="changeTranslationAPI('VRCX_translationAPI')" />
:tooltip="t('view.settings.advanced.advanced.translation_api.enable_tooltip')" </SettingsItem>
:long-label="true"
@change="changeTranslationAPI('VRCX_translationAPI')" /> <SettingsItem :label="t('view.settings.advanced.advanced.translation_api.translation_api_key')">
<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: 6px" /> <Languages class="h-4 w-4 mr-1.5" />
{{ t('view.settings.advanced.advanced.translation_api.translation_api_key') }} {{ t('view.settings.advanced.advanced.translation_api.translation_api_key') }}
</Button> </Button>
</div> </SettingsItem>
</div> </SettingsGroup>
<div class="options-container">
<span class="header">{{ t('view.settings.advanced.advanced.video_progress_pie.header') }}</span> <SettingsGroup :title="t('view.settings.advanced.advanced.video_progress_pie.header')">
<simple-switch <SettingsItem :label="t('view.settings.advanced.advanced.video_progress_pie.enable')"
:label="t('view.settings.advanced.advanced.video_progress_pie.enable')" :description="t('view.settings.advanced.advanced.video_progress_pie.enable_tooltip')">
:value="progressPie" <Switch
:model-value="progressPie"
:disabled="!openVR" :disabled="!openVR"
:tooltip="t('view.settings.advanced.advanced.video_progress_pie.enable_tooltip')" @update:modelValue="changeYouTubeApi('VRCX_progressPie')" />
:long-label="true" </SettingsItem>
@change="changeYouTubeApi('VRCX_progressPie')" />
<simple-switch <SettingsItem :label="t('view.settings.advanced.advanced.video_progress_pie.dance_world_only')">
:label="t('view.settings.advanced.advanced.video_progress_pie.dance_world_only')" <Switch
:value="progressPieFilter" :model-value="progressPieFilter"
:disabled="!openVR" :disabled="!openVR"
:long-label="true" @update:modelValue="changeYouTubeApi('VRCX_progressPieFilter')" />
@change="changeYouTubeApi('VRCX_progressPieFilter')" /> </SettingsItem>
</div> </SettingsGroup>
<div class="options-container">
<span class="header">{{ t('view.settings.advanced.advanced.launch_commands.header') }}</span> <SettingsGroup :title="t('view.settings.advanced.advanced.launch_commands.header')">
<simple-switch <SettingsItem
:label="t('view.settings.advanced.advanced.launch_commands.show_confirmation_on_switch_avatar_enable')" :label="t('view.settings.advanced.advanced.launch_commands.show_confirmation_on_switch_avatar_enable')"
:value="showConfirmationOnSwitchAvatar" :description="t('view.settings.advanced.advanced.launch_commands.show_confirmation_on_switch_avatar_tooltip')">
:tooltip=" <Switch
t('view.settings.advanced.advanced.launch_commands.show_confirmation_on_switch_avatar_tooltip') :model-value="showConfirmationOnSwitchAvatar"
" @update:modelValue="setShowConfirmationOnSwitchAvatar" />
:long-label="true" </SettingsItem>
@change="setShowConfirmationOnSwitchAvatar" />
<div class="options-container-item"> <div class="flex gap-2">
<Button <Button
size="sm" size="sm"
variant="outline" variant="outline"
class="mr-2"
@click="openExternalLink('https://github.com/vrcx-team/VRCX/wiki/Launch-parameters-&-VRCX.json')" @click="openExternalLink('https://github.com/vrcx-team/VRCX/wiki/Launch-parameters-&-VRCX.json')"
>{{ t('view.settings.advanced.advanced.launch_commands.docs') }}</Button >{{ t('view.settings.advanced.advanced.launch_commands.docs') }}</Button
> >
@@ -198,15 +188,14 @@
>{{ t('view.settings.advanced.advanced.launch_commands.website_userscript') }}</Button >{{ t('view.settings.advanced.advanced.launch_commands.website_userscript') }}</Button
> >
</div> </div>
</div> </SettingsGroup>
<div class="options-container">
<span class="header">{{ t('view.settings.advanced.advanced.cache_debug.header') }}</span> <SettingsGroup :title="t('view.settings.advanced.advanced.cache_debug.header')">
<br /> <div class="flex gap-2 flex-wrap">
<div class="options-container-item"> <Button size="sm" variant="outline" @click="clearVRCXCache">{{
<Button size="sm" variant="outline" class="mr-2" @click="clearVRCXCache">{{
t('view.settings.advanced.advanced.cache_debug.clear_cache') t('view.settings.advanced.advanced.cache_debug.clear_cache')
}}</Button> }}</Button>
<Button size="sm" variant="outline" class="mr-2" @click="promptAutoClearVRCXCacheFrequency">{{ <Button size="sm" variant="outline" @click="promptAutoClearVRCXCacheFrequency">{{
t('view.settings.advanced.advanced.cache_debug.auto_clear_cache') t('view.settings.advanced.advanced.cache_debug.auto_clear_cache')
}}</Button> }}</Button>
<Button size="sm" variant="outline" @click="refreshCacheSize">{{ <Button size="sm" variant="outline" @click="refreshCacheSize">{{
@@ -214,146 +203,61 @@
}}</Button> }}</Button>
</div> </div>
<simple-switch <SettingsItem
:label="`${t('view.settings.advanced.advanced.cache_debug.disable_gamelog')} ${t('view.settings.advanced.advanced.cache_debug.disable_gamelog_notice')}`" :label="`${t('view.settings.advanced.advanced.cache_debug.disable_gamelog')} ${t('view.settings.advanced.advanced.cache_debug.disable_gamelog_notice')}`">
:value="gameLogDisabled" <Switch :model-value="gameLogDisabled" @update:modelValue="disableGameLogDialog()" />
:long-label="true" </SettingsItem>
@change="disableGameLogDialog()" />
<div class="options-container-item"> <div class="flex flex-col gap-1 text-sm">
<span class="name"> <span>{{ t('view.settings.advanced.advanced.cache_debug.user_cache') }} <span v-text="cacheSize.cachedUsers"></span></span>
{{ t('view.settings.advanced.advanced.cache_debug.user_cache') }} <span>{{ t('view.settings.advanced.advanced.cache_debug.world_cache') }} <span v-text="cacheSize.cachedWorlds"></span></span>
<span v-text="cacheSize.cachedUsers"></span> <span>{{ t('view.settings.advanced.advanced.cache_debug.avatar_cache') }} <span v-text="cacheSize.cachedAvatars"></span></span>
</span> <span>{{ t('view.settings.advanced.advanced.cache_debug.group_cache') }} <span v-text="cacheSize.cachedGroups"></span></span>
<span>{{ t('view.settings.advanced.advanced.cache_debug.avatar_name_cache') }} <span v-text="cacheSize.cachedAvatarNames"></span></span>
<span>{{ t('view.settings.advanced.advanced.cache_debug.instance_cache') }} <span v-text="cacheSize.cachedInstances"></span></span>
</div> </div>
<div class="options-container-item">
<span class="name"> <SettingsItem :label="t('view.settings.advanced.advanced.cache_debug.show_console')">
{{ t('view.settings.advanced.advanced.cache_debug.world_cache') }}
<span v-text="cacheSize.cachedWorlds"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.cache_debug.avatar_cache') }}
<span v-text="cacheSize.cachedAvatars"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.cache_debug.group_cache') }}
<span v-text="cacheSize.cachedGroups"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.cache_debug.avatar_name_cache') }}
<span v-text="cacheSize.cachedAvatarNames"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.cache_debug.instance_cache') }}
<span v-text="cacheSize.cachedInstances"></span>
</span>
</div>
<div class="options-container-item">
<Button size="sm" variant="outline" @click="showConsole">{{ <Button size="sm" variant="outline" @click="showConsole">{{
t('view.settings.advanced.advanced.cache_debug.show_console') t('view.settings.advanced.advanced.cache_debug.show_console')
}}</Button> }}</Button>
</div> </SettingsItem>
</div> </SettingsGroup>
<div class="options-container">
<span class="sub-header">{{ t('view.settings.advanced.advanced.sqlite_table_size.header') }}</span> <SettingsGroup :title="t('view.settings.advanced.advanced.sqlite_table_size.header')">
<div class="options-container-item"> <SettingsItem :label="t('view.settings.advanced.advanced.sqlite_table_size.refresh')">
<Button size="sm" variant="outline" @click="getSqliteTableSizes">{{ <Button size="sm" variant="outline" @click="getSqliteTableSizes">{{
t('view.settings.advanced.advanced.sqlite_table_size.refresh') t('view.settings.advanced.advanced.sqlite_table_size.refresh')
}}</Button> }}</Button>
</div> </SettingsItem>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.sqlite_table_size.gps') }}
<span v-text="sqliteTableSizes.gps"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.sqlite_table_size.status') }}
<span v-text="sqliteTableSizes.status"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.sqlite_table_size.bio') }}
<span v-text="sqliteTableSizes.bio"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.sqlite_table_size.avatar') }}
<span v-text="sqliteTableSizes.avatar"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.sqlite_table_size.online_offline') }}
<span v-text="sqliteTableSizes.onlineOffline"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.sqlite_table_size.friend_log_history') }}
<span v-text="sqliteTableSizes.friendLogHistory"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.sqlite_table_size.notification') }}
<span v-text="sqliteTableSizes.notification"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.sqlite_table_size.location') }}
<span v-text="sqliteTableSizes.location"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.sqlite_table_size.join_leave') }}
<span v-text="sqliteTableSizes.joinLeave"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.sqlite_table_size.portal_spawn') }}
<span v-text="sqliteTableSizes.portalSpawn"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.sqlite_table_size.video_play') }}
<span v-text="sqliteTableSizes.videoPlay"></span>
</span>
</div>
<div class="options-container-item">
<span class="name">
{{ t('view.settings.advanced.advanced.sqlite_table_size.event') }}
<span v-text="sqliteTableSizes.event"></span>
</span>
</div>
</div>
<div class="options-container"> <div class="flex flex-col gap-1 text-sm">
<div class="header-bar"> <span>{{ t('view.settings.advanced.advanced.sqlite_table_size.gps') }} <span v-text="sqliteTableSizes.gps"></span></span>
<span class="header">{{ t('view.profile.config_json') }}</span> <span>{{ t('view.settings.advanced.advanced.sqlite_table_size.status') }} <span v-text="sqliteTableSizes.status"></span></span>
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.bio') }} <span v-text="sqliteTableSizes.bio"></span></span>
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.avatar') }} <span v-text="sqliteTableSizes.avatar"></span></span>
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.online_offline') }} <span v-text="sqliteTableSizes.onlineOffline"></span></span>
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.friend_log_history') }} <span v-text="sqliteTableSizes.friendLogHistory"></span></span>
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.notification') }} <span v-text="sqliteTableSizes.notification"></span></span>
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.location') }} <span v-text="sqliteTableSizes.location"></span></span>
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.join_leave') }} <span v-text="sqliteTableSizes.joinLeave"></span></span>
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.portal_spawn') }} <span v-text="sqliteTableSizes.portalSpawn"></span></span>
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.video_play') }} <span v-text="sqliteTableSizes.videoPlay"></span></span>
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.event') }} <span v-text="sqliteTableSizes.event"></span></span>
</div>
</SettingsGroup>
<SettingsGroup :title="t('view.profile.config_json')">
<div class="flex items-center gap-2">
<TooltipWrapper side="top" :content="t('view.profile.refresh_tooltip')"> <TooltipWrapper side="top" :content="t('view.profile.refresh_tooltip')">
<Button class="rounded-full mr-2" size="icon-sm" variant="outline" @click="refreshConfigTreeData()"> <Button class="rounded-full" size="icon-sm" variant="outline" @click="refreshConfigTreeData()">
<RefreshCcw /> <RefreshCcw />
</Button> </Button>
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper side="top" :content="t('view.profile.clear_results_tooltip')"> <TooltipWrapper side="top" :content="t('view.profile.clear_results_tooltip')">
<Button class="rounded-full" size="icon-sm" variant="outline" @click="configTreeData = {}"> <Button class="rounded-full" size="icon-sm" variant="outline" @click="configTreeData = {}">
<Trash2 <Trash2 />
/></Button> </Button>
</TooltipWrapper> </TooltipWrapper>
</div> </div>
<vue-json-pretty <vue-json-pretty
@@ -365,7 +269,7 @@
:dynamic-height="false" :dynamic-height="false"
virtual virtual
show-icon /> show-icon />
</div> </SettingsGroup>
<RegistryBackupDialog /> <RegistryBackupDialog />
<YouTubeApiDialog v-model:isYouTubeApiDialogVisible="isYouTubeApiDialogVisible" /> <YouTubeApiDialog v-model:isYouTubeApiDialogVisible="isYouTubeApiDialogVisible" />
@@ -379,6 +283,7 @@
import { Languages, RefreshCcw, Trash2 } from 'lucide-vue-next'; import { Languages, RefreshCcw, Trash2 } from 'lucide-vue-next';
import { computed, reactive, ref } from 'vue'; import { computed, reactive, ref } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Switch } from '@/components/ui/switch';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -400,18 +305,19 @@
useVRCXUpdaterStore, useVRCXUpdaterStore,
useVrStore, useVrStore,
useWorldStore useWorldStore
} from '../../../../stores'; } from '@/stores';
import { authRequest, queryRequest } from '../../../../api'; import { authRequest, queryRequest } from '@/api';
import { disableGameLogDialog } from '../../../../coordinators/gameLogCoordinator'; import { disableGameLogDialog } from '@/coordinators/gameLogCoordinator';
import { clearVRCXCache } from '../../../../coordinators/vrcxCoordinator'; import { clearVRCXCache } from '@/coordinators/vrcxCoordinator';
import { openExternalLink } from '../../../../shared/utils'; import { openExternalLink } from '@/shared/utils';
import AvatarProviderDialog from '../../dialogs/AvatarProviderDialog.vue'; import AvatarProviderDialog from '../../dialogs/AvatarProviderDialog.vue';
import PhotonSettings from '../PhotonSettings.vue'; import PhotonSettings from '../PhotonSettings.vue';
import RegistryBackupDialog from '../../../Tools/dialogs/RegistryBackupDialog.vue'; import RegistryBackupDialog from '../../../Tools/dialogs/RegistryBackupDialog.vue';
import SimpleSwitch from '../SimpleSwitch.vue';
import TranslationApiDialog from '../../dialogs/TranslationApiDialog.vue'; import TranslationApiDialog from '../../dialogs/TranslationApiDialog.vue';
import YouTubeApiDialog from '../../dialogs/YouTubeApiDialog.vue'; import YouTubeApiDialog from '../../dialogs/YouTubeApiDialog.vue';
import SettingsGroup from '../SettingsGroup.vue';
import SettingsItem from '../SettingsItem.vue';
const { t } = useI18n(); const { t } = useI18n();
@@ -1,87 +1,111 @@
<template> <template>
<div class="options-container mt-0"> <div class="flex flex-col gap-10 py-2">
<span class="header">{{ t('view.settings.discord_presence.discord_presence.header') }}</span> <SettingsGroup :title="t('view.settings.discord_presence.discord_presence.header')">
<div class="options-container-item"> <template #description>
<span>{{ t('view.settings.discord_presence.discord_presence.description') }}</span> <p class="m-0">{{ t('view.settings.discord_presence.discord_presence.description') }}</p>
</div> <p class="m-0 cursor-pointer hover:text-foreground transition-colors" @click="showVRChatConfig">
<div class="options-container-item" @click="showVRChatConfig" style="cursor: pointer"> {{ t('view.settings.discord_presence.discord_presence.enable_tooltip') }}
<span>{{ t('view.settings.discord_presence.discord_presence.enable_tooltip') }}</span> </p>
</div> </template>
<br />
<simple-switch <SettingsItem :label="t('view.settings.discord_presence.discord_presence.enable')">
:label="t('view.settings.discord_presence.discord_presence.enable')" <Switch
:value="discordActive" :model-value="discordActive"
@change=" @update:modelValue="
setDiscordActive(); setDiscordActive();
saveDiscordOption(); saveDiscordOption();
" /> " />
<simple-switch </SettingsItem>
<SettingsItem
:label="t('view.settings.discord_presence.discord_presence.world_integration')" :label="t('view.settings.discord_presence.discord_presence.world_integration')"
:value="discordWorldIntegration" :description="t('view.settings.discord_presence.discord_presence.world_integration_tooltip')">
<Switch
:model-value="discordWorldIntegration"
:disabled="!discordActive" :disabled="!discordActive"
@change=" @update:modelValue="
setDiscordWorldIntegration(); setDiscordWorldIntegration();
saveDiscordOption(); saveDiscordOption();
" " />
:tooltip="t('view.settings.discord_presence.discord_presence.world_integration_tooltip')" /> </SettingsItem>
<simple-switch
:label="t('view.settings.discord_presence.discord_presence.instance_type_player_count')" <SettingsItem
:value="discordInstance" :label="t('view.settings.discord_presence.discord_presence.instance_type_player_count')">
<Switch
:model-value="discordInstance"
:disabled="!discordActive" :disabled="!discordActive"
@change=" @update:modelValue="
setDiscordInstance(); setDiscordInstance();
saveDiscordOption(); saveDiscordOption();
" /> " />
<simple-switch </SettingsItem>
:label="t('view.settings.discord_presence.discord_presence.show_current_platform')"
:value="discordShowPlatform" <SettingsItem :label="t('view.settings.discord_presence.discord_presence.show_current_platform')">
<Switch
:model-value="discordShowPlatform"
:disabled="!discordActive || !discordInstance" :disabled="!discordActive || !discordInstance"
@change=" @update:modelValue="
setDiscordShowPlatform(); setDiscordShowPlatform();
saveDiscordOption(); saveDiscordOption();
" /> " />
<simple-switch </SettingsItem>
:label="t('view.settings.discord_presence.discord_presence.show_details_in_private')"
:value="!discordHideInvite" <SettingsItem
:label="t('view.settings.discord_presence.discord_presence.show_details_in_private')">
<Switch
:model-value="!discordHideInvite"
:disabled="!discordActive" :disabled="!discordActive"
@change=" @update:modelValue="
setDiscordHideInvite(); setDiscordHideInvite();
saveDiscordOption(); saveDiscordOption();
" /> " />
<simple-switch </SettingsItem>
:label="t('view.settings.discord_presence.discord_presence.join_button')"
:value="discordJoinButton" <SettingsItem :label="t('view.settings.discord_presence.discord_presence.join_button')">
<Switch
:model-value="discordJoinButton"
:disabled="!discordActive" :disabled="!discordActive"
@change=" @update:modelValue="
setDiscordJoinButton(); setDiscordJoinButton();
saveDiscordOption(); saveDiscordOption();
" /> " />
<simple-switch </SettingsItem>
:label="t('view.settings.discord_presence.discord_presence.show_images')"
:value="!discordHideImage" <SettingsItem :label="t('view.settings.discord_presence.discord_presence.show_images')">
<Switch
:model-value="!discordHideImage"
:disabled="!discordActive" :disabled="!discordActive"
@change=" @update:modelValue="
setDiscordHideImage(); setDiscordHideImage();
saveDiscordOption(); saveDiscordOption();
" /> " />
<simple-switch </SettingsItem>
:label="t('view.settings.discord_presence.discord_presence.display_world_name_as_discord_status')"
:value="discordWorldNameAsDiscordStatus" <SettingsItem
:label="
t('view.settings.discord_presence.discord_presence.display_world_name_as_discord_status')
">
<Switch
:model-value="discordWorldNameAsDiscordStatus"
:disabled="!discordActive" :disabled="!discordActive"
@change=" @update:modelValue="
setDiscordWorldNameAsDiscordStatus(); setDiscordWorldNameAsDiscordStatus();
saveDiscordOption(); saveDiscordOption();
" /> " />
</SettingsItem>
</SettingsGroup>
</div> </div>
</template> </template>
<script setup> <script setup>
import { Switch } from '@/components/ui/switch';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useAdvancedSettingsStore, useDiscordPresenceSettingsStore } from '../../../../stores'; import { useAdvancedSettingsStore, useDiscordPresenceSettingsStore } from '@/stores';
import SimpleSwitch from '../SimpleSwitch.vue'; import SettingsGroup from '../SettingsGroup.vue';
import SettingsItem from '../SettingsItem.vue';
const { t } = useI18n(); const { t } = useI18n();
+106 -100
View File
@@ -1,63 +1,59 @@
<template> <template>
<div> <div class="flex flex-col gap-10 py-2">
<div class="options-container mt-0"> <SettingsGroup :title="t('view.settings.general.general.header')">
<span class="header">{{ t('view.settings.general.general.header') }}</span> <div class="flex flex-col gap-0.5 px-1 py-1">
<div class="px-2.5 overflow-y-auto overflow-x-hidden mt-2"> <div class="flex-1">
<div class="box-border flex items-center p-1.5 text-[13px] cursor-default"> <span class="block truncate font-medium text-sm leading-[18px]">{{
<div class="flex-1 overflow-hidden">
<span class="block truncate font-medium leading-[18px]">{{
t('view.settings.general.general.version') t('view.settings.general.general.version')
}}</span> }}</span>
<span class="block truncate text-xs" v-text="appVersion"></span> <span class="block truncate text-xs text-muted-foreground" v-text="appVersion"></span>
</div> </div>
</div> </div>
<div class="box-border flex items-center p-1.5 text-[13px] cursor-pointer" @click="checkForVRCXUpdate">
<div class="flex-1 overflow-hidden"> <div class="flex flex-col gap-0.5 px-1 py-1 cursor-pointer" @click="checkForVRCXUpdate">
<span class="block truncate font-medium leading-[18px]">{{ <div class="flex-1">
<span class="block truncate font-medium text-sm leading-[18px]">{{
t('view.settings.general.general.latest_app_version') t('view.settings.general.general.latest_app_version')
}}</span> }}</span>
<span v-if="latestAppVersion" class="block truncate text-xs" v-text="latestAppVersion"></span> <span v-if="latestAppVersion" class="block truncate text-xs text-muted-foreground" v-text="latestAppVersion"></span>
<span v-else class="block truncate text-xs">{{ <span v-else class="block truncate text-xs text-muted-foreground">{{
t('view.settings.general.general.latest_app_version_refresh') t('view.settings.general.general.latest_app_version_refresh')
}}</span> }}</span>
</div> </div>
</div> </div>
<div
class="box-border flex items-center p-1.5 text-[13px] cursor-pointer" <div class="flex flex-col gap-0.5 px-1 py-1 cursor-pointer" @click="openExternalLink(links.github)">
@click="openExternalLink(links.github)"> <div class="flex-1">
<div class="flex-1 overflow-hidden"> <span class="block truncate font-medium text-sm leading-[18px]">{{
<span class="block truncate font-medium leading-[18px]">{{
t('view.settings.general.general.repository_url') t('view.settings.general.general.repository_url')
}}</span> }}</span>
<span v-once class="block truncate text-xs">{{ links.github }}</span> <span v-once class="block truncate text-xs text-muted-foreground">{{ links.github }}</span>
</div> </div>
</div> </div>
<div
class="box-border flex items-center p-1.5 text-[13px] cursor-pointer" <div class="flex flex-col gap-0.5 px-1 py-1 cursor-pointer" @click="openExternalLink(links.discord)">
@click="openExternalLink(links.discord)"> <div class="flex-1">
<div class="flex-1 overflow-hidden"> <span class="block truncate font-medium text-sm leading-[18px]">{{
<span class="block truncate font-medium leading-[18px]">{{
t('view.settings.general.general.support') t('view.settings.general.general.support')
}}</span> }}</span>
<span v-once class="block truncate text-xs">{{ links.discord }}</span> <span v-once class="block truncate text-xs text-muted-foreground">{{ links.discord }}</span>
</div> </div>
</div> </div>
</div> </SettingsGroup>
</div>
<div class="options-container"> <SettingsGroup :title="t('view.settings.general.vrcx_updater.header')">
<span class="header">{{ t('view.settings.general.vrcx_updater.header') }}</span> <div class="flex gap-2">
<div class="options-container-item"> <Button size="sm" variant="outline" @click="showChangeLogDialog">{{
<Button size="sm" variant="outline" class="mr-2" @click="showChangeLogDialog">{{
t('view.settings.general.vrcx_updater.change_log') t('view.settings.general.vrcx_updater.change_log')
}}</Button> }}</Button>
<Button size="sm" variant="outline" v-if="!noUpdater" @click="showVRCXUpdateDialog()">{{ <Button v-if="!noUpdater" size="sm" variant="outline" @click="showVRCXUpdateDialog()">{{
t('view.settings.general.vrcx_updater.change_build') t('view.settings.general.vrcx_updater.change_build')
}}</Button> }}</Button>
</div> </div>
<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> <template v-if="!noUpdater">
<SettingsItem :label="t('view.settings.general.vrcx_updater.update_action')">
<ToggleGroup <ToggleGroup
class="mt-1.5"
type="single" type="single"
required required
variant="outline" variant="outline"
@@ -74,65 +70,72 @@
t('view.settings.general.vrcx_updater.auto_update_download') t('view.settings.general.vrcx_updater.auto_update_download')
}}</ToggleGroupItem> }}</ToggleGroupItem>
</ToggleGroup> </ToggleGroup>
</SettingsItem>
</template>
<div v-else class="text-sm text-muted-foreground">
{{ t('view.settings.general.vrcx_updater.updater_disabled') }}
</div> </div>
<div v-else class="options-container-item"> </SettingsGroup>
<span>{{ t('view.settings.general.vrcx_updater.updater_disabled') }}</span>
</div> <SettingsGroup :title="t('view.settings.general.application.header')">
</div> <SettingsItem v-if="!isLinux" :label="t('view.settings.general.application.startup')">
<div class="options-container"> <Switch :model-value="isStartAtWindowsStartup" @update:modelValue="setIsStartAtWindowsStartup" />
<span class="header">{{ t('view.settings.general.application.header') }}</span> </SettingsItem>
<simple-switch
<SettingsItem
v-if="!isLinux" v-if="!isLinux"
:label="t('view.settings.general.application.startup')" :label="t('view.settings.general.application.minimized')">
:value="isStartAtWindowsStartup" <Switch :model-value="isStartAsMinimizedState" @update:modelValue="setIsStartAsMinimizedState" />
@change="setIsStartAtWindowsStartup" /> </SettingsItem>
<simple-switch <SettingsItem
v-if="!isLinux"
:label="t('view.settings.general.application.minimized')"
:value="isStartAsMinimizedState"
@change="setIsStartAsMinimizedState" />
<simple-switch
v-else v-else
:label="t('view.settings.general.application.minimized')" :label="t('view.settings.general.application.minimized')"
:value="isStartAsMinimizedState" :description="t('view.settings.general.application.startup_linux')">
:tooltip="t('view.settings.general.application.startup_linux')" <Switch :model-value="isStartAsMinimizedState" @update:modelValue="setIsStartAsMinimizedState" />
@change="setIsStartAsMinimizedState" /> </SettingsItem>
<simple-switch
v-if="!isMacOS" <SettingsItem v-if="!isMacOS" :label="t('view.settings.general.application.tray')">
:label="t('view.settings.general.application.tray')" <Switch :model-value="isCloseToTray" @update:modelValue="setIsCloseToTray" />
:value="isCloseToTray" </SettingsItem>
@change="setIsCloseToTray" />
<simple-switch <SettingsItem
v-if="!isLinux" v-if="!isLinux"
:label="t('view.settings.general.application.disable_gpu_acceleration')" :label="t('view.settings.general.application.disable_gpu_acceleration')"
:value="disableGpuAcceleration" :description="t('view.settings.general.application.disable_gpu_acceleration_tooltip')">
:tooltip="t('view.settings.general.application.disable_gpu_acceleration_tooltip')" <Switch :model-value="disableGpuAcceleration" @update:modelValue="setDisableGpuAcceleration" />
@change="setDisableGpuAcceleration" /> </SettingsItem>
<simple-switch
<SettingsItem
v-if="!isLinux" v-if="!isLinux"
:label="t('view.settings.general.application.disable_vr_overlay_gpu_acceleration')" :label="t('view.settings.general.application.disable_vr_overlay_gpu_acceleration')"
:value="disableVrOverlayGpuAcceleration" :description="t('view.settings.general.application.disable_gpu_acceleration_tooltip')">
:tooltip="t('view.settings.general.application.disable_gpu_acceleration_tooltip')" <Switch
@change="setDisableVrOverlayGpuAcceleration" /> :model-value="disableVrOverlayGpuAcceleration"
<div class="options-container-item"> @update:modelValue="setDisableVrOverlayGpuAcceleration" />
</SettingsItem>
<SettingsItem :label="t('view.settings.general.application.proxy')">
<Button size="sm" variant="outline" @click="promptProxySettings">{{ <Button size="sm" variant="outline" @click="promptProxySettings">{{
t('view.settings.general.application.proxy') t('view.settings.general.application.proxy')
}}</Button> }}</Button>
</div> </SettingsItem>
</div> </SettingsGroup>
<div class="options-container">
<span class="header inline-flex items-center" <SettingsGroup>
>{{ t('view.settings.general.favorites.header') }} <template #description>
<div class="flex items-center gap-1.5">
<span class="text-base font-semibold text-foreground">{{ t('view.settings.general.favorites.header') }}</span>
<TooltipWrapper side="top" :content="t('view.settings.general.favorites.header_tooltip')"> <TooltipWrapper side="top" :content="t('view.settings.general.favorites.header_tooltip')">
<Info class="ml-1" style="width: 12px; height: 12px; vertical-align: middle; cursor: help" /> <Info class="size-3 text-muted-foreground cursor-help" />
</TooltipWrapper> </TooltipWrapper>
</span> </div>
<br /> </template>
<Select <Select
:model-value="localFavoriteFriendsGroups" :model-value="localFavoriteFriendsGroups"
multiple multiple
@update:modelValue="setLocalFavoriteFriendsGroups"> @update:modelValue="setLocalFavoriteFriendsGroups">
<SelectTrigger class="mt-2"> <SelectTrigger>
<SelectValue :placeholder="t('view.settings.general.favorites.group_placeholder')" /> <SelectValue :placeholder="t('view.settings.general.favorites.group_placeholder')" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -154,37 +157,39 @@
</template> </template>
</SelectContent> </SelectContent>
</Select> </Select>
</div> </SettingsGroup>
<div class="options-container">
<span class="header">{{ t('view.settings.general.contributors.header') }}</span> <SettingsGroup :title="t('view.settings.general.contributors.header')">
<div class="options-container-item"> <div>
<img <img
src="https://contrib.rocks/image?repo=vrcx-team/VRCX" src="https://contrib.rocks/image?repo=vrcx-team/VRCX"
alt="Contributors" alt="Contributors"
style="cursor: pointer" class="cursor-pointer"
@click="openExternalLink('https://github.com/vrcx-team/VRCX/graphs/contributors')" /> @click="openExternalLink('https://github.com/vrcx-team/VRCX/graphs/contributors')" />
</div> </div>
</div> </SettingsGroup>
<div class="options-container border-t border-border" style="margin-top: 45px; padding-top: 30px">
<span class="header">{{ t('view.settings.general.legal_notice.header') }}</span> <SettingsGroup :title="t('view.settings.general.legal_notice.header')">
<div class="options-container-item" style="display: block"> <div class="flex flex-col gap-2 text-sm text-muted-foreground">
<p> <p class="m-0">
&copy; 2019-2026 &copy; 2019-2026
<a class="cursor-pointer" @click="openExternalLink('https://github.com/pypy-vrc')">pypy</a> &amp; <a class="cursor-pointer" @click="openExternalLink('https://github.com/pypy-vrc')">pypy</a> &amp;
<a class="cursor-pointer" @click="openExternalLink('https://github.com/Natsumi-sama')">Natsumi</a> <a class="cursor-pointer" @click="openExternalLink('https://github.com/Natsumi-sama')">Natsumi</a>
&amp; &amp;
<a class="cursor-pointer" @click="openExternalLink('https://github.com/Map1en')">Map1en</a> <a class="cursor-pointer" @click="openExternalLink('https://github.com/Map1en')">Map1en</a>
</p> </p>
<p>{{ t('view.settings.general.legal_notice.info') }}</p> <p class="m-0">{{ t('view.settings.general.legal_notice.info') }}</p>
<p>{{ t('view.settings.general.legal_notice.disclaimer1') }}</p> <p class="m-0">{{ t('view.settings.general.legal_notice.disclaimer1') }}</p>
<p>{{ t('view.settings.general.legal_notice.disclaimer2') }}</p> <p class="m-0">{{ t('view.settings.general.legal_notice.disclaimer2') }}</p>
</div> </div>
<div class="options-container-item">
<SettingsItem :label="t('view.settings.general.legal_notice.open_source_software_notice')">
<Button size="sm" variant="outline" @click="openOSSDialog">{{ <Button size="sm" variant="outline" @click="openOSSDialog">{{
t('view.settings.general.legal_notice.open_source_software_notice') t('view.settings.general.legal_notice.open_source_software_notice')
}}</Button> }}</Button>
</div> </SettingsItem>
</div> </SettingsGroup>
<OpenSourceSoftwareNoticeDialog v-if="ossDialog" v-model:ossDialog="ossDialog" /> <OpenSourceSoftwareNoticeDialog v-if="ossDialog" v-model:ossDialog="ossDialog" />
</div> </div>
</template> </template>
@@ -192,6 +197,7 @@
<script setup> <script setup>
import { computed, defineAsyncComponent, ref } from 'vue'; import { computed, defineAsyncComponent, ref } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Switch } from '@/components/ui/switch';
import { Info } from 'lucide-vue-next'; import { Info } from 'lucide-vue-next';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -204,14 +210,14 @@
SelectSeparator, SelectSeparator,
SelectTrigger, SelectTrigger,
SelectValue SelectValue
} from '../../../../components/ui/select'; } from '@/components/ui/select';
import { useFavoriteStore, useGeneralSettingsStore, useVRCXUpdaterStore } from '../../../../stores'; import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
import { ToggleGroup, ToggleGroupItem } from '../../../../components/ui/toggle-group'; import { useFavoriteStore, useGeneralSettingsStore, useVRCXUpdaterStore } from '@/stores';
import { links } from '../../../../shared/constants'; import { links } from '@/shared/constants';
import { openExternalLink } from '../../../../shared/utils'; import { openExternalLink } from '@/shared/utils';
import SimpleSwitch from '../SimpleSwitch.vue'; import SettingsGroup from '../SettingsGroup.vue';
import TooltipWrapper from '../../../../components/ui/tooltip/TooltipWrapper.vue'; import SettingsItem from '../SettingsItem.vue';
const { t } = useI18n(); const { t } = useI18n();
@@ -1,29 +1,23 @@
<template> <template>
<div> <div class="flex flex-col gap-10 py-2">
<div class="options-container mt-0"> <SettingsGroup :title="t('view.settings.notifications.notifications.header')">
<span class="header">{{ t('view.settings.notifications.notifications.header') }}</span> <SettingsItem :label="t('view.settings.notifications.notifications.notification_filter')">
<div class="options-container-item">
<Button size="sm" variant="outline" @click="showNotyFeedFiltersDialog">{{ <Button size="sm" variant="outline" @click="showNotyFeedFiltersDialog">{{
t('view.settings.notifications.notifications.notification_filter') t('view.settings.notifications.notifications.notification_filter')
}}</Button> }}</Button>
</div> </SettingsItem>
<div class="options-container-item">
<SettingsItem :label="t('view.settings.notifications.notifications.test_notification')">
<Button size="sm" variant="outline" @click="testNotification" <Button size="sm" variant="outline" @click="testNotification"
><Play />{{ t('view.settings.notifications.notifications.test_notification') }}</Button ><Play />{{ t('view.settings.notifications.notifications.test_notification') }}</Button
> >
</div> </SettingsItem>
</div> </SettingsGroup>
<div class="options-container">
<span class="sub-header">{{ <SettingsGroup :title="t('view.settings.notifications.notifications.steamvr_notifications.header')">
t('view.settings.notifications.notifications.steamvr_notifications.header') <SettingsItem
}}</span> :label="t('view.settings.notifications.notifications.desktop_notifications.when_to_display')">
<div class="options-container-item">
<span class="name">{{
t('view.settings.notifications.notifications.desktop_notifications.when_to_display')
}}</span>
<br />
<ToggleGroup <ToggleGroup
class="mt-1.5"
type="single" type="single"
required required
variant="outline" variant="outline"
@@ -52,24 +46,36 @@
t('view.settings.notifications.notifications.conditions.always') t('view.settings.notifications.notifications.conditions.always')
}}</ToggleGroupItem> }}</ToggleGroupItem>
</ToggleGroup> </ToggleGroup>
</div> </SettingsItem>
<simple-switch
:label="t('view.settings.notifications.notifications.steamvr_notifications.steamvr_overlay')" <SettingsItem
:value="openVR" :label="t('view.settings.notifications.notifications.steamvr_notifications.steamvr_overlay')">
@change=" <Switch
:model-value="openVR"
@update:modelValue="
setOpenVR(); setOpenVR();
saveOpenVROption(); saveOpenVROption();
" /> " />
</SettingsItem>
<template v-if="openVR"> <template v-if="openVR">
<simple-switch <SettingsItem
:label="t('view.settings.notifications.notifications.steamvr_notifications.overlay_notifications')" :label="
:value="overlayNotifications" t('view.settings.notifications.notifications.steamvr_notifications.overlay_notifications')
">
<Switch
:model-value="overlayNotifications"
:disabled="!openVR" :disabled="!openVR"
@change=" @update:modelValue="
setOverlayNotifications(); setOverlayNotifications();
saveOpenVROption(); saveOpenVROption();
" /> " />
<div class="options-container-item"> </SettingsItem>
<SettingsItem
:label="
t('view.settings.notifications.notifications.steamvr_notifications.notification_position')
">
<Button <Button
size="sm" size="sm"
variant="outline" variant="outline"
@@ -79,17 +85,22 @@
t('view.settings.notifications.notifications.steamvr_notifications.notification_position') t('view.settings.notifications.notifications.steamvr_notifications.notification_position')
}}</Button }}</Button
> >
</div> </SettingsItem>
</template> </template>
<div class="options-container-item">
<span class="name" style="vertical-align: top; padding-top: 8px">{{ <SettingsItem
:label="
t('view.settings.notifications.notifications.steamvr_notifications.notification_opacity') t('view.settings.notifications.notifications.steamvr_notifications.notification_opacity')
}}</span> ">
<div style="flex: 0 0 300px; width: 300px; max-width: 100%; padding-top: 16px"> <div class="w-75 max-w-full pt-1">
<Slider v-model="notificationOpacityValue" :min="0" :max="100" /> <Slider v-model="notificationOpacityValue" :min="0" :max="100" />
</div> </div>
</div> </SettingsItem>
<div class="options-container-item">
<SettingsItem
:label="
t('view.settings.notifications.notifications.steamvr_notifications.notification_timeout')
">
<Button <Button
size="sm" size="sm"
variant="outline" variant="outline"
@@ -99,75 +110,85 @@
t('view.settings.notifications.notifications.steamvr_notifications.notification_timeout') t('view.settings.notifications.notifications.steamvr_notifications.notification_timeout')
}}</Button }}</Button
> >
</div> </SettingsItem>
<simple-switch
:label="t('view.settings.notifications.notifications.steamvr_notifications.user_images')" <SettingsItem
:value="imageNotifications" :label="t('view.settings.notifications.notifications.steamvr_notifications.user_images')">
@change=" <Switch
:model-value="imageNotifications"
@update:modelValue="
setImageNotifications(); setImageNotifications();
saveOpenVROption(); saveOpenVROption();
" /> " />
</SettingsItem>
<template v-if="!isLinux"> <template v-if="!isLinux">
<simple-switch <SettingsItem
:label=" :label="
t('view.settings.notifications.notifications.steamvr_notifications.xsoverlay_notifications') t('view.settings.notifications.notifications.steamvr_notifications.xsoverlay_notifications')
" ">
:value="xsNotifications" <Switch
@change=" :model-value="xsNotifications"
@update:modelValue="
setXsNotifications(); setXsNotifications();
saveOpenVROption(); saveOpenVROption();
" /> " />
</SettingsItem>
</template> </template>
<template v-else> <template v-else>
<simple-switch <SettingsItem
:label="t('view.settings.notifications.notifications.steamvr_notifications.wayvr_notifications')" :label="
:value="xsNotifications" t('view.settings.notifications.notifications.steamvr_notifications.wayvr_notifications')
@change=" ">
<Switch
:model-value="xsNotifications"
@update:modelValue="
setXsNotifications(); setXsNotifications();
saveOpenVROption(); saveOpenVROption();
" /> " />
</SettingsItem>
</template> </template>
<template v-if="!isLinux"> <template v-if="!isLinux">
<simple-switch <SettingsItem
:label=" :label="
t( t(
'view.settings.notifications.notifications.steamvr_notifications.ovrtoolkit_hud_notifications' 'view.settings.notifications.notifications.steamvr_notifications.ovrtoolkit_hud_notifications'
) )
" ">
:value="ovrtHudNotifications" <Switch
@change=" :model-value="ovrtHudNotifications"
@update:modelValue="
setOvrtHudNotifications(); setOvrtHudNotifications();
saveOpenVROption(); saveOpenVROption();
" /> " />
<simple-switch </SettingsItem>
<SettingsItem
:label=" :label="
t( t(
'view.settings.notifications.notifications.steamvr_notifications.ovrtoolkit_wrist_notifications' 'view.settings.notifications.notifications.steamvr_notifications.ovrtoolkit_wrist_notifications'
) )
" ">
:value="ovrtWristNotifications" <Switch
@change=" :model-value="ovrtWristNotifications"
@update:modelValue="
setOvrtWristNotifications(); setOvrtWristNotifications();
saveOpenVROption(); saveOpenVROption();
" /> " />
</SettingsItem>
</template> </template>
</div> </SettingsGroup>
<div class="options-container">
<span class="sub-header">{{ <SettingsGroup :title="t('view.settings.notifications.notifications.desktop_notifications.header')">
t('view.settings.notifications.notifications.desktop_notifications.header') <SettingsItem
}}</span> :label="t('view.settings.notifications.notifications.desktop_notifications.when_to_display')">
<div class="options-container-item">
<span class="name">{{
t('view.settings.notifications.notifications.desktop_notifications.when_to_display')
}}</span>
<br />
<ToggleGroup <ToggleGroup
type="single" type="single"
required required
variant="outline" variant="outline"
size="sm" size="sm"
:model-value="desktopToast" :model-value="desktopToast"
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')
@@ -191,28 +212,25 @@
t('view.settings.notifications.notifications.conditions.always') t('view.settings.notifications.notifications.conditions.always')
}}</ToggleGroupItem> }}</ToggleGroupItem>
</ToggleGroup> </ToggleGroup>
</div> </SettingsItem>
<simple-switch
<SettingsItem
:label=" :label="
t('view.settings.notifications.notifications.desktop_notifications.desktop_notification_while_afk') t('view.settings.notifications.notifications.desktop_notifications.desktop_notification_while_afk')
" ">
:value="afkDesktopToast" <Switch :model-value="afkDesktopToast" @update:modelValue="setAfkDesktopToast" />
@change="setAfkDesktopToast" /> </SettingsItem>
</div> </SettingsGroup>
<div class="options-container">
<span class="sub-header">{{ t('view.settings.notifications.notifications.text_to_speech.header') }}</span> <SettingsGroup :title="t('view.settings.notifications.notifications.text_to_speech.header')">
<div class="options-container-item"> <SettingsItem
<span class="name">{{ :label="t('view.settings.notifications.notifications.text_to_speech.when_to_play')">
t('view.settings.notifications.notifications.text_to_speech.when_to_play')
}}</span>
<br />
<ToggleGroup <ToggleGroup
type="single" type="single"
required required
variant="outline" variant="outline"
size="sm" size="sm"
:model-value="notificationTTS" :model-value="notificationTTS"
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')
@@ -230,9 +248,9 @@
t('view.settings.notifications.notifications.conditions.always') t('view.settings.notifications.notifications.conditions.always')
}}</ToggleGroupItem> }}</ToggleGroupItem>
</ToggleGroup> </ToggleGroup>
</div> </SettingsItem>
<div class="options-container-item">
<span class="name">{{ t('view.settings.notifications.notifications.text_to_speech.tts_voice') }}</span> <SettingsItem :label="t('view.settings.notifications.notifications.text_to_speech.tts_voice')">
<Select <Select
:model-value="ttsVoiceIndex" :model-value="ttsVoiceIndex"
:disabled="notificationTTS === 'Never'" :disabled="notificationTTS === 'Never'"
@@ -248,28 +266,34 @@
</SelectGroup> </SelectGroup>
</SelectContent> </SelectContent>
</Select> </Select>
</div> </SettingsItem>
<simple-switch
:label="t('view.settings.notifications.notifications.text_to_speech.use_memo_nicknames')" <SettingsItem
:value="notificationTTSNickName" :label="t('view.settings.notifications.notifications.text_to_speech.use_memo_nicknames')">
<Switch
:model-value="notificationTTSNickName"
:disabled="notificationTTS === 'Never'" :disabled="notificationTTS === 'Never'"
@change="setNotificationTTSNickName" /> @update:modelValue="setNotificationTTSNickName" />
<simple-switch </SettingsItem>
:label="t('view.settings.notifications.notifications.text_to_speech.tts_test_placeholder')"
:value="isTestTTSVisible" <SettingsItem
@change="isTestTTSVisible = !isTestTTSVisible" /> :label="t('view.settings.notifications.notifications.text_to_speech.tts_test_placeholder')">
<div v-if="isTestTTSVisible" style="margin-top: 6px"> <Switch :model-value="isTestTTSVisible" @update:modelValue="isTestTTSVisible = !isTestTTSVisible" />
</SettingsItem>
<div v-if="isTestTTSVisible" class="flex items-center gap-2 mt-1">
<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')"
:rows="1" :rows="1"
style="width: 175px; display: inline-block" class="w-44"
input-class="resize-none min-h-0" /> input-class="resize-none min-h-0" />
<Button size="sm" variant="outline" @click="testNotificationTTS">{{ <Button size="sm" variant="outline" @click="testNotificationTTS">{{
t('view.settings.notifications.notifications.text_to_speech.play') t('view.settings.notifications.notifications.text_to_speech.play')
}}</Button> }}</Button>
</div> </div>
</div> </SettingsGroup>
<NotificationPositionDialog v-model:isNotificationPositionDialogVisible="isNotificationPositionDialogVisible" /> <NotificationPositionDialog v-model:isNotificationPositionDialogVisible="isNotificationPositionDialogVisible" />
<FeedFiltersDialog v-model:feedFiltersDialogMode="feedFiltersDialogMode" /> <FeedFiltersDialog v-model:feedFiltersDialogMode="feedFiltersDialogMode" />
</div> </div>
@@ -277,6 +301,9 @@
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
import { Switch } from '@/components/ui/switch';
import { Slider } from '@/components/ui/slider';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
@@ -289,13 +316,12 @@
useNotificationStore, useNotificationStore,
useNotificationsSettingsStore, useNotificationsSettingsStore,
useVrStore useVrStore
} from '../../../../stores'; } from '@/stores';
import { ToggleGroup, ToggleGroupItem } from '../../../../components/ui/toggle-group';
import { Slider } from '../../../../components/ui/slider';
import FeedFiltersDialog from '../../dialogs/FeedFiltersDialog.vue'; import FeedFiltersDialog from '../../dialogs/FeedFiltersDialog.vue';
import NotificationPositionDialog from '../../dialogs/NotificationPositionDialog.vue'; import NotificationPositionDialog from '../../dialogs/NotificationPositionDialog.vue';
import SimpleSwitch from '../SimpleSwitch.vue'; import SettingsGroup from '../SettingsGroup.vue';
import SettingsItem from '../SettingsItem.vue';
const { t } = useI18n(); const { t } = useI18n();
@@ -1,117 +1,110 @@
<template> <template>
<!--//- Pictures | Screenshot Helper--> <!--//- Pictures | Screenshot Helper-->
<div class="options-container mt-0"> <div class="flex flex-col gap-10 py-2">
<span class="header">{{ t('view.settings.advanced.advanced.screenshot_helper.header') }}</span> <SettingsGroup :title="t('view.settings.advanced.advanced.screenshot_helper.header')">
<div class="options-container-item"> <template #description>
<span class="name">{{ t('view.settings.advanced.advanced.screenshot_helper.description') }}</span> {{ t('view.settings.advanced.advanced.screenshot_helper.description') }}
</div> </template>
<simple-switch
<SettingsItem
:label="t('view.settings.advanced.advanced.screenshot_helper.enable')" :label="t('view.settings.advanced.advanced.screenshot_helper.enable')"
:value="screenshotHelper" :description="t('view.settings.advanced.advanced.screenshot_helper.description_tooltip')">
@change="setScreenshotHelper()" <Switch :model-value="screenshotHelper" @update:modelValue="setScreenshotHelper()" />
:tooltip="t('view.settings.advanced.advanced.screenshot_helper.description_tooltip')" </SettingsItem>
:long-label="true" />
<simple-switch <SettingsItem
:label="t('view.settings.advanced.advanced.screenshot_helper.modify_filename')" :label="t('view.settings.advanced.advanced.screenshot_helper.modify_filename')"
:value="screenshotHelperModifyFilename" :description="t('view.settings.advanced.advanced.screenshot_helper.modify_filename_tooltip')">
@change="setScreenshotHelperModifyFilename()" <Switch
:model-value="screenshotHelperModifyFilename"
:disabled="!screenshotHelper" :disabled="!screenshotHelper"
:tooltip="t('view.settings.advanced.advanced.screenshot_helper.modify_filename_tooltip')" @update:modelValue="setScreenshotHelperModifyFilename()" />
:long-label="true" /> </SettingsItem>
<simple-switch
:label="t('view.settings.advanced.advanced.screenshot_helper.copy_to_clipboard')" <SettingsItem :label="t('view.settings.advanced.advanced.screenshot_helper.copy_to_clipboard')">
:value="screenshotHelperCopyToClipboard" <Switch
@change="setScreenshotHelperCopyToClipboard()" :model-value="screenshotHelperCopyToClipboard"
:long-label="true" /> @update:modelValue="setScreenshotHelperCopyToClipboard()" />
<Button size="sm" variant="outline" class="mt-2" @click="askDeleteAllScreenshotMetadata()">{{ </SettingsItem>
<SettingsItem :label="t('view.settings.advanced.advanced.delete_all_screenshot_metadata.button')">
<Button size="sm" variant="outline" @click="askDeleteAllScreenshotMetadata()">{{
t('view.settings.advanced.advanced.delete_all_screenshot_metadata.button') t('view.settings.advanced.advanced.delete_all_screenshot_metadata.button')
}}</Button> }}</Button>
</div> </SettingsItem>
</SettingsGroup>
<div class="options-container"> <SettingsGroup :title="t('view.settings.pictures.pictures.auto_delete_old_prints')">
<span class="header">{{ t('view.settings.pictures.pictures.auto_delete_old_prints') }}</span> <SettingsItem :label="t('view.settings.pictures.pictures.auto_delete_prints_from_vrc')">
<simple-switch <Switch :model-value="autoDeleteOldPrints" @update:modelValue="setAutoDeleteOldPrints()" />
:label="t('view.settings.pictures.pictures.auto_delete_prints_from_vrc')" </SettingsItem>
:value="autoDeleteOldPrints" </SettingsGroup>
@change="setAutoDeleteOldPrints()"
:long-label="true" />
</div>
<!-- //- Pictures | User Generated Content --> <!-- //- Pictures | User Generated Content -->
<div class="options-container"> <SettingsGroup :title="t('view.settings.advanced.advanced.user_generated_content.header')">
<span class="header">{{ t('view.settings.advanced.advanced.user_generated_content.header') }}</span> <template #description>
<br /> {{ t('view.settings.advanced.advanced.user_generated_content.description') }}
<div class="options-container-item mb-1.5"> </template>
<span class="name" style="min-width: 300px">{{
t('view.settings.advanced.advanced.user_generated_content.description') <div class="flex gap-2">
}}</span>
</div>
<div class="flex gap-2 mt-2">
<Button size="sm" variant="outline" @click="openUGCFolder()">{{ <Button size="sm" variant="outline" @click="openUGCFolder()">{{
t('view.settings.advanced.advanced.user_generated_content.folder') t('view.settings.advanced.advanced.user_generated_content.folder')
}}</Button> }}</Button>
<Button size="sm" variant="outline" @click="openUGCFolderSelector()">{{ <Button size="sm" variant="outline" @click="openUGCFolderSelector()">{{
t('view.settings.advanced.advanced.user_generated_content.set_folder') t('view.settings.advanced.advanced.user_generated_content.set_folder')
}}</Button> }}</Button>
<Button size="sm" variant="outline" @click="resetUGCFolder()" v-if="ugcFolderPath">{{ <Button v-if="ugcFolderPath" size="sm" variant="outline" @click="resetUGCFolder()">{{
t('view.settings.advanced.advanced.user_generated_content.reset_override') t('view.settings.advanced.advanced.user_generated_content.reset_override')
}}</Button> }}</Button>
</div> </div>
</SettingsGroup>
<br /> <SettingsGroup :title="t('view.settings.advanced.advanced.save_instance_prints_to_file.header')">
<br /> <template #description>
<br /> {{ t('view.settings.advanced.advanced.save_instance_prints_to_file.header_tooltip') }}
<span class="sub-header mr-1.5">{{ </template>
t('view.settings.advanced.advanced.save_instance_prints_to_file.header')
}}</span> <SettingsItem
<TooltipWrapper :label="t('view.settings.advanced.advanced.save_instance_prints_to_file.description')">
side="top" <Switch :model-value="saveInstancePrints" @update:modelValue="setSaveInstancePrints()" />
:content="t('view.settings.advanced.advanced.save_instance_prints_to_file.header_tooltip')"> </SettingsItem>
<Info class="inline-block" />
</TooltipWrapper> <SettingsItem :label="t('view.settings.advanced.advanced.save_instance_prints_to_file.crop')">
<simple-switch <Switch :model-value="cropInstancePrints" @update:modelValue="setCropInstancePrints()" />
:label="t('view.settings.advanced.advanced.save_instance_prints_to_file.description')" </SettingsItem>
:value="saveInstancePrints" </SettingsGroup>
@change="setSaveInstancePrints()"
:long-label="true" /> <SettingsGroup
<simple-switch :title="t('view.settings.advanced.advanced.save_instance_stickers_to_file.header')">
:label="t('view.settings.advanced.advanced.save_instance_prints_to_file.crop')" <SettingsItem
:value="cropInstancePrints" :label="t('view.settings.advanced.advanced.save_instance_stickers_to_file.description')">
@change="setCropInstancePrints()" <Switch :model-value="saveInstanceStickers" @update:modelValue="setSaveInstanceStickers()" />
:long-label="true" /> </SettingsItem>
<br /> </SettingsGroup>
<span class="sub-header">{{ t('view.settings.advanced.advanced.save_instance_stickers_to_file.header') }}</span>
<simple-switch <SettingsGroup :title="t('view.settings.advanced.advanced.save_instance_emoji_to_file.header')">
:label="t('view.settings.advanced.advanced.save_instance_stickers_to_file.description')" <template #description>
:value="saveInstanceStickers" {{ t('view.settings.advanced.advanced.save_instance_prints_to_file.header_tooltip') }}
@change="setSaveInstanceStickers()" </template>
:long-label="true" />
<br /> <SettingsItem
<span class="sub-header mr-1.5" :label="t('view.settings.advanced.advanced.save_instance_emoji_to_file.description')">
>{{ t('view.settings.advanced.advanced.save_instance_emoji_to_file.header') }} <Switch :model-value="saveInstanceEmoji" @update:modelValue="setSaveInstanceEmoji()" />
</span> </SettingsItem>
<TooltipWrapper </SettingsGroup>
side="top"
:content="t('view.settings.advanced.advanced.save_instance_prints_to_file.header_tooltip')">
<Info class="inline-block" />
</TooltipWrapper>
<simple-switch
:label="t('view.settings.advanced.advanced.save_instance_emoji_to_file.description')"
:value="saveInstanceEmoji"
@change="setSaveInstanceEmoji()"
:long-label="true" />
</div> </div>
</template> </template>
<script setup> <script setup>
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Info } from 'lucide-vue-next'; import { Switch } from '@/components/ui/switch';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useAdvancedSettingsStore } from '../../../../stores'; import { useAdvancedSettingsStore } from '@/stores';
import SimpleSwitch from '../SimpleSwitch.vue'; import SettingsGroup from '../SettingsGroup.vue';
import SettingsItem from '../SettingsItem.vue';
const { t } = useI18n(); const { t } = useI18n();
@@ -1,7 +1,13 @@
<template> <template>
<div class="options-container mt-0"> <div class="flex flex-col gap-10 py-2">
<span class="header">{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.header') }}</span> <SettingsGroup :title="t('view.settings.wrist_overlay.steamvr_wrist_overlay.header')">
<div class="options-container-item"> <template #description>
<p class="m-0">{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.description') }}</p>
<p class="m-0">{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.grip') }}</p>
<p class="m-0">{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.menu') }}</p>
</template>
<SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.wrist_feed_filters')">
<Button <Button
size="sm" size="sm"
variant="outline" variant="outline"
@@ -9,44 +15,43 @@
@click="emit('open-feed-filters')" @click="emit('open-feed-filters')"
>{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.wrist_feed_filters') }}</Button >{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.wrist_feed_filters') }}</Button
> >
</div> </SettingsItem>
<div class="options-container-item">
<span>{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.description') }}</span> <SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.steamvr_overlay')">
</div> <Switch
<div class="options-container-item"> :model-value="openVR"
<span>{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.grip') }}</span> @update:modelValue="
</div>
<div class="options-container-item">
<span>{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.menu') }}</span>
</div>
<simple-switch
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.steamvr_overlay')"
:value="openVR"
@change="
setOpenVR(); setOpenVR();
saveOpenVROption(); saveOpenVROption();
" /> " />
<simple-switch </SettingsItem>
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.wrist_feed_overlay')"
:value="overlayWrist" <SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.wrist_feed_overlay')">
<Switch
:model-value="overlayWrist"
:disabled="!openVR" :disabled="!openVR"
@change=" @update:modelValue="
setOverlayWrist(); setOverlayWrist();
saveOpenVROption(); saveOpenVROption();
"></simple-switch> " />
<simple-switch </SettingsItem>
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.hide_private_worlds')"
:value="hidePrivateFromFeed" <SettingsItem
@change=" :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.hide_private_worlds')">
<Switch
:model-value="hidePrivateFromFeed"
@update:modelValue="
setHidePrivateFromFeed(); setHidePrivateFromFeed();
saveOpenVROption(); saveOpenVROption();
" /> " />
<div class="options-container-item" style="min-width: 118px"> </SettingsItem>
<span class="name">{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.start_overlay_with') }}</span>
<SettingsItem
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.start_overlay_with')">
<RadioGroup <RadioGroup
:model-value="openVRAlways ? 'true' : 'false'" :model-value="openVRAlways ? 'true' : 'false'"
:disabled="!openVR" :disabled="!openVR"
class="gap-2 flex mt-2" class="gap-2 flex"
@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" />
@@ -57,13 +62,13 @@
<label for="openVRAlways-true">{{ 'SteamVR' }}</label> <label for="openVRAlways-true">{{ 'SteamVR' }}</label>
</div> </div>
</RadioGroup> </RadioGroup>
</div> </SettingsItem>
<div class="options-container-item">
<span class="name">{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.overlay_button') }}</span> <SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.overlay_button')">
<RadioGroup <RadioGroup
:model-value="overlaybutton ? 'true' : 'false'" :model-value="overlaybutton ? 'true' : 'false'"
:disabled="!openVR || !overlayWrist" :disabled="!openVR || !overlayWrist"
class="gap-2 flex mt-2" class="gap-2 flex"
@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" />
@@ -78,9 +83,10 @@
}}</label> }}</label>
</div> </div>
</RadioGroup> </RadioGroup>
</div> </SettingsItem>
<div class="options-container-item">
<span class="name">{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on') }}</span> <SettingsItem
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on')">
<ToggleGroup <ToggleGroup
type="single" type="single"
required required
@@ -101,68 +107,86 @@
t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_both') t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_both')
}}</ToggleGroupItem> }}</ToggleGroupItem>
</ToggleGroup> </ToggleGroup>
</div> </SettingsItem>
<simple-switch
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.grey_background')" <SettingsItem
:value="vrBackgroundEnabled" :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.grey_background')">
<Switch
:model-value="vrBackgroundEnabled"
:disabled="!openVR || !overlayWrist" :disabled="!openVR || !overlayWrist"
@change=" @update:modelValue="
setVrBackgroundEnabled(); setVrBackgroundEnabled();
saveOpenVROption(); saveOpenVROption();
" /> " />
<simple-switch </SettingsItem>
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.minimal_feed_icons')"
:value="minimalFeed" <SettingsItem
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.minimal_feed_icons')">
<Switch
:model-value="minimalFeed"
:disabled="!openVR || !overlayWrist" :disabled="!openVR || !overlayWrist"
@change=" @update:modelValue="
setMinimalFeed(); setMinimalFeed();
saveOpenVROption(); saveOpenVROption();
" /> " />
<simple-switch </SettingsItem>
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.show_vr_devices')"
:value="!hideDevicesFromFeed" <SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.show_vr_devices')">
<Switch
:model-value="!hideDevicesFromFeed"
:disabled="!openVR || !overlayWrist" :disabled="!openVR || !overlayWrist"
@change=" @update:modelValue="
setHideDevicesFromFeed(); setHideDevicesFromFeed();
saveOpenVROption(); saveOpenVROption();
" /> " />
<simple-switch </SettingsItem>
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.show_cpu_usage')"
:value="vrOverlayCpuUsage" <SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.show_cpu_usage')">
<Switch
:model-value="vrOverlayCpuUsage"
:disabled="!openVR || !overlayWrist" :disabled="!openVR || !overlayWrist"
@change=" @update:modelValue="
setVrOverlayCpuUsage(); setVrOverlayCpuUsage();
saveOpenVROption(); saveOpenVROption();
" /> " />
<simple-switch </SettingsItem>
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.show_game_uptime')"
:value="!hideUptimeFromFeed" <SettingsItem
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.show_game_uptime')">
<Switch
:model-value="!hideUptimeFromFeed"
:disabled="!openVR || !overlayWrist" :disabled="!openVR || !overlayWrist"
@change=" @update:modelValue="
setHideUptimeFromFeed(); setHideUptimeFromFeed();
saveOpenVROption(); saveOpenVROption();
" /> " />
<simple-switch </SettingsItem>
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.show_pc_uptime')"
:value="pcUptimeOnFeed" <SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.show_pc_uptime')">
<Switch
:model-value="pcUptimeOnFeed"
:disabled="!openVR || !overlayWrist" :disabled="!openVR || !overlayWrist"
@change=" @update:modelValue="
setPcUptimeOnFeed(); setPcUptimeOnFeed();
saveOpenVROption(); saveOpenVROption();
"></simple-switch> " />
</SettingsItem>
</SettingsGroup>
</div> </div>
</template> </template>
<script setup> <script setup>
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Switch } from '@/components/ui/switch';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useNotificationsSettingsStore, useVrStore, useWristOverlaySettingsStore } from '../../../stores'; import { useNotificationsSettingsStore, useVrStore, useWristOverlaySettingsStore } from '@/stores';
import { RadioGroup, RadioGroupItem } from '../../../components/ui/radio-group';
import { ToggleGroup, ToggleGroupItem } from '../../../components/ui/toggle-group';
import SimpleSwitch from './SimpleSwitch.vue'; import SettingsGroup from './SettingsGroup.vue';
import SettingsItem from './SettingsItem.vue';
const emit = defineEmits(['open-feed-filters']); const emit = defineEmits(['open-feed-filters']);
const { t } = useI18n(); const { t } = useI18n();