feat: add vue-router

This commit is contained in:
pa
2025-10-16 00:00:48 +09:00
committed by Natsumi
parent 9cba3dbce8
commit df04f1d449
24 changed files with 175 additions and 136 deletions

25
package-lock.json generated
View File

@@ -48,6 +48,7 @@
"vue": "^3.5.22", "vue": "^3.5.22",
"vue-i18n": "^11.1.12", "vue-i18n": "^11.1.12",
"vue-marquee-text-component": "^2.0.1", "vue-marquee-text-component": "^2.0.1",
"vue-router": "^4.6.0",
"vue-showdown": "^4.2.0", "vue-showdown": "^4.2.0",
"worker-timers": "^8.0.25", "worker-timers": "^8.0.25",
"yargs": "^18.0.0" "yargs": "^18.0.0"
@@ -8241,6 +8242,7 @@
"integrity": "sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==", "integrity": "sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"app-builder-lib": "26.0.12", "app-builder-lib": "26.0.12",
"builder-util": "26.0.11", "builder-util": "26.0.11",
@@ -18167,6 +18169,29 @@
"url": "https://opencollective.com/core-js" "url": "https://opencollective.com/core-js"
} }
}, },
"node_modules/vue-router": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.0.tgz",
"integrity": "sha512-YRrWLi4ayHe1d6zyH6sMPwF/WwcDY8XgUOfQGa0Kx4kmugSorLavD1ExrM/Y83B4X2NQMXYpJFSq2pbZh9ildQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vue/devtools-api": "^6.6.4"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"vue": "^3.5.0"
}
},
"node_modules/vue-router/node_modules/@vue/devtools-api": {
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
"dev": true,
"license": "MIT"
},
"node_modules/vue-showdown": { "node_modules/vue-showdown": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/vue-showdown/-/vue-showdown-4.2.0.tgz", "resolved": "https://registry.npmjs.org/vue-showdown/-/vue-showdown-4.2.0.tgz",

View File

@@ -69,6 +69,7 @@
"vue": "^3.5.22", "vue": "^3.5.22",
"vue-i18n": "^11.1.12", "vue-i18n": "^11.1.12",
"vue-marquee-text-component": "^2.0.1", "vue-marquee-text-component": "^2.0.1",
"vue-router": "^4.6.0",
"vue-showdown": "^4.2.0", "vue-showdown": "^4.2.0",
"worker-timers": "^8.0.25", "worker-timers": "^8.0.25",
"yargs": "^18.0.0" "yargs": "^18.0.0"

View File

@@ -1,5 +1,4 @@
<template> <template>
<!DOCTYPE html>
<el-config-provider :locale="currentLocale"> <el-config-provider :locale="currentLocale">
<MacOSTitleBar></MacOSTitleBar> <MacOSTitleBar></MacOSTitleBar>
@@ -18,29 +17,11 @@
<template v-if="watchState.isLoggedIn"> <template v-if="watchState.isLoggedIn">
<NavMenu></NavMenu> <NavMenu></NavMenu>
<el-splitter @resize-end="setAsideWidth" v-show="isSideBarTabShow"> <RouterView v-if="requiresFullScreen"></RouterView>
<el-splitter v-else @resize-end="setAsideWidth" v-show="isSideBarTabShow">
<el-splitter-panel> <el-splitter-panel>
<Feed></Feed> <RouterView></RouterView>
<GameLog></GameLog>
<PlayerList></PlayerList>
<Search></Search>
<Favorites></Favorites>
<FriendLog></FriendLog>
<Moderation></Moderation>
<Notification></Notification>
<Tools></Tools>
<Profile></Profile>
<Settings></Settings>
</el-splitter-panel> </el-splitter-panel>
<el-splitter-panel :min="200" :max="700" :size="asideWidth"> <el-splitter-panel :min="200" :max="700" :size="asideWidth">
@@ -48,10 +29,6 @@
</el-splitter-panel> </el-splitter-panel>
</el-splitter> </el-splitter>
<FriendList></FriendList>
<Charts></Charts>
<!-- ## Dialogs ## --> <!-- ## Dialogs ## -->
<UserDialog></UserDialog> <UserDialog></UserDialog>
@@ -95,6 +72,7 @@
import { computed, onBeforeMount, onMounted } from 'vue'; import { computed, onBeforeMount, onMounted } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import cs from 'element-plus/es/locale/lang/cs'; import cs from 'element-plus/es/locale/lang/cs';
import en from 'element-plus/es/locale/lang/en'; import en from 'element-plus/es/locale/lang/en';
@@ -117,16 +95,10 @@
import AvatarDialog from './components/dialogs/AvatarDialog/AvatarDialog.vue'; import AvatarDialog from './components/dialogs/AvatarDialog/AvatarDialog.vue';
import AvatarImportDialog from './views/Favorites/dialogs/AvatarImportDialog.vue'; import AvatarImportDialog from './views/Favorites/dialogs/AvatarImportDialog.vue';
import Charts from './views/Charts/Charts.vue';
import ChooseFavoriteGroupDialog from './components/dialogs/ChooseFavoriteGroupDialog.vue'; import ChooseFavoriteGroupDialog from './components/dialogs/ChooseFavoriteGroupDialog.vue';
import EditInviteMessageDialog from './views/Profile/dialogs/EditInviteMessageDialog.vue'; import EditInviteMessageDialog from './views/Profile/dialogs/EditInviteMessageDialog.vue';
import Favorites from './views/Favorites/Favorites.vue';
import Feed from './views/Feed/Feed.vue';
import FriendImportDialog from './views/Favorites/dialogs/FriendImportDialog.vue'; import FriendImportDialog from './views/Favorites/dialogs/FriendImportDialog.vue';
import FriendList from './views/FriendList/FriendList.vue';
import FriendLog from './views/FriendLog/FriendLog.vue';
import FullscreenImagePreview from './components/FullscreenImagePreview.vue'; import FullscreenImagePreview from './components/FullscreenImagePreview.vue';
import GameLog from './views/GameLog/GameLog.vue';
import GroupDialog from './components/dialogs/GroupDialog/GroupDialog.vue'; import GroupDialog from './components/dialogs/GroupDialog/GroupDialog.vue';
import GroupMemberModerationDialog from './components/dialogs/GroupDialog/GroupMemberModerationDialog.vue'; import GroupMemberModerationDialog from './components/dialogs/GroupDialog/GroupMemberModerationDialog.vue';
import InviteGroupDialog from './components/dialogs/InviteGroupDialog.vue'; import InviteGroupDialog from './components/dialogs/InviteGroupDialog.vue';
@@ -134,17 +106,10 @@
import LaunchOptionsDialog from './views/Settings/dialogs/LaunchOptionsDialog.vue'; import LaunchOptionsDialog from './views/Settings/dialogs/LaunchOptionsDialog.vue';
import Login from './views/Login/Login.vue'; import Login from './views/Login/Login.vue';
import MacOSTitleBar from './components/TitleBar/MacOSTitleBar.vue'; import MacOSTitleBar from './components/TitleBar/MacOSTitleBar.vue';
import Moderation from './views/Moderation/Moderation.vue';
import NavMenu from './components/NavMenu.vue'; import NavMenu from './components/NavMenu.vue';
import Notification from './views/Notifications/Notification.vue';
import PlayerList from './views/PlayerList/PlayerList.vue';
import PreviousInstancesInfoDialog from './components/dialogs/PreviousInstancesDialog/PreviousInstancesInfoDialog.vue'; import PreviousInstancesInfoDialog from './components/dialogs/PreviousInstancesDialog/PreviousInstancesInfoDialog.vue';
import PrimaryPasswordDialog from './views/Settings/dialogs/PrimaryPasswordDialog.vue'; import PrimaryPasswordDialog from './views/Settings/dialogs/PrimaryPasswordDialog.vue';
import Profile from './views/Profile/Profile.vue';
import Search from './views/Search/Search.vue';
import Settings from './views/Settings/Settings.vue';
import Sidebar from './views/Sidebar/Sidebar.vue'; import Sidebar from './views/Sidebar/Sidebar.vue';
import Tools from './views/Tools/Tools.vue';
import UserDialog from './components/dialogs/UserDialog/UserDialog.vue'; import UserDialog from './components/dialogs/UserDialog/UserDialog.vue';
import VRCXUpdateDialog from './components/dialogs/VRCXUpdateDialog.vue'; import VRCXUpdateDialog from './components/dialogs/VRCXUpdateDialog.vue';
import VRChatConfigDialog from './views/Settings/dialogs/VRChatConfigDialog.vue'; import VRChatConfigDialog from './views/Settings/dialogs/VRChatConfigDialog.vue';
@@ -153,6 +118,12 @@
import './app.scss'; import './app.scss';
const route = useRoute();
const requiresFullScreen = computed(() => {
return route.meta.fullScreen;
});
console.log(`isLinux: ${LINUX}`); console.log(`isLinux: ${LINUX}`);
const isMacOS = computed(() => { const isMacOS = computed(() => {

View File

@@ -8,7 +8,13 @@ import { createApp } from 'vue';
import ElementPlus from 'element-plus'; import ElementPlus from 'element-plus';
import { i18n, initComponents, initPlugins, initSentry } from './plugin'; import {
i18n,
initComponents,
initPlugins,
initRouter,
initSentry
} from './plugin';
import { pinia } from './stores'; import { pinia } from './stores';
import App from './App.vue'; import App from './App.vue';
@@ -19,10 +25,9 @@ await initPlugins();
const app = createApp(App); const app = createApp(App);
app.use(pinia); app.use(pinia).use(i18n).use(ElementPlus);
app.use(i18n);
app.use(ElementPlus);
initComponents(app); initComponents(app);
initRouter(app);
await initSentry(app); await initSentry(app);
app.mount('#root'); app.mount('#root');

View File

@@ -3,7 +3,7 @@
<div v-if="updateInProgress" class="pending-update" @click="showVRCXUpdateDialog"> <div v-if="updateInProgress" class="pending-update" @click="showVRCXUpdateDialog">
<el-progress <el-progress
type="circle" type="circle"
width="50" :width="50"
:stroke-width="3" :stroke-width="3"
:percentage="updateProgress" :percentage="updateProgress"
:format="updateProgressText"></el-progress> :format="updateProgressText"></el-progress>
@@ -17,12 +17,7 @@
style="font-size: 14px; height: 50px; width: 50px" style="font-size: 14px; height: 50px; width: 50px"
@click="showVRCXUpdateDialog" /> @click="showVRCXUpdateDialog" />
</div> </div>
<el-menu <el-menu ref="navRef" collapse router default-active="feed" :collapse-transition="false">
ref="navRef"
collapse
:default-active="menuActiveIndex"
:collapse-transition="false"
@select="selectMenu">
<el-menu-item <el-menu-item
v-for="item in navItems" v-for="item in navItems"
:key="item.index" :key="item.index"
@@ -51,7 +46,7 @@
{ index: 'gameLog', icon: 'ri-history-line', tooltip: 'nav_tooltip.game_log' }, { index: 'gameLog', icon: 'ri-history-line', tooltip: 'nav_tooltip.game_log' },
{ index: 'playerList', icon: 'ri-group-3-line', tooltip: 'nav_tooltip.player_list' }, { index: 'playerList', icon: 'ri-group-3-line', tooltip: 'nav_tooltip.player_list' },
{ index: 'search', icon: 'ri-search-line', tooltip: 'nav_tooltip.search' }, { index: 'search', icon: 'ri-search-line', tooltip: 'nav_tooltip.search' },
{ index: 'favorite', icon: 'ri-star-line', tooltip: 'nav_tooltip.favorites' }, { index: 'favorites', icon: 'ri-star-line', tooltip: 'nav_tooltip.favorites' },
{ index: 'friendLog', icon: 'ri-contacts-line', tooltip: 'nav_tooltip.friend_log' }, { index: 'friendLog', icon: 'ri-contacts-line', tooltip: 'nav_tooltip.friend_log' },
{ index: 'moderation', icon: 'ri-user-forbid-line', tooltip: 'nav_tooltip.moderation' }, { index: 'moderation', icon: 'ri-user-forbid-line', tooltip: 'nav_tooltip.moderation' },
{ index: 'notification', icon: 'ri-notification-2-line', tooltip: 'nav_tooltip.notification' }, { index: 'notification', icon: 'ri-notification-2-line', tooltip: 'nav_tooltip.notification' },
@@ -66,8 +61,7 @@
const { pendingVRCXUpdate, pendingVRCXInstall, updateInProgress, updateProgress } = storeToRefs(VRCXUpdaterStore); const { pendingVRCXUpdate, pendingVRCXInstall, updateInProgress, updateProgress } = storeToRefs(VRCXUpdaterStore);
const { showVRCXUpdateDialog, updateProgressText } = VRCXUpdaterStore; const { showVRCXUpdateDialog, updateProgressText } = VRCXUpdaterStore;
const uiStore = useUiStore(); const uiStore = useUiStore();
const { menuActiveIndex, notifiedMenus } = storeToRefs(uiStore); const { notifiedMenus } = storeToRefs(uiStore);
const { selectMenu } = uiStore;
</script> </script>
<style scoped> <style scoped>

View File

@@ -15,3 +15,4 @@ export async function initPlugins(isVrOverlay = false) {
export * from './i18n'; export * from './i18n';
export * from './components'; export * from './components';
export * from './sentry'; export * from './sentry';
export * from './router';

50
src/plugin/router.js Normal file
View File

@@ -0,0 +1,50 @@
import { createRouter, createWebHashHistory } from 'vue-router';
import Charts from './../views/Charts/Charts.vue';
import Favorites from './../views/Favorites/Favorites.vue';
import Feed from './../views/Feed/Feed.vue';
import FriendList from './../views/FriendList/FriendList.vue';
import FriendLog from './../views/FriendLog/FriendLog.vue';
import GameLog from './../views/GameLog/GameLog.vue';
import Moderation from './../views/Moderation/Moderation.vue';
import Notification from './../views/Notifications/Notification.vue';
import PlayerList from './../views/PlayerList/PlayerList.vue';
import Profile from './../views/Profile/Profile.vue';
import Search from './../views/Search/Search.vue';
import Settings from './../views/Settings/Settings.vue';
import Tools from './../views/Tools/Tools.vue';
const routes = [
{ path: '/feed', name: 'feed', component: Feed },
{ path: '/gamelog', name: 'gameLog', component: GameLog },
{ path: '/playerlist', name: 'playerList', component: PlayerList },
{ path: '/search', name: 'search', component: Search },
{ path: '/favorites', name: 'favorites', component: Favorites },
{ path: '/friendlog', name: 'friendLog', component: FriendLog },
{ path: '/moderation', name: 'moderation', component: Moderation },
{ path: '/notification', name: 'notification', component: Notification },
{
path: '/friendlist',
name: 'friendList',
component: FriendList,
meta: { fullScreen: true }
},
{
path: '/charts',
name: 'charts',
component: Charts,
meta: { fullScreen: true }
},
{ path: '/tools', name: 'tools', component: Tools },
{ path: '/profile', name: 'profile', component: Profile },
{ path: '/settings', name: 'settings', component: Settings }
];
export const router = createRouter({
history: createWebHashHistory(),
routes
});
export function initRouter(app) {
app.use(router);
}

View File

@@ -1,9 +1,10 @@
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useAppearanceSettingsStore, useUiStore } from '../../../stores';
import { THEME_CONFIG } from '../../constants'; import { THEME_CONFIG } from '../../constants';
import { i18n } from '../../../plugin/i18n'; import { i18n } from '../../../plugin/i18n';
import { router } from '../../../plugin/router';
import { useAppearanceSettingsStore } from '../../../stores';
/** /**
* *
@@ -273,8 +274,7 @@ async function getThemeMode(configRepository) {
} }
function redirectToToolsTab() { function redirectToToolsTab() {
const uiStore = useUiStore(); router.push({ name: 'tools' });
uiStore.menuActiveIndex = 'tools';
ElMessage({ ElMessage({
message: i18n.global.t('view.tools.redirect_message'), message: i18n.global.t('view.tools.redirect_message'),
type: 'primary', type: 'primary',

View File

@@ -2,6 +2,7 @@ import { computed, ref, watch } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus'; import { ElMessage, ElMessageBox } from 'element-plus';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import { compareByName, localeIncludes } from '../shared/utils'; import { compareByName, localeIncludes } from '../shared/utils';
import { instanceRequest, userRequest } from '../api'; import { instanceRequest, userRequest } from '../api';
@@ -11,14 +12,13 @@ import { useAppearanceSettingsStore } from './settings/appearance';
import { useAvatarStore } from './avatar'; import { useAvatarStore } from './avatar';
import { useFriendStore } from './friend'; import { useFriendStore } from './friend';
import { useGroupStore } from './group'; import { useGroupStore } from './group';
import { useUiStore } from './ui';
import { useUserStore } from './user'; import { useUserStore } from './user';
import { useWorldStore } from './world'; import { useWorldStore } from './world';
import { watchState } from '../service/watchState'; import { watchState } from '../service/watchState';
export const useSearchStore = defineStore('Search', () => { export const useSearchStore = defineStore('Search', () => {
const userStore = useUserStore(); const userStore = useUserStore();
const uiStore = useUiStore(); const router = useRouter();
const appearanceSettingsStore = useAppearanceSettingsStore(); const appearanceSettingsStore = useAppearanceSettingsStore();
const friendStore = useFriendStore(); const friendStore = useFriendStore();
const worldStore = useWorldStore(); const worldStore = useWorldStore();
@@ -180,20 +180,22 @@ export const useSearchStore = defineStore('Search', () => {
} }
function quickSearchChange(value) { function quickSearchChange(value) {
if (value) { if (!value) {
if (value.startsWith('search:')) { return;
const searchText = value.substr(7); }
if (quickSearchItems.value.length > 1 && searchText.length) {
friendsListSearch.value = searchText; if (value.startsWith('search:')) {
uiStore.menuActiveIndex = 'friendList'; const searchTerm = value.slice(7);
} else { if (quickSearchItems.value.length > 1 && searchTerm.length) {
uiStore.menuActiveIndex = 'search'; friendsListSearch.value = searchTerm;
searchText.value = searchText; router.push({ name: 'friendList' });
userStore.lookupUser({ displayName: searchText });
}
} else { } else {
userStore.showUserDialog(value); router.push({ name: 'search' });
searchText.value = searchTerm;
userStore.lookupUser({ displayName: searchTerm });
} }
} else {
userStore.showUserDialog(value);
} }
} }

View File

@@ -2,6 +2,7 @@ import { computed, ref, watch } from 'vue';
import { ElMessageBox } from 'element-plus'; import { ElMessageBox } from 'element-plus';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import { import {
HueToHex, HueToHex,
@@ -18,7 +19,6 @@ import { useFriendStore } from '../friend';
import { useGameLogStore } from '../gameLog'; import { useGameLogStore } from '../gameLog';
import { useModerationStore } from '../moderation'; import { useModerationStore } from '../moderation';
import { useNotificationStore } from '../notification'; import { useNotificationStore } from '../notification';
import { useUiStore } from '../ui';
import { useUserStore } from '../user'; import { useUserStore } from '../user';
import { useVrStore } from '../vr'; import { useVrStore } from '../vr';
import { useVrcxStore } from '../vrcx'; import { useVrcxStore } from '../vrcx';
@@ -38,7 +38,7 @@ export const useAppearanceSettingsStore = defineStore(
const gameLogStore = useGameLogStore(); const gameLogStore = useGameLogStore();
const vrcxStore = useVrcxStore(); const vrcxStore = useVrcxStore();
const userStore = useUserStore(); const userStore = useUserStore();
const uiStore = useUiStore(); const router = useRouter();
const { t, availableLocales, locale } = useI18n(); const { t, availableLocales, locale } = useI18n();
@@ -80,9 +80,10 @@ export const useAppearanceSettingsStore = defineStore(
}); });
const currentCulture = ref(''); const currentCulture = ref('');
const isSideBarTabShow = computed(() => { const isSideBarTabShow = computed(() => {
const currentRouteName = router.currentRoute.value?.name;
return !( return !(
uiStore.menuActiveIndex === 'friendList' || currentRouteName === 'friendList' ||
uiStore.menuActiveIndex === 'charts' currentRouteName === 'charts'
); );
}); });

View File

@@ -1,11 +1,13 @@
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { useRouter } from 'vue-router';
import { useNotificationStore } from './notification'; import { useNotificationStore } from './notification';
import { watchState } from '../service/watchState'; import { watchState } from '../service/watchState';
export const useUiStore = defineStore('Ui', () => { export const useUiStore = defineStore('Ui', () => {
const notificationStore = useNotificationStore(); const notificationStore = useNotificationStore();
const router = useRouter();
document.addEventListener('keydown', function (e) { document.addEventListener('keydown', function (e) {
if (e.shiftKey) { if (e.shiftKey) {
@@ -19,7 +21,6 @@ export const useUiStore = defineStore('Ui', () => {
} }
}); });
const menuActiveIndex = ref('feed');
const notifiedMenus = ref([]); const notifiedMenus = ref([]);
const shiftHeld = ref(false); const shiftHeld = ref(false);
@@ -27,40 +28,43 @@ export const useUiStore = defineStore('Ui', () => {
() => watchState.isLoggedIn, () => watchState.isLoggedIn,
(isLoggedIn) => { (isLoggedIn) => {
if (isLoggedIn) { if (isLoggedIn) {
menuActiveIndex.value = 'feed'; router.push({ name: 'feed' });
} }
}, },
{ flush: 'sync' } { flush: 'sync' }
); );
function notifyMenu(index) { function notifyMenu(index) {
const currentRouteName = router.currentRoute.value?.name;
if ( if (
index !== menuActiveIndex.value && index !== currentRouteName &&
!notifiedMenus.value.includes(index) !notifiedMenus.value.includes(index)
) { ) {
notifiedMenus.value.push(index); notifiedMenus.value.push(index);
} }
} }
function selectMenu(index) { watch(
menuActiveIndex.value = index; () => router.currentRoute.value.name,
removeNotify(index); (routeName) => {
if (index === 'notification') { if (routeName) {
notificationStore.unseenNotifications = []; removeNotify(routeName);
if (routeName === 'notification') {
notificationStore.unseenNotifications = [];
}
}
} }
} );
function removeNotify(index) { function removeNotify(index) {
notifiedMenus.value = notifiedMenus.value.filter((i) => i !== index); notifiedMenus.value = notifiedMenus.value.filter((i) => i !== index);
} }
return { return {
menuActiveIndex,
notifiedMenus, notifiedMenus,
shiftHeld, shiftHeld,
notifyMenu, notifyMenu,
selectMenu,
removeNotify removeNotify
}; };
}); });

View File

@@ -1,10 +1,10 @@
<template> <template>
<div id="chart" class="x-container" v-show="menuActiveIndex === 'charts'"> <div id="chart" class="x-container">
<div class="options-container" style="margin-top: 0"> <div class="options-container" style="margin-top: 0">
<span class="header">{{ t('view.charts.header') }}</span> <span class="header">{{ t('view.charts.header') }}</span>
</div> </div>
<keep-alive> <keep-alive>
<InstanceActivity v-if="menuActiveIndex === 'charts'" /> <InstanceActivity />
</keep-alive> </keep-alive>
<el-backtop target="#chart" :right="30" :bottom="30"></el-backtop> <el-backtop target="#chart" :right="30" :bottom="30"></el-backtop>
</div> </div>
@@ -12,15 +12,9 @@
<script setup> <script setup>
import { defineAsyncComponent } from 'vue'; import { defineAsyncComponent } from 'vue';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useUiStore } from '../../stores';
const InstanceActivity = defineAsyncComponent(() => import('./components/InstanceActivity.vue')); const InstanceActivity = defineAsyncComponent(() => import('./components/InstanceActivity.vue'));
const { t } = useI18n(); const { t } = useI18n();
const uiStore = useUiStore();
const { menuActiveIndex } = storeToRefs(uiStore);
</script> </script>

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-show="menuActiveIndex === 'favorite'" class="x-container"> <div class="x-container">
<div <div
style=" style="
font-size: 13px; font-size: 13px;
@@ -98,7 +98,6 @@
showWorldImportDialog, showWorldImportDialog,
showAvatarImportDialog showAvatarImportDialog
} = useFavoriteStore(); } = useFavoriteStore();
const { menuActiveIndex } = storeToRefs(useUiStore());
const { applyAvatar } = useAvatarStore(); const { applyAvatar } = useAvatarStore();
const editFavoritesMode = ref(false); const editFavoritesMode = ref(false);

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-show="menuActiveIndex === 'feed'" class="x-container feed"> <div class="x-container feed">
<div style="margin: 0 0 10px; display: flex; align-items: center"> <div style="margin: 0 0 10px; display: flex; align-items: center">
<div style="flex: none; margin-right: 10px; display: flex; align-items: center"> <div style="flex: none; margin-right: 10px; display: flex; align-items: center">
<el-tooltip placement="bottom" :content="t('view.feed.favorites_only_tooltip')"> <el-tooltip placement="bottom" :content="t('view.feed.favorites_only_tooltip')">
@@ -319,7 +319,6 @@
const { showUserDialog } = useUserStore(); const { showUserDialog } = useUserStore();
const { feedTable } = storeToRefs(useFeedStore()); const { feedTable } = storeToRefs(useFeedStore());
const { feedTableLookup } = useFeedStore(); const { feedTableLookup } = useFeedStore();
const { menuActiveIndex } = storeToRefs(useUiStore());
const { showFullscreenImageDialog } = useGalleryStore(); const { showFullscreenImageDialog } = useGalleryStore();
const { t } = useI18n(); const { t } = useI18n();

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-show="menuActiveIndex === 'friendList'" class="x-container"> <div class="x-container">
<div style="padding: 0 10px 0 10px"> <div style="padding: 0 10px 0 10px">
<div style="display: flex; align-items: center; justify-content: space-between"> <div style="display: flex; align-items: center; justify-content: space-between">
<span class="header">{{ t('view.friend_list.header') }}</span> <span class="header">{{ t('view.friend_list.header') }}</span>
@@ -256,11 +256,12 @@
</template> </template>
<script setup> <script setup>
import { nextTick, onMounted, reactive, ref, watch } from 'vue';
import { Close, Loading, Refresh, RefreshLeft } from '@element-plus/icons-vue'; import { Close, Loading, Refresh, RefreshLeft } from '@element-plus/icons-vue';
import { nextTick, reactive, ref, watch } from 'vue';
import { ElMessageBox } from 'element-plus'; import { ElMessageBox } from 'element-plus';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import { import {
formatDateFilter, formatDateFilter,
@@ -279,7 +280,6 @@
useFriendStore, useFriendStore,
useGalleryStore, useGalleryStore,
useSearchStore, useSearchStore,
useUiStore,
useUserStore useUserStore
} from '../../stores'; } from '../../stores';
import { friendRequest, userRequest } from '../../api'; import { friendRequest, userRequest } from '../../api';
@@ -293,7 +293,6 @@
const { getAllUserStats, confirmDeleteFriend, handleFriendDelete } = useFriendStore(); const { getAllUserStats, confirmDeleteFriend, handleFriendDelete } = useFriendStore();
const { randomUserColours } = storeToRefs(useAppearanceSettingsStore()); const { randomUserColours } = storeToRefs(useAppearanceSettingsStore());
const { showUserDialog } = useUserStore(); const { showUserDialog } = useUserStore();
const { menuActiveIndex } = storeToRefs(useUiStore());
const { stringComparer, friendsListSearch } = storeToRefs(useSearchStore()); const { stringComparer, friendsListSearch } = storeToRefs(useSearchStore());
const { showFullscreenImageDialog } = useGalleryStore(); const { showFullscreenImageDialog } = useGalleryStore();
@@ -310,15 +309,19 @@
const friendsListSearchFilterVIP = ref(false); const friendsListSearchFilterVIP = ref(false);
const friendsListBulkUnfriendForceUpdate = ref(0); const friendsListBulkUnfriendForceUpdate = ref(0);
watch(menuActiveIndex, (val) => { const route = useRoute();
if (val === 'friendList') nextTick(friendsListSearchChange);
});
onMounted(() => { watch(
friendsListSearchChange(); () => route.path,
}); (newPath, oldPath) => {
console.log('Route changed - FriendsList', newPath, oldPath);
nextTick(() => friendsListSearchChange());
},
{ immediate: true }
);
function friendsListSearchChange() { function friendsListSearchChange() {
console.log('Friends List Search Change');
friendsListLoading.value = true; friendsListLoading.value = true;
let query = ''; let query = '';
let cleanedQuery = ''; let cleanedQuery = '';

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-show="menuActiveIndex === 'friendLog'" class="x-container"> <div class="x-container">
<!-- 工具栏 --> <!-- 工具栏 -->
<div style="margin: 0 0 10px; display: flex; align-items: center"> <div style="margin: 0 0 10px; display: flex; align-items: center">
<el-select <el-select
@@ -105,7 +105,6 @@
const { showUserDialog } = useUserStore(); const { showUserDialog } = useUserStore();
const { friendLogTable } = storeToRefs(useFriendStore()); const { friendLogTable } = storeToRefs(useFriendStore());
const { shiftHeld } = storeToRefs(useUiStore()); const { shiftHeld } = storeToRefs(useUiStore());
const { menuActiveIndex } = storeToRefs(useUiStore());
watch( watch(
() => hideUnfriends.value, () => hideUnfriends.value,

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-show="menuActiveIndex === 'gameLog'" class="x-container"> <div class="x-container">
<div style="margin: 0 0 10px; display: flex; align-items: center"> <div style="margin: 0 0 10px; display: flex; align-items: center">
<div style="flex: none; margin-right: 10px; display: flex; align-items: center"> <div style="flex: none; margin-right: 10px; display: flex; align-items: center">
<el-tooltip placement="bottom" :content="t('view.feed.favorites_only_tooltip')"> <el-tooltip placement="bottom" :content="t('view.feed.favorites_only_tooltip')">
@@ -204,7 +204,7 @@
const { showWorldDialog } = useWorldStore(); const { showWorldDialog } = useWorldStore();
const { lookupUser } = useUserStore(); const { lookupUser } = useUserStore();
const { showPreviousInstancesInfoDialog } = useInstanceStore(); const { showPreviousInstancesInfoDialog } = useInstanceStore();
const { menuActiveIndex, shiftHeld } = storeToRefs(useUiStore()); const { shiftHeld } = storeToRefs(useUiStore());
const { gameLogIsFriend, gameLogIsFavorite, gameLogTableLookup } = useGameLogStore(); const { gameLogIsFriend, gameLogIsFavorite, gameLogTableLookup } = useGameLogStore();
const { gameLogTable } = storeToRefs(useGameLogStore()); const { gameLogTable } = storeToRefs(useGameLogStore());
const { updateSharedFeed } = useSharedFeedStore(); const { updateSharedFeed } = useSharedFeedStore();

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-show="menuActiveIndex === 'moderation'" class="x-container"> <div class="x-container">
<!-- 工具栏 --> <!-- 工具栏 -->
<div class="tool-slot"> <div class="tool-slot">
<el-select <el-select
@@ -108,7 +108,7 @@
const { showUserDialog } = useUserStore(); const { showUserDialog } = useUserStore();
const { isPlayerModerationsLoading, playerModerationTable } = storeToRefs(useModerationStore()); const { isPlayerModerationsLoading, playerModerationTable } = storeToRefs(useModerationStore());
const { refreshPlayerModerations, handlePlayerModerationDelete } = useModerationStore(); const { refreshPlayerModerations, handlePlayerModerationDelete } = useModerationStore();
const { menuActiveIndex, shiftHeld } = storeToRefs(useUiStore()); const { shiftHeld } = storeToRefs(useUiStore());
const { currentUser } = storeToRefs(useUserStore()); const { currentUser } = storeToRefs(useUserStore());
const filters = ref([ const filters = ref([

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-show="menuActiveIndex === 'notification'" v-loading="isNotificationsLoading" class="x-container"> <div v-loading="isNotificationsLoading" class="x-container">
<div style="margin: 0 0 10px; display: flex; align-items: center"> <div style="margin: 0 0 10px; display: flex; align-items: center">
<el-select <el-select
v-model="notificationTable.filters[0].value" v-model="notificationTable.filters[0].value"
@@ -400,7 +400,6 @@
useInviteStore, useInviteStore,
useLocationStore, useLocationStore,
useNotificationStore, useNotificationStore,
useUiStore,
useUserStore, useUserStore,
useWorldStore useWorldStore
} from '../../stores'; } from '../../stores';
@@ -427,7 +426,6 @@
const { clearInviteImageUpload } = useGalleryStore(); const { clearInviteImageUpload } = useGalleryStore();
const { notificationTable, isNotificationsLoading } = storeToRefs(useNotificationStore()); const { notificationTable, isNotificationsLoading } = storeToRefs(useNotificationStore());
const { refreshNotifications, handleNotificationHide } = useNotificationStore(); const { refreshNotifications, handleNotificationHide } = useNotificationStore();
const { menuActiveIndex, shiftHeld } = storeToRefs(useUiStore());
const { isGameRunning } = storeToRefs(useGameStore()); const { isGameRunning } = storeToRefs(useGameStore());
const { showFullscreenImageDialog } = useGalleryStore(); const { showFullscreenImageDialog } = useGalleryStore();
const { currentUser } = storeToRefs(useUserStore()); const { currentUser } = storeToRefs(useUserStore());

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-show="menuActiveIndex === 'playerList'" class="x-container" style="padding-top: 5px"> <div class="x-container" style="padding-top: 5px">
<div style="display: flex; flex-direction: column; height: 100%"> <div style="display: flex; flex-direction: column; height: 100%">
<div v-if="currentInstanceWorld.ref.id" style="display: flex"> <div v-if="currentInstanceWorld.ref.id" style="display: flex">
<img <img
@@ -441,7 +441,6 @@
const { currentInstanceLocation, currentInstanceWorld } = storeToRefs(useInstanceStore()); const { currentInstanceLocation, currentInstanceWorld } = storeToRefs(useInstanceStore());
const { getCurrentInstanceUserList } = useInstanceStore(); const { getCurrentInstanceUserList } = useInstanceStore();
const { currentInstanceUsersTable } = storeToRefs(useInstanceStore()); const { currentInstanceUsersTable } = storeToRefs(useInstanceStore());
const { menuActiveIndex } = storeToRefs(useUiStore());
const { showFullscreenImageDialog } = useGalleryStore(); const { showFullscreenImageDialog } = useGalleryStore();
const { currentUser } = storeToRefs(useUserStore()); const { currentUser } = storeToRefs(useUserStore());

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-show="menuActiveIndex === 'profile'" class="x-container"> <div class="x-container">
<div class="options-container" style="margin-top: 0"> <div class="options-container" style="margin-top: 0">
<span class="header">{{ t('view.profile.profile.header') }}</span> <span class="header">{{ t('view.profile.profile.header') }}</span>
<div class="x-friend-list" style="margin-top: 10px"> <div class="x-friend-list" style="margin-top: 10px">
@@ -514,7 +514,6 @@
inviteRequestMessageTable, inviteRequestMessageTable,
inviteRequestResponseMessageTable inviteRequestResponseMessageTable
} = storeToRefs(useInviteStore()); } = storeToRefs(useInviteStore());
const { menuActiveIndex } = storeToRefs(useUiStore());
const { directAccessWorld } = useSearchStore(); const { directAccessWorld } = useSearchStore();
const { logout } = useAuthStore(); const { logout } = useAuthStore();
const { cachedConfig } = storeToRefs(useAuthStore()); const { cachedConfig } = storeToRefs(useAuthStore());

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-show="menuActiveIndex === 'search'" class="x-container"> <div class="x-container">
<div style="margin: 0 0 10px; display: flex; align-items: center"> <div style="margin: 0 0 10px; display: flex; align-items: center">
<el-input <el-input
:model-value="searchText" :model-value="searchText"
@@ -320,7 +320,6 @@
useAvatarStore, useAvatarStore,
useGroupStore, useGroupStore,
useSearchStore, useSearchStore,
useUiStore,
useUserStore, useUserStore,
useWorldStore useWorldStore
} from '../../stores'; } from '../../stores';
@@ -343,7 +342,6 @@
const { showAvatarDialog, lookupAvatars, cachedAvatars } = useAvatarStore(); const { showAvatarDialog, lookupAvatars, cachedAvatars } = useAvatarStore();
const { cachedWorlds, showWorldDialog } = useWorldStore(); const { cachedWorlds, showWorldDialog } = useWorldStore();
const { showGroupDialog, applyGroup } = useGroupStore(); const { showGroupDialog, applyGroup } = useGroupStore();
const { menuActiveIndex } = storeToRefs(useUiStore());
const { searchText, searchUserResults } = storeToRefs(useSearchStore()); const { searchText, searchUserResults } = storeToRefs(useSearchStore());
const { clearSearch, moreSearchUser } = useSearchStore(); const { clearSearch, moreSearchUser } = useSearchStore();
const { cachedConfig } = storeToRefs(useAuthStore()); const { cachedConfig } = storeToRefs(useAuthStore());

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-show="menuActiveIndex === 'settings'" class="x-container"> <div class="x-container">
<div class="options-container" style="margin-top: 0; padding: 5px"> <div class="options-container" style="margin-top: 0; padding: 5px">
<span class="header">{{ t('view.settings.header') }}</span> <span class="header">{{ t('view.settings.header') }}</span>
</div> </div>
@@ -1413,7 +1413,6 @@
useAvatarProviderStore, useAvatarProviderStore,
useAvatarStore, useAvatarStore,
useFavoriteStore, useFavoriteStore,
useFriendStore,
useGameLogStore, useGameLogStore,
useGeneralSettingsStore, useGeneralSettingsStore,
useGroupStore, useGroupStore,
@@ -1469,7 +1468,6 @@
const { cachedWorlds } = useWorldStore(); const { cachedWorlds } = useWorldStore();
const { cachedInstances } = useInstanceStore(); const { cachedInstances } = useInstanceStore();
const { showLaunchOptions } = useLaunchStore(); const { showLaunchOptions } = useLaunchStore();
const { menuActiveIndex } = storeToRefs(useUiStore());
const { enablePrimaryPasswordChange } = useAuthStore(); const { enablePrimaryPasswordChange } = useAuthStore();
const { saveOpenVROption, updateVRLastLocation, updateOpenVR, updateVRConfigVars } = useVrStore(); const { saveOpenVROption, updateVRLastLocation, updateOpenVR, updateVRConfigVars } = useVrStore();
const { clearVRCXCache, showRegistryBackupDialog } = useVrcxStore(); const { clearVRCXCache, showRegistryBackupDialog } = useVrcxStore();
@@ -1519,7 +1517,6 @@
isAgeGatedInstancesVisible, isAgeGatedInstancesVisible,
sortFavorites, sortFavorites,
instanceUsersSortAlphabetical, instanceUsersSortAlphabetical,
tablePageSize,
dtHour12, dtHour12,
dtIsoFormat, dtIsoFormat,
sidebarSortMethod1, sidebarSortMethod1,

View File

@@ -1,5 +1,5 @@
<template> <template>
<div id="chart" class="x-container" v-show="isShowToolsTab"> <div id="chart" class="x-container">
<div class="options-container" style="margin-top: 0"> <div class="options-container" style="margin-top: 0">
<span class="header">{{ t('view.tools.header') }}</span> <span class="header">{{ t('view.tools.header') }}</span>
@@ -157,7 +157,7 @@
</div> </div>
</div> </div>
</div> </div>
<template v-if="isShowToolsTab"> <template v-if="isToolsTabVisible">
<GroupCalendarDialog <GroupCalendarDialog
:visible="isGroupCalendarDialogVisible" :visible="isGroupCalendarDialogVisible"
@close="isGroupCalendarDialogVisible = false" /> @close="isGroupCalendarDialogVisible = false" />
@@ -180,13 +180,14 @@
</template> </template>
<script setup> <script setup>
import { computed, defineAsyncComponent, ref } from 'vue'; import { computed, defineAsyncComponent, ref, watch } from 'vue';
import { ArrowRight } from '@element-plus/icons-vue'; import { ArrowRight } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import { useFriendStore, useGalleryStore, useUiStore } from '../../stores'; import { useFriendStore, useGalleryStore } from '../../stores';
const GroupCalendarDialog = defineAsyncComponent(() => import('./dialogs/GroupCalendarDialog.vue')); const GroupCalendarDialog = defineAsyncComponent(() => import('./dialogs/GroupCalendarDialog.vue'));
const ScreenshotMetadataDialog = defineAsyncComponent(() => import('./dialogs/ScreenshotMetadataDialog.vue')); const ScreenshotMetadataDialog = defineAsyncComponent(() => import('./dialogs/ScreenshotMetadataDialog.vue'));
@@ -199,9 +200,7 @@
const { t } = useI18n(); const { t } = useI18n();
const uiStore = useUiStore();
const { showGalleryDialog } = useGalleryStore(); const { showGalleryDialog } = useGalleryStore();
const { menuActiveIndex } = storeToRefs(uiStore);
const { friends } = storeToRefs(useFriendStore()); const { friends } = storeToRefs(useFriendStore());
const categoryCollapsed = ref({ const categoryCollapsed = ref({
@@ -216,8 +215,9 @@
const isExportDiscordNamesDialogVisible = ref(false); const isExportDiscordNamesDialogVisible = ref(false);
const isExportFriendsListDialogVisible = ref(false); const isExportFriendsListDialogVisible = ref(false);
const isExportAvatarsListDialogVisible = ref(false); const isExportAvatarsListDialogVisible = ref(false);
const isToolsTabVisible = computed(() => {
const isShowToolsTab = computed(() => menuActiveIndex.value === 'tools'); return useRoute().name === 'tools';
});
const showGroupCalendarDialog = () => { const showGroupCalendarDialog = () => {
isGroupCalendarDialogVisible.value = true; isGroupCalendarDialogVisible.value = true;