mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-06 14:46:04 +02:00
Split component, improve UI, fix and refactor (#1162)
This commit is contained in:
+63
-272
@@ -38,11 +38,13 @@ import _vrcxJsonStorage from './classes/vrcxJsonStorage.js';
|
||||
// tabs
|
||||
import ModerationTab from './views/tabs/Moderation.vue';
|
||||
import ChartsTab from './views/tabs/Charts.vue';
|
||||
import SideBar from './views/SideBar.vue';
|
||||
import NavMenu from './views/NavMenu.vue';
|
||||
|
||||
// components
|
||||
import SimpleSwitch from './components/settings/SimpleSwitch.vue';
|
||||
import GroupsSidebar from './components/sidebar/GroupsSidebar.vue';
|
||||
import PreviousInstanceInfo from './views/dialogs/PreviousInstanceInfo.vue';
|
||||
import Location from './components/common/Location.vue';
|
||||
|
||||
// main app classes
|
||||
import _sharedFeed from './classes/sharedFeed.js';
|
||||
@@ -171,14 +173,18 @@ console.log(`isLinux: ${LINUX}`);
|
||||
// tabs
|
||||
ModerationTab,
|
||||
ChartsTab,
|
||||
// - others
|
||||
SideBar,
|
||||
NavMenu,
|
||||
|
||||
// components
|
||||
// - settings
|
||||
SimpleSwitch,
|
||||
|
||||
// components
|
||||
// - sidebar(friendsListSidebar)
|
||||
GroupsSidebar,
|
||||
// - common
|
||||
Location,
|
||||
|
||||
// - dialogs
|
||||
PreviousInstanceInfo
|
||||
},
|
||||
@@ -186,7 +192,10 @@ console.log(`isLinux: ${LINUX}`);
|
||||
return {
|
||||
API,
|
||||
showUserDialog: this.showUserDialog,
|
||||
adjustDialogZ: this.adjustDialogZ
|
||||
adjustDialogZ: this.adjustDialogZ,
|
||||
getWorldName: this.getWorldName,
|
||||
userImage: this.userImage,
|
||||
userStatusClass: this.userStatusClass
|
||||
};
|
||||
},
|
||||
el: '#x-app',
|
||||
@@ -2875,7 +2884,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
API.$on('LOGIN', function () {
|
||||
$app.localFavoriteFriends.clear();
|
||||
$app.currentUserGroupsInit = false;
|
||||
$app.localFavoriteFriendsDivideByGroup.clear();
|
||||
this.cachedFavorites.clear();
|
||||
this.cachedFavoritesByObjectId.clear();
|
||||
this.cachedFavoriteGroups.clear();
|
||||
@@ -2953,12 +2961,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
// 애초에 $isDeleted인데 여기로 올 수 가 있나..?
|
||||
this.cachedFavoritesByObjectId.delete(args.params.objectId);
|
||||
$app.localFavoriteFriends.delete(args.params.objectId);
|
||||
$app.localFavoriteFriendsDivideByGroup.forEach((group, key) => {
|
||||
$app.removeFromArray(group, args.params.objectId);
|
||||
if (group.length === 0) {
|
||||
$app.localFavoriteFriendsDivideByGroup.delete(key);
|
||||
}
|
||||
});
|
||||
$app.updateSidebarFriendsList();
|
||||
if (ref.$isDeleted) {
|
||||
return;
|
||||
@@ -3013,12 +3015,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
}
|
||||
this.cachedFavoritesByObjectId.delete(ref.favoriteId);
|
||||
$app.localFavoriteFriends.delete(ref.favoriteId);
|
||||
$app.localFavoriteFriendsDivideByGroup.forEach((group, key) => {
|
||||
$app.removeFromArray(group, ref.favoriteId);
|
||||
if (group.length === 0) {
|
||||
$app.localFavoriteFriendsDivideByGroup.delete(key);
|
||||
}
|
||||
});
|
||||
$app.updateSidebarFriendsList();
|
||||
ref.$isDeleted = true;
|
||||
API.$emit('FAVORITE:@DELETE', {
|
||||
@@ -3093,15 +3089,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
ref.$isExpired = false;
|
||||
}
|
||||
ref.$groupKey = `${ref.type}:${String(ref.tags[0])}`;
|
||||
if (!$app.localFavoriteFriendsDivideByGroup.has(ref.$groupKey)) {
|
||||
$app.localFavoriteFriendsDivideByGroup.set(ref.$groupKey, [
|
||||
ref.favoriteId
|
||||
]);
|
||||
} else {
|
||||
$app.localFavoriteFriendsDivideByGroup
|
||||
.get(ref.$groupKey)
|
||||
.push(ref.favoriteId);
|
||||
}
|
||||
|
||||
if (ref.$isDeleted === false && ref.$groupRef === null) {
|
||||
var group = this.cachedFavoriteGroupsByTypeName.get(ref.$groupKey);
|
||||
@@ -3115,7 +3102,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
|
||||
API.expireFavorites = function () {
|
||||
$app.localFavoriteFriends.clear();
|
||||
$app.localFavoriteFriendsDivideByGroup.clear();
|
||||
this.cachedFavorites.clear();
|
||||
this.cachedFavoritesByObjectId.clear();
|
||||
$app.favoriteObjects.clear();
|
||||
@@ -3884,10 +3870,12 @@ console.log(`isLinux: ${LINUX}`);
|
||||
$app.data.debugGameLog = false;
|
||||
$app.data.debugFriendState = false;
|
||||
|
||||
$app.data.menuActiveIndex = 'feed';
|
||||
|
||||
$app.methods.notifyMenu = function (index) {
|
||||
var { menu } = this.$refs;
|
||||
if (menu.activeIndex !== index) {
|
||||
var item = menu.items[index];
|
||||
const navRef = this.$refs.menu.$children[0];
|
||||
if (this.menuActiveIndex !== index) {
|
||||
const item = navRef.items[this.menuActiveIndex];
|
||||
if (item) {
|
||||
item.$el.classList.add('notify');
|
||||
}
|
||||
@@ -3895,7 +3883,8 @@ console.log(`isLinux: ${LINUX}`);
|
||||
};
|
||||
|
||||
$app.methods.selectMenu = function (index) {
|
||||
var item = this.$refs.menu.items[index];
|
||||
this.menuActiveIndex = index;
|
||||
const item = this.$refs.menu.$children[0]?.items[index];
|
||||
if (item) {
|
||||
item.$el.classList.remove('notify');
|
||||
}
|
||||
@@ -4068,7 +4057,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
args.ref.displayName
|
||||
)}</strong>!`
|
||||
}).show();
|
||||
$app.$refs.menu.activeIndex = 'feed';
|
||||
$app.updateStoredUser(this.currentUser);
|
||||
});
|
||||
|
||||
@@ -4276,56 +4264,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
$app.data.sortActiveFriends = false;
|
||||
$app.data.sortOfflineFriends = false;
|
||||
|
||||
$app.methods.saveFriendsGroupStates = async function () {
|
||||
await configRepository.setBool(
|
||||
'VRCX_isFriendsGroupMe',
|
||||
this.isFriendsGroupMe
|
||||
);
|
||||
await configRepository.setBool(
|
||||
'VRCX_isFriendsGroupFavorites',
|
||||
this.isVIPFriends
|
||||
);
|
||||
await configRepository.setBool(
|
||||
'VRCX_isFriendsGroupOnline',
|
||||
this.isOnlineFriends
|
||||
);
|
||||
await configRepository.setBool(
|
||||
'VRCX_isFriendsGroupActive',
|
||||
this.isActiveFriends
|
||||
);
|
||||
await configRepository.setBool(
|
||||
'VRCX_isFriendsGroupOffline',
|
||||
this.isOfflineFriends
|
||||
);
|
||||
};
|
||||
|
||||
$app.methods.loadFriendsGroupStates = async function () {
|
||||
this.isFriendsGroupMe = await configRepository.getBool(
|
||||
'VRCX_isFriendsGroupMe',
|
||||
true
|
||||
);
|
||||
this.isVIPFriends = await configRepository.getBool(
|
||||
'VRCX_isFriendsGroupFavorites',
|
||||
true
|
||||
);
|
||||
this.isOnlineFriends = await configRepository.getBool(
|
||||
'VRCX_isFriendsGroupOnline',
|
||||
true
|
||||
);
|
||||
this.isActiveFriends = await configRepository.getBool(
|
||||
'VRCX_isFriendsGroupActive',
|
||||
false
|
||||
);
|
||||
this.isOfflineFriends = await configRepository.getBool(
|
||||
'VRCX_isFriendsGroupOffline',
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
API.$on('LOGIN', function () {
|
||||
$app.loadFriendsGroupStates();
|
||||
});
|
||||
|
||||
$app.methods.fetchActiveFriend = function (userId) {
|
||||
this.pendingActiveFriends.add(userId);
|
||||
// FIXME: handle error
|
||||
@@ -4367,11 +4305,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
$app.friends.clear();
|
||||
$app.pendingActiveFriends.clear();
|
||||
$app.friendNumber = 0;
|
||||
$app.isFriendsGroupMe = true;
|
||||
$app.isVIPFriends = true;
|
||||
$app.isOnlineFriends = true;
|
||||
$app.isActiveFriends = true;
|
||||
$app.isOfflineFriends = false;
|
||||
$app.isGroupInstances = false;
|
||||
$app.groupInstances = [];
|
||||
$app.vipFriends_ = [];
|
||||
@@ -5149,47 +5082,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
return this.vipFriends_;
|
||||
};
|
||||
|
||||
// VIP friends divide by group
|
||||
$app.computed.vipFriendsDivideByGroup = function () {
|
||||
const array = [];
|
||||
const helloYesThisIsDynamic = this.vipFriends_;
|
||||
|
||||
for (const [key, value] of this.localFavoriteFriendsDivideByGroup) {
|
||||
let friends = [];
|
||||
for (const item of value) {
|
||||
const friend = this.vipFriendsByGroupStatus.find(
|
||||
(friend) => friend.id === item
|
||||
);
|
||||
if (friend) {
|
||||
friends.push(friend);
|
||||
}
|
||||
}
|
||||
if (friends.length === 0) {
|
||||
continue;
|
||||
}
|
||||
friends.sort(getFriendsSortFunction(this.sidebarSortMethods));
|
||||
|
||||
let groupName = API.favoriteFriendGroups.find(
|
||||
(item) => item.key === key
|
||||
)?.displayName;
|
||||
if (!groupName) {
|
||||
groupName = key;
|
||||
}
|
||||
|
||||
array.push({
|
||||
key: key,
|
||||
value: friends,
|
||||
displayName: groupName
|
||||
});
|
||||
}
|
||||
|
||||
array.sort((a, b) => {
|
||||
return a.key.localeCompare(b.key);
|
||||
});
|
||||
|
||||
return array;
|
||||
};
|
||||
|
||||
// Online friends
|
||||
$app.computed.onlineFriends = function () {
|
||||
if (!this.sortOnlineFriends) {
|
||||
@@ -5341,7 +5233,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
// #endregion
|
||||
// #region | App: Quick Search
|
||||
|
||||
$app.data.quickSearch = '';
|
||||
$app.data.quickSearchItems = [];
|
||||
|
||||
var localeIncludes = function (str, search, comparer) {
|
||||
@@ -5469,24 +5360,15 @@ console.log(`isLinux: ${LINUX}`);
|
||||
const searchText = value.substr(7);
|
||||
if (this.quickSearchItems.length > 1 && searchText.length) {
|
||||
this.friendsListSearch = searchText;
|
||||
this.$refs.menu.activeIndex = 'friendsList';
|
||||
this.menuActiveIndex = 'friendsList';
|
||||
} else {
|
||||
this.$refs.menu.activeIndex = 'search';
|
||||
this.menuActiveIndex = 'search';
|
||||
this.searchText = searchText;
|
||||
this.lookupUser({ displayName: searchText });
|
||||
}
|
||||
} else {
|
||||
this.showUserDialog(value);
|
||||
}
|
||||
this.quickSearchVisibleChange(value);
|
||||
}
|
||||
};
|
||||
|
||||
// NOTE: 그냥 열고 닫고 했을때 changed 이벤트 발생이 안되기 때문에 넣음
|
||||
$app.methods.quickSearchVisibleChange = function (value) {
|
||||
if (value) {
|
||||
this.quickSearch = '';
|
||||
this.quickSearchItems = [];
|
||||
this.quickSearchUserHistory();
|
||||
}
|
||||
};
|
||||
@@ -5545,7 +5427,7 @@ console.log(`isLinux: ${LINUX}`);
|
||||
$app.friendLogInitStatus = false;
|
||||
$app.notificationInitStatus = false;
|
||||
await database.initUserTables(args.json.id);
|
||||
$app.$refs.menu.activeIndex = 'feed';
|
||||
$app.menuActiveIndex = 'feed';
|
||||
await $app.updateDatabaseVersion();
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
$app.gameLogTable.data = await database.lookupGameLogDatabase(
|
||||
@@ -6556,7 +6438,7 @@ console.log(`isLinux: ${LINUX}`);
|
||||
}
|
||||
}
|
||||
this.$refs.searchTab.currentName = '0';
|
||||
this.$refs.menu.activeIndex = 'search';
|
||||
this.menuActiveIndex = 'search';
|
||||
};
|
||||
|
||||
// #endregion
|
||||
@@ -22160,7 +22042,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
// #region | Local Favorite Friends
|
||||
|
||||
$app.data.localFavoriteFriends = new Set();
|
||||
$app.data.localFavoriteFriendsDivideByGroup = new Map();
|
||||
$app.data.localFavoriteFriendsGroups = JSON.parse(
|
||||
await configRepository.getString(
|
||||
'VRCX_localFavoriteFriendsGroups',
|
||||
@@ -22169,7 +22050,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
);
|
||||
$app.methods.updateLocalFavoriteFriends = function () {
|
||||
this.localFavoriteFriends.clear();
|
||||
this.localFavoriteFriendsDivideByGroup.clear();
|
||||
for (const ref of API.cachedFavorites.values()) {
|
||||
if (
|
||||
!ref.$isDeleted &&
|
||||
@@ -22178,17 +22058,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
this.localFavoriteFriendsGroups.length === 0)
|
||||
) {
|
||||
this.localFavoriteFriends.add(ref.favoriteId);
|
||||
if (
|
||||
!this.localFavoriteFriendsDivideByGroup.has(ref.$groupKey)
|
||||
) {
|
||||
this.localFavoriteFriendsDivideByGroup.set(ref.$groupKey, [
|
||||
ref.favoriteId
|
||||
]);
|
||||
} else {
|
||||
this.localFavoriteFriendsDivideByGroup
|
||||
.get(ref.$groupKey)
|
||||
.push(ref.favoriteId);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.updateSidebarFriendsList();
|
||||
@@ -22736,6 +22605,7 @@ console.log(`isLinux: ${LINUX}`);
|
||||
|
||||
$app.data.appLanguage =
|
||||
(await configRepository.getString('VRCX_appLanguage')) ?? 'en';
|
||||
$utils.changeCJKorder($app.data.appLanguage);
|
||||
i18n.locale = $app.data.appLanguage;
|
||||
$app.methods.initLanguage = async function () {
|
||||
if (!(await configRepository.getString('VRCX_appLanguage'))) {
|
||||
@@ -22760,6 +22630,7 @@ console.log(`isLinux: ${LINUX}`);
|
||||
$app.methods.changeAppLanguage = function (language) {
|
||||
console.log('Language changed:', language);
|
||||
this.appLanguage = language;
|
||||
$utils.changeCJKorder(language);
|
||||
i18n.locale = language;
|
||||
configRepository.setString('VRCX_appLanguage', language);
|
||||
this.applyLanguageStrings();
|
||||
@@ -23394,123 +23265,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
);
|
||||
};
|
||||
|
||||
$app.data.isSidebarGroupByInstanceCollapsed =
|
||||
await configRepository.getBool(
|
||||
'VRCX_sidebarGroupByInstanceCollapsed',
|
||||
false
|
||||
);
|
||||
|
||||
$app.methods.toggleSwitchGroupByInstanceCollapsed = function () {
|
||||
this.isSidebarGroupByInstanceCollapsed =
|
||||
!this.isSidebarGroupByInstanceCollapsed;
|
||||
configRepository.setBool(
|
||||
'VRCX_sidebarGroupByInstanceCollapsed',
|
||||
this.isSidebarGroupByInstanceCollapsed
|
||||
);
|
||||
};
|
||||
|
||||
$app.computed.friendsInSameInstance = function () {
|
||||
const friendsList = {};
|
||||
|
||||
const allFriends = [...this.vipFriends, ...this.onlineFriends];
|
||||
allFriends.forEach((friend) => {
|
||||
let locationTag;
|
||||
|
||||
if (friend.ref?.$location.isRealInstance) {
|
||||
locationTag = friend.ref.$location.tag;
|
||||
} else if (this.lastLocation.friendList.has(friend.id)) {
|
||||
let $location = $utils.parseLocation(
|
||||
this.lastLocation.location
|
||||
);
|
||||
if ($location.isRealInstance) {
|
||||
if ($location.tag === 'private') {
|
||||
locationTag = this.lastLocation.name;
|
||||
} else {
|
||||
locationTag = $location.tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!locationTag) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!friendsList[locationTag]) {
|
||||
friendsList[locationTag] = [];
|
||||
}
|
||||
friendsList[locationTag].push(friend);
|
||||
});
|
||||
|
||||
const sortedFriendsList = [];
|
||||
for (const group of Object.values(friendsList)) {
|
||||
if (group.length > 1) {
|
||||
sortedFriendsList.push(
|
||||
group.sort(
|
||||
(a, b) => a.ref?.$location_at - b.ref?.$location_at
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return sortedFriendsList.sort((a, b) => b.length - a.length);
|
||||
};
|
||||
|
||||
$app.computed.onlineFriendsByGroupStatus = function () {
|
||||
if (
|
||||
!this.isSidebarGroupByInstance ||
|
||||
(this.isSidebarGroupByInstance && !this.isHideFriendsInSameInstance)
|
||||
) {
|
||||
return this.onlineFriends;
|
||||
}
|
||||
|
||||
const sameInstanceTag = new Set(
|
||||
this.friendsInSameInstance.flatMap((item) =>
|
||||
item.map((friend) => friend.ref?.$location.tag)
|
||||
)
|
||||
);
|
||||
|
||||
return this.onlineFriends.filter(
|
||||
(item) => !sameInstanceTag.has(item.ref?.$location.tag)
|
||||
);
|
||||
};
|
||||
|
||||
$app.computed.vipFriendsByGroupStatus = function () {
|
||||
if (
|
||||
!this.isSidebarGroupByInstance ||
|
||||
(this.isSidebarGroupByInstance && !this.isHideFriendsInSameInstance)
|
||||
) {
|
||||
return this.vipFriends;
|
||||
}
|
||||
|
||||
const sameInstanceTag = new Set(
|
||||
this.friendsInSameInstance.flatMap((item) =>
|
||||
item.map((friend) => friend.ref?.$location.tag)
|
||||
)
|
||||
);
|
||||
|
||||
return this.vipFriends.filter(
|
||||
(item) => !sameInstanceTag.has(item.ref?.$location.tag)
|
||||
);
|
||||
};
|
||||
|
||||
$app.methods.getFriendsLocations = function (friendsArr) {
|
||||
// prevent the instance title display as "Traveling".
|
||||
if (!friendsArr?.length) {
|
||||
return '';
|
||||
}
|
||||
for (const friend of friendsArr) {
|
||||
if (friend.ref?.location !== 'traveling') {
|
||||
return friend.ref.location;
|
||||
}
|
||||
if ($utils.isRealInstance(friend.ref?.travelingToLocation)) {
|
||||
return friend.ref.travelingToLocation;
|
||||
}
|
||||
if (this.lastLocation.friendList.has(friend.id)) {
|
||||
return this.lastLocation.name;
|
||||
}
|
||||
}
|
||||
return friendsArr[0].ref?.location;
|
||||
};
|
||||
|
||||
// favorites Tab
|
||||
// - local favorites
|
||||
// - local world & avatar
|
||||
@@ -23534,6 +23288,43 @@ console.log(`isLinux: ${LINUX}`);
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region | Tab Props
|
||||
$app.computed.sideBarTabProps = function () {
|
||||
return {
|
||||
style: { width: `${this.asideWidth}px` },
|
||||
vipFriends: this.vipFriends,
|
||||
onlineFriends: this.onlineFriends,
|
||||
quickSearchRemoteMethod: this.quickSearchRemoteMethod,
|
||||
quickSearchItems: this.quickSearchItems,
|
||||
hideTooltips: this.hideTooltips,
|
||||
onlineFriendCount: this.onlineFriendCount,
|
||||
friends: this.friends,
|
||||
isGameRunning: this.isGameRunning,
|
||||
isSidebarDivideByFriendGroup: this.isSidebarDivideByFriendGroup,
|
||||
isSidebarGroupByInstance: this.isSidebarGroupByInstance,
|
||||
isHideFriendsInSameInstance: this.isHideFriendsInSameInstance,
|
||||
gameLogDisabled: this.gameLogDisabled,
|
||||
lastLocation: this.lastLocation,
|
||||
lastLocationDestination: this.lastLocationDestination,
|
||||
hideNicknames: this.hideNicknames,
|
||||
activeFriends: this.activeFriends,
|
||||
offlineFriends: this.offlineFriends,
|
||||
groupInstances: this.groupInstances,
|
||||
inGameGroupOrder: this.inGameGroupOrder,
|
||||
groupedByGroupKeyFavoriteFriends:
|
||||
this.groupedByGroupKeyFavoriteFriends
|
||||
};
|
||||
};
|
||||
|
||||
$app.computed.isSideBarTabShow = function () {
|
||||
return !(
|
||||
this.menuActiveIndex === 'friendsList' ||
|
||||
this.menuActiveIndex === 'charts'
|
||||
);
|
||||
};
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region | Electron
|
||||
|
||||
if (LINUX) {
|
||||
|
||||
+8
-12
@@ -8,7 +8,6 @@
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
//
|
||||
|
||||
@import '~normalize.css/normalize.css';
|
||||
@import '~animate.css/animate.min.css';
|
||||
@import '~noty/lib/noty.css';
|
||||
@import '~element-ui/lib/theme-chalk/index.css';
|
||||
@@ -135,14 +134,11 @@
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
body,
|
||||
input,
|
||||
textarea,
|
||||
select,
|
||||
button {
|
||||
font-family: 'Noto Sans JP', 'Noto Sans KR', 'Noto Sans TC', 'Noto Sans SC',
|
||||
'Meiryo UI', 'Malgun Gothic', 'Segoe UI', sans-serif;
|
||||
line-height: normal;
|
||||
body {
|
||||
font-family:
|
||||
'Noto Sans KR', 'Noto Sans JP', 'Noto Sans TC', 'Noto Sans SC',
|
||||
'Meiryo UI', 'Malgun Gothic', 'Segoe UI', system-ui, sans-serif;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -164,10 +160,9 @@ a {
|
||||
}
|
||||
|
||||
.x-app {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden auto;
|
||||
cursor: default;
|
||||
}
|
||||
@@ -307,6 +302,7 @@ hr.x-vertical-divider {
|
||||
.el-popper.x-quick-search {
|
||||
width: 225px;
|
||||
min-width: 0 !important;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-popper.x-quick-search .el-select-dropdown__item {
|
||||
|
||||
@@ -68,152 +68,6 @@ export default class extends baseClass {
|
||||
}
|
||||
});
|
||||
|
||||
Vue.component('location', {
|
||||
template:
|
||||
"<span><span @click=\"showWorldDialog\" :class=\"{ 'x-link': link && this.location !== 'private' && this.location !== 'offline'}\">" +
|
||||
'<i v-if="isTraveling" class="el-icon el-icon-loading" style="display:inline-block;margin-right:5px"></i>' +
|
||||
'<span>{{ text }}</span></span>' +
|
||||
'<span v-if="groupName" @click="showGroupDialog" :class="{ \'x-link\': link}">({{ groupName }})</span>' +
|
||||
'<span v-if="region" class="flags" :class="region" style="display:inline-block;margin-left:5px"></span>' +
|
||||
'<i v-if="strict" class="el-icon el-icon-lock" style="display:inline-block;margin-left:5px"></i></span>',
|
||||
props: {
|
||||
location: String,
|
||||
traveling: String,
|
||||
hint: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
grouphint: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
link: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
isOpenPreviousInstanceInfoDialog: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
text: this.location,
|
||||
region: this.region,
|
||||
strict: this.strict,
|
||||
isTraveling: this.isTraveling,
|
||||
groupName: this.groupName
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
parse() {
|
||||
this.isTraveling = false;
|
||||
this.groupName = '';
|
||||
var instanceId = this.location;
|
||||
if (
|
||||
typeof this.traveling !== 'undefined' &&
|
||||
this.location === 'traveling'
|
||||
) {
|
||||
instanceId = this.traveling;
|
||||
this.isTraveling = true;
|
||||
}
|
||||
this.text = instanceId;
|
||||
var L = $utils.parseLocation(instanceId);
|
||||
if (L.isOffline) {
|
||||
this.text = 'Offline';
|
||||
} else if (L.isPrivate) {
|
||||
this.text = 'Private';
|
||||
} else if (L.isTraveling) {
|
||||
this.text = 'Traveling';
|
||||
} else if (
|
||||
typeof this.hint === 'string' &&
|
||||
this.hint !== ''
|
||||
) {
|
||||
if (L.instanceId) {
|
||||
this.text = `${this.hint} #${L.instanceName} ${L.accessTypeName}`;
|
||||
} else {
|
||||
this.text = this.hint;
|
||||
}
|
||||
} else if (L.worldId) {
|
||||
var ref = API.cachedWorlds.get(L.worldId);
|
||||
if (typeof ref === 'undefined') {
|
||||
$app.getWorldName(L.worldId).then((worldName) => {
|
||||
if (L.tag === instanceId) {
|
||||
if (L.instanceId) {
|
||||
this.text = `${worldName} #${L.instanceName} ${L.accessTypeName}`;
|
||||
} else {
|
||||
this.text = worldName;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (L.instanceId) {
|
||||
this.text = `${ref.name} #${L.instanceName} ${L.accessTypeName}`;
|
||||
} else {
|
||||
this.text = ref.name;
|
||||
}
|
||||
}
|
||||
if (this.grouphint) {
|
||||
this.groupName = this.grouphint;
|
||||
} else if (L.groupId) {
|
||||
this.groupName = L.groupId;
|
||||
$app.getGroupName(instanceId).then((groupName) => {
|
||||
if (L.tag === instanceId) {
|
||||
this.groupName = groupName;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.region = '';
|
||||
if (!L.isOffline && !L.isPrivate && !L.isTraveling) {
|
||||
this.region = L.region;
|
||||
if (!L.region && L.instanceId) {
|
||||
this.region = 'us';
|
||||
}
|
||||
}
|
||||
this.strict = L.strict;
|
||||
},
|
||||
showWorldDialog() {
|
||||
if (this.link) {
|
||||
var instanceId = this.location;
|
||||
if (this.traveling && this.location === 'traveling') {
|
||||
instanceId = this.traveling;
|
||||
}
|
||||
if (!instanceId && this.hint.length === 8) {
|
||||
// shortName
|
||||
API.$emit('SHOW_WORLD_DIALOG_SHORTNAME', this.hint);
|
||||
return;
|
||||
}
|
||||
if (this.isOpenPreviousInstanceInfoDialog) {
|
||||
this.$emit(
|
||||
'open-previous-instance-info-dialog',
|
||||
instanceId
|
||||
);
|
||||
} else {
|
||||
API.$emit('SHOW_WORLD_DIALOG', instanceId);
|
||||
}
|
||||
}
|
||||
},
|
||||
showGroupDialog() {
|
||||
var location = this.location;
|
||||
if (this.isTraveling) {
|
||||
location = this.traveling;
|
||||
}
|
||||
if (!location || !this.link) {
|
||||
return;
|
||||
}
|
||||
var L = $utils.parseLocation(location);
|
||||
if (!L.groupId) {
|
||||
return;
|
||||
}
|
||||
API.$emit('SHOW_GROUP_DIALOG', L.groupId);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
location() {
|
||||
this.parse();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.parse();
|
||||
}
|
||||
});
|
||||
|
||||
Vue.component('location-world', {
|
||||
template:
|
||||
'<span><span @click="showLaunchDialog" class="x-link">' +
|
||||
|
||||
@@ -351,5 +351,29 @@ export default {
|
||||
echarts = module;
|
||||
return echarts;
|
||||
});
|
||||
},
|
||||
// CJK character in Japanese, Korean, Chinese are different
|
||||
// so change font-family order when users change language to display CJK character correctly
|
||||
changeCJKorder(lang) {
|
||||
const otherFonts = window
|
||||
.getComputedStyle(document.body)
|
||||
.fontFamily.split(',')
|
||||
.filter((item) => !item.includes('Noto Sans'))
|
||||
.join(', ');
|
||||
const notoSans = 'Noto Sans';
|
||||
|
||||
const fontFamilies = {
|
||||
ja_JP: ['JP', 'KR', 'TC', 'SC'],
|
||||
ko: ['KR', 'JP', 'TC', 'SC'],
|
||||
zh_TW: ['TC', 'JP', 'KR', 'SC'],
|
||||
zh_CN: ['SC', 'JP', 'KR', 'TC']
|
||||
};
|
||||
|
||||
if (fontFamilies[lang]) {
|
||||
const CJKFamily = fontFamilies[lang]
|
||||
.map((item) => `${notoSans} ${item}`)
|
||||
.join(', ');
|
||||
document.body.style.fontFamily = `${CJKFamily}, ${otherFonts}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
class="location"
|
||||
:location="activityDetailData[0].location"
|
||||
is-open-previous-instance-info-dialog
|
||||
@open-previous-instance-info-dialog="$emit('open-previous-instance-info-dialog', $event)"
|
||||
></location>
|
||||
@open-previous-instance-info-dialog="
|
||||
$emit('open-previous-instance-info-dialog', $event)
|
||||
"></location>
|
||||
</transition>
|
||||
</div>
|
||||
|
||||
@@ -19,9 +20,13 @@
|
||||
<script>
|
||||
import dayjs from 'dayjs';
|
||||
import utils from '../../classes/utils';
|
||||
import Location from '../common/Location.vue';
|
||||
|
||||
export default {
|
||||
name: 'InstanceActivityDetail',
|
||||
components: {
|
||||
Location
|
||||
},
|
||||
inject: ['API', 'showUserDialog'],
|
||||
props: {
|
||||
activityDetailData: {
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<div>
|
||||
<span v-if="!text" style="color: transparent">-</span>
|
||||
<span v-show="text">
|
||||
<span
|
||||
:class="{ 'x-link': link && location !== 'private' && location !== 'offline' }"
|
||||
@click="showWorldDialog">
|
||||
<i v-if="isTraveling" class="el-icon el-icon-loading" style="display: inline-block"></i>
|
||||
<span>{{ text }}</span>
|
||||
</span>
|
||||
<span v-if="groupName" :class="{ 'x-link': link }" @click="showGroupDialog">({{ groupName }})</span>
|
||||
<span v-if="region" class="flags" :class="region" style="display: inline-block; margin-left: 5px"></span>
|
||||
<i v-if="strict" class="el-icon el-icon-lock" style="display: inline-block; margin-left: 5px"></i>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import utils from '../../classes/utils';
|
||||
|
||||
export default {
|
||||
// eslint-disable-next-line vue/multi-word-component-names
|
||||
name: 'Location',
|
||||
inject: ['API'],
|
||||
props: {
|
||||
location: String,
|
||||
traveling: String,
|
||||
hint: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
grouphint: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
link: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
isOpenPreviousInstanceInfoDialog: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
text: '',
|
||||
region: this.region,
|
||||
strict: this.strict,
|
||||
isTraveling: this.isTraveling,
|
||||
groupName: this.groupName
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
location() {
|
||||
this.parse();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.parse();
|
||||
},
|
||||
methods: {
|
||||
parse() {
|
||||
if (!this.API) return;
|
||||
this.isTraveling = false;
|
||||
this.groupName = '';
|
||||
let instanceId = this.location;
|
||||
if (typeof this.traveling !== 'undefined' && this.location === 'traveling') {
|
||||
instanceId = this.traveling;
|
||||
this.isTraveling = true;
|
||||
}
|
||||
const L = utils.parseLocation(instanceId);
|
||||
if (L.isOffline) {
|
||||
this.text = 'Offline';
|
||||
} else if (L.isPrivate) {
|
||||
this.text = 'Private';
|
||||
} else if (L.isTraveling) {
|
||||
this.text = 'Traveling';
|
||||
} else if (typeof this.hint === 'string' && this.hint !== '') {
|
||||
if (L.instanceId) {
|
||||
this.text = `${this.hint} #${L.instanceName} ${L.accessTypeName}`;
|
||||
} else {
|
||||
this.text = this.hint;
|
||||
}
|
||||
} else if (L.worldId) {
|
||||
var ref = this.API.cachedWorlds.get(L.worldId);
|
||||
if (typeof ref === 'undefined') {
|
||||
// TODO: USE props
|
||||
$app.getWorldName(L.worldId).then((worldName) => {
|
||||
if (L.tag === instanceId) {
|
||||
if (L.instanceId) {
|
||||
this.text = `${worldName} #${L.instanceName} ${L.accessTypeName}`;
|
||||
} else {
|
||||
this.text = worldName;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (L.instanceId) {
|
||||
this.text = `${ref.name} #${L.instanceName} ${L.accessTypeName}`;
|
||||
} else {
|
||||
this.text = ref.name;
|
||||
}
|
||||
}
|
||||
if (this.grouphint) {
|
||||
this.groupName = this.grouphint;
|
||||
} else if (L.groupId) {
|
||||
this.groupName = L.groupId;
|
||||
// TODO: USE props
|
||||
$app.getGroupName(instanceId).then((groupName) => {
|
||||
if (L.tag === instanceId) {
|
||||
this.groupName = groupName;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.region = '';
|
||||
if (!L.isOffline && !L.isPrivate && !L.isTraveling) {
|
||||
this.region = L.region;
|
||||
if (!L.region && L.instanceId) {
|
||||
this.region = 'us';
|
||||
}
|
||||
}
|
||||
this.strict = L.strict;
|
||||
},
|
||||
showWorldDialog() {
|
||||
if (this.link) {
|
||||
let instanceId = this.location;
|
||||
if (this.traveling && this.location === 'traveling') {
|
||||
instanceId = this.traveling;
|
||||
}
|
||||
if (!instanceId && this.hint.length === 8) {
|
||||
// shortName
|
||||
this.API.$emit('SHOW_WORLD_DIALOG_SHORTNAME', this.hint);
|
||||
return;
|
||||
}
|
||||
if (this.isOpenPreviousInstanceInfoDialog) {
|
||||
this.$emit('open-previous-instance-info-dialog', instanceId);
|
||||
} else {
|
||||
this.API.$emit('SHOW_WORLD_DIALOG', instanceId);
|
||||
}
|
||||
}
|
||||
},
|
||||
showGroupDialog() {
|
||||
let location = this.location;
|
||||
if (this.isTraveling) {
|
||||
location = this.traveling;
|
||||
}
|
||||
if (!location || !this.link) {
|
||||
return;
|
||||
}
|
||||
const L = utils.parseLocation(location);
|
||||
if (!L.groupId) {
|
||||
return;
|
||||
}
|
||||
this.API.$emit('SHOW_GROUP_DIALOG', L.groupId);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<div class="x-friend-item" @click="$emit('click')">
|
||||
<template v-if="friend.ref">
|
||||
<div
|
||||
class="avatar"
|
||||
:class="isFriendActiveOrOffline ? undefined : userStatusClass(friend.ref, friend.pendingOffline)">
|
||||
<img v-lazy="userImage(friend.ref)" />
|
||||
</div>
|
||||
<div class="detail">
|
||||
<span v-if="!hideNicknames && friend.$nickName" class="name" :style="{ color: friend.ref.$userColour }">
|
||||
{{ friend.ref.displayName }} ({{ friend.$nickName }})
|
||||
</span>
|
||||
<span v-else class="name" :style="{ color: friend.ref.$userColour }"
|
||||
>{{ friend.ref.displayName }}{{ isGroupByInstance && friend.isVIP ? ' ⭐' : '' }}</span
|
||||
>
|
||||
|
||||
<span v-if="isFriendActiveOrOffline" class="extra">{{ friend.ref.statusDescription }}</span>
|
||||
<template v-else>
|
||||
<span v-if="friend.pendingOffline" class="extra">
|
||||
<i class="el-icon-warning-outline" /> {{ $t('side_panel.pending_offline') }}
|
||||
</span>
|
||||
<template v-else-if="isGroupByInstance">
|
||||
<i v-if="isFriendTraveling" class="el-icon el-icon-loading"></i>
|
||||
<timer
|
||||
class="extra"
|
||||
:epoch="epoch"
|
||||
:style="
|
||||
isFriendTraveling ? { display: 'inline-block', overflow: 'unset' } : undefined
|
||||
"></timer>
|
||||
</template>
|
||||
<location
|
||||
v-else
|
||||
class="extra"
|
||||
:location="friend.ref.location"
|
||||
:traveling="friend.ref.travelingToLocation"
|
||||
:link="false" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="!friend.ref && !API.isRefreshFriendsLoading">
|
||||
<span>{{ friend.name || friend.id }}</span>
|
||||
<el-button
|
||||
ttype="text"
|
||||
icon="el-icon-close"
|
||||
size="mini"
|
||||
style="margin-left: 5px"
|
||||
@click.stop="$emit('confirm-delete-friend', friend.id)">
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<el-skeleton v-else animated class="skeleton" :throttle="100">
|
||||
<template slot="template">
|
||||
<div>
|
||||
<el-skeleton-item variant="circle" />
|
||||
<div>
|
||||
<el-skeleton-item variant="text" />
|
||||
<el-skeleton-item variant="text" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-skeleton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Location from '../common/Location.vue';
|
||||
|
||||
export default {
|
||||
name: 'FriendItem',
|
||||
components: {
|
||||
Location
|
||||
},
|
||||
inject: ['API', 'userImage', 'userStatusClass'],
|
||||
props: {
|
||||
friend: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
hideNicknames: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isGroupByInstance: Boolean
|
||||
},
|
||||
computed: {
|
||||
isFriendTraveling() {
|
||||
return this.friend.ref.location === 'traveling';
|
||||
},
|
||||
isFriendActiveOrOffline() {
|
||||
return this.friend.state === 'active' || this.friend.state === 'offline';
|
||||
},
|
||||
epoch() {
|
||||
return this.isFriendTraveling ? this.friend.ref.$travelingToTime : this.friend.ref.$location_at;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.skeleton {
|
||||
height: 40px;
|
||||
width: 100%;
|
||||
::v-deep .el-skeleton {
|
||||
height: 100%;
|
||||
> div {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
> :first-child {
|
||||
margin-right: 8px;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
> :last-child {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
> :first-child {
|
||||
width: 50%;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
> :last-child {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,373 @@
|
||||
<template>
|
||||
<div class="x-friend-list" style="padding: 10px 5px">
|
||||
<div
|
||||
class="x-friend-group x-link"
|
||||
style="padding: 0 0 5px"
|
||||
@click="
|
||||
isFriendsGroupMe = !isFriendsGroupMe;
|
||||
saveFriendsGroupStates();
|
||||
">
|
||||
<i class="el-icon-arrow-right" :class="{ rotate: isFriendsGroupMe }"></i>
|
||||
<span style="margin-left: 5px">{{ $t('side_panel.me') }}</span>
|
||||
</div>
|
||||
<div v-show="isFriendsGroupMe">
|
||||
<div class="x-friend-item" @click="showUserDialog(API.currentUser.id)">
|
||||
<div class="avatar" :class="userStatusClass(API.currentUser)">
|
||||
<img v-lazy="userImage(API.currentUser)" />
|
||||
</div>
|
||||
<div class="detail">
|
||||
<span class="name" :style="{ color: API.currentUser.$userColour }">{{
|
||||
API.currentUser.displayName
|
||||
}}</span>
|
||||
<location
|
||||
v-if="isGameRunning && !gameLogDisabled"
|
||||
class="extra"
|
||||
:location="lastLocation.location"
|
||||
:traveling="lastLocationDestination"
|
||||
:link="false"></location>
|
||||
<location
|
||||
v-else-if="
|
||||
isRealInstance(API.currentUser.$locationTag) ||
|
||||
isRealInstance(API.currentUser.$travelingToLocation)
|
||||
"
|
||||
class="extra"
|
||||
:location="API.currentUser.$locationTag"
|
||||
:traveling="API.currentUser.$travelingToLocation"
|
||||
:link="false">
|
||||
</location>
|
||||
<span v-else class="extra">{{ API.currentUser.statusDescription }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-show="vipFriendsByGroupStatus.length"
|
||||
class="x-friend-group x-link"
|
||||
@click="
|
||||
isVIPFriends = !isVIPFriends;
|
||||
saveFriendsGroupStates();
|
||||
">
|
||||
<i class="el-icon-arrow-right" :class="{ rotate: isVIPFriends }"></i>
|
||||
<span style="margin-left: 5px">
|
||||
{{ $t('side_panel.favorite') }} ― {{ vipFriendsByGroupStatus.length }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-show="isVIPFriends">
|
||||
<template v-if="isSidebarDivideByFriendGroup">
|
||||
<div v-for="group in vipFriendsDivideByGroup" :key="group[0].key">
|
||||
<transition name="el-fade-in-linear">
|
||||
<div v-show="group[0].groupName !== ''" style="margin-bottom: 3px">
|
||||
<span class="extra">{{ group[0].groupName }}</span>
|
||||
<span class="extra" style="margin-left: 5px">{{ `(${group.length})` }}</span>
|
||||
</div>
|
||||
</transition>
|
||||
<div v-if="group.length" style="margin-bottom: 10px">
|
||||
<friend-item
|
||||
v-for="friend in group"
|
||||
:key="friend.id"
|
||||
:friend="friend"
|
||||
:hide-nicknames="hideNicknames"
|
||||
@click="showUserDialog(friend.id)"
|
||||
@confirm-delete-friend="$emit('confirm-delete-friend', $event)"></friend-item>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<friend-item
|
||||
v-for="friend in vipFriendsByGroupStatus"
|
||||
v-else
|
||||
:key="friend.id"
|
||||
:friend="friend"
|
||||
:hide-nicknames="hideNicknames"
|
||||
@click="showUserDialog(friend.id)"
|
||||
@confirm-delete-friend="$emit('confirm-delete-friend', $event)">
|
||||
</friend-item>
|
||||
</div>
|
||||
|
||||
<template v-if="isSidebarGroupByInstance && friendsInSameInstance.length">
|
||||
<div class="x-friend-group x-link" @click="toggleSwitchGroupByInstanceCollapsed">
|
||||
<i class="el-icon-arrow-right" :class="{ rotate: !isSidebarGroupByInstanceCollapsed }"></i>
|
||||
<span style="margin-left: 5px"
|
||||
>{{ $t('side_panel.same_instance') }} ― {{ friendsInSameInstance.length }}</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<div v-show="!isSidebarGroupByInstanceCollapsed">
|
||||
<div v-for="friendArr in friendsInSameInstance" :key="friendArr[0].ref.$location.tag">
|
||||
<div style="margin-bottom: 3px">
|
||||
<location
|
||||
class="extra"
|
||||
:location="getFriendsLocations(friendArr)"
|
||||
style="display: inline"></location>
|
||||
<span class="extra" style="margin-left: 5px">{{ `(${friendArr.length})` }}</span>
|
||||
</div>
|
||||
<div v-if="friendArr && friendArr.length">
|
||||
<friend-item
|
||||
v-for="(friend, idx) in friendArr"
|
||||
:key="friend.id"
|
||||
:friend="friend"
|
||||
is-group-by-instance
|
||||
:style="{ 'margin-bottom': idx === friendArr.length - 1 ? '5px' : undefined }"
|
||||
@click="showUserDialog(friend.id)"
|
||||
@confirm-delete-friend="$emit('confirm-delete-friend', $event)">
|
||||
</friend-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div
|
||||
v-show="onlineFriendsByGroupStatus.length"
|
||||
class="x-friend-group x-link"
|
||||
@click="
|
||||
isOnlineFriends = !isOnlineFriends;
|
||||
saveFriendsGroupStates();
|
||||
">
|
||||
<i class="el-icon-arrow-right" :class="{ rotate: isOnlineFriends }"></i>
|
||||
<span style="margin-left: 5px"
|
||||
>{{ $t('side_panel.online') }} ― {{ onlineFriendsByGroupStatus.length }}</span
|
||||
>
|
||||
</div>
|
||||
<div v-show="isOnlineFriends">
|
||||
<friend-item
|
||||
v-for="friend in onlineFriendsByGroupStatus"
|
||||
:key="friend.id"
|
||||
:friend="friend"
|
||||
:hide-nicknames="hideNicknames"
|
||||
@click="showUserDialog(friend.id)"
|
||||
@confirm-delete-friend="$emit('confirm-delete-friend', $event)" />
|
||||
</div>
|
||||
<div
|
||||
v-show="activeFriends.length"
|
||||
class="x-friend-group x-link"
|
||||
@click="
|
||||
isActiveFriends = !isActiveFriends;
|
||||
saveFriendsGroupStates();
|
||||
">
|
||||
<i class="el-icon-arrow-right" :class="{ rotate: isActiveFriends }"></i>
|
||||
<span style="margin-left: 5px">{{ $t('side_panel.active') }} ― {{ activeFriends.length }}</span>
|
||||
</div>
|
||||
<div v-show="isActiveFriends">
|
||||
<friend-item
|
||||
v-for="friend in activeFriends"
|
||||
:key="friend.id"
|
||||
:friend="friend"
|
||||
:hide-nicknames="hideNicknames"
|
||||
@click="showUserDialog(friend.id)"
|
||||
@confirm-delete-friend="$emit('confirm-delete-friend', $event)"></friend-item>
|
||||
</div>
|
||||
<div
|
||||
v-show="offlineFriends.length"
|
||||
class="x-friend-group x-link"
|
||||
@click="
|
||||
isOfflineFriends = !isOfflineFriends;
|
||||
saveFriendsGroupStates();
|
||||
">
|
||||
<i class="el-icon-arrow-right" :class="{ rotate: isOfflineFriends }"></i>
|
||||
<span style="margin-left: 5px">{{ $t('side_panel.offline') }} ― {{ offlineFriends.length }}</span>
|
||||
</div>
|
||||
<div v-show="isOfflineFriends">
|
||||
<friend-item
|
||||
v-for="friend in offlineFriends"
|
||||
:key="friend.id"
|
||||
:friend="friend"
|
||||
:hide-nicknames="hideNicknames"
|
||||
@click="showUserDialog(friend.id)"
|
||||
@confirm-delete-friend="$emit('confirm-delete-friend', $event)"></friend-item>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FriendItem from './FriendItem.vue';
|
||||
import Location from '../common/Location.vue';
|
||||
import configRepository from '../../repository/config';
|
||||
import utils from '../../classes/utils';
|
||||
|
||||
export default {
|
||||
name: 'FriendsSidebar',
|
||||
components: {
|
||||
FriendItem,
|
||||
Location
|
||||
},
|
||||
inject: ['API', 'showUserDialog', 'userImage', 'userStatusClass'],
|
||||
props: {
|
||||
// settings
|
||||
isGameRunning: Boolean,
|
||||
|
||||
isSidebarDivideByFriendGroup: Boolean,
|
||||
isSidebarGroupByInstance: Boolean,
|
||||
gameLogDisabled: Boolean,
|
||||
hideNicknames: Boolean,
|
||||
isHideFriendsInSameInstance: Boolean,
|
||||
|
||||
lastLocation: Object,
|
||||
lastLocationDestination: String,
|
||||
|
||||
activeFriends: Array,
|
||||
offlineFriends: Array,
|
||||
|
||||
vipFriends: Array,
|
||||
onlineFriends: Array,
|
||||
|
||||
groupedByGroupKeyFavoriteFriends: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isFriendsGroupMe: true,
|
||||
isVIPFriends: true,
|
||||
isOnlineFriends: true,
|
||||
isActiveFriends: true,
|
||||
isOfflineFriends: true,
|
||||
isSidebarGroupByInstanceCollapsed: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
friendsInSameInstance() {
|
||||
const friendsList = {};
|
||||
|
||||
const allFriends = [...this.vipFriends, ...this.onlineFriends];
|
||||
allFriends.forEach((friend) => {
|
||||
let locationTag;
|
||||
|
||||
if (friend.ref?.$location.isRealInstance) {
|
||||
locationTag = friend.ref.$location.tag;
|
||||
} else if (this.lastLocation.friendList.has(friend.id)) {
|
||||
let $location = utils.parseLocation(this.lastLocation.location);
|
||||
if ($location.isRealInstance) {
|
||||
if ($location.tag === 'private') {
|
||||
locationTag = this.lastLocation.name;
|
||||
} else {
|
||||
locationTag = $location.tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!locationTag) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!friendsList[locationTag]) {
|
||||
friendsList[locationTag] = [];
|
||||
}
|
||||
friendsList[locationTag].push(friend);
|
||||
});
|
||||
|
||||
const sortedFriendsList = [];
|
||||
for (const group of Object.values(friendsList)) {
|
||||
if (group.length > 1) {
|
||||
sortedFriendsList.push(group.sort((a, b) => a.ref?.$location_at - b.ref?.$location_at));
|
||||
}
|
||||
}
|
||||
|
||||
return sortedFriendsList.sort((a, b) => b.length - a.length);
|
||||
},
|
||||
onlineFriendsByGroupStatus() {
|
||||
if (
|
||||
!this.isSidebarGroupByInstance ||
|
||||
(this.isSidebarGroupByInstance && !this.isHideFriendsInSameInstance)
|
||||
) {
|
||||
return this.onlineFriends;
|
||||
}
|
||||
|
||||
const sameInstanceTag = new Set(
|
||||
this.friendsInSameInstance.flatMap((item) => item.map((friend) => friend.ref?.$location.tag))
|
||||
);
|
||||
|
||||
return this.onlineFriends.filter((item) => !sameInstanceTag.has(item.ref?.$location.tag));
|
||||
},
|
||||
vipFriendsByGroupStatus() {
|
||||
if (
|
||||
!this.isSidebarGroupByInstance ||
|
||||
(this.isSidebarGroupByInstance && !this.isHideFriendsInSameInstance)
|
||||
) {
|
||||
return this.vipFriends;
|
||||
}
|
||||
|
||||
const sameInstanceTag = new Set(
|
||||
this.friendsInSameInstance.flatMap((item) => item.map((friend) => friend.ref?.$location.tag))
|
||||
);
|
||||
|
||||
return this.vipFriends.filter((item) => !sameInstanceTag.has(item.ref?.$location.tag));
|
||||
},
|
||||
// VIP friends divide by group
|
||||
vipFriendsDivideByGroup() {
|
||||
const vipFriendsByGroup = { ...this.groupedByGroupKeyFavoriteFriends };
|
||||
const result = [];
|
||||
|
||||
for (const key in vipFriendsByGroup) {
|
||||
if (Object.prototype.hasOwnProperty.call(vipFriendsByGroup, key)) {
|
||||
const groupFriends = vipFriendsByGroup[key];
|
||||
// sort groupFriends using the order of vipFriends
|
||||
// avoid unnecessary sorting
|
||||
let filteredFriends = this.vipFriends.filter((friend) =>
|
||||
groupFriends.some((item) => item.id === friend.id)
|
||||
);
|
||||
|
||||
if (filteredFriends.length > 0) {
|
||||
const groupName =
|
||||
this.API.favoriteFriendGroups.find((item) => item.key === key)?.displayName || '';
|
||||
result.push(filteredFriends.map((item) => ({ groupName, key, ...item })));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.sort((a, b) => a[0].key.localeCompare(b[0].key));
|
||||
}
|
||||
},
|
||||
created() {
|
||||
configRepository.getBool('VRCX_sidebarGroupByInstanceCollapsed', false).then((value) => {
|
||||
this.isSidebarGroupByInstanceCollapsed = value;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
saveFriendsGroupStates() {
|
||||
configRepository.setBool('VRCX_isFriendsGroupMe', this.isFriendsGroupMe);
|
||||
configRepository.setBool('VRCX_isFriendsGroupFavorites', this.isVIPFriends);
|
||||
configRepository.setBool('VRCX_isFriendsGroupOnline', this.isOnlineFriends);
|
||||
configRepository.setBool('VRCX_isFriendsGroupActive', this.isActiveFriends);
|
||||
configRepository.setBool('VRCX_isFriendsGroupOffline', this.isOfflineFriends);
|
||||
},
|
||||
async loadFriendsGroupStates() {
|
||||
this.isFriendsGroupMe = await configRepository.getBool('VRCX_isFriendsGroupMe', true);
|
||||
this.isVIPFriends = await configRepository.getBool('VRCX_isFriendsGroupFavorites', true);
|
||||
this.isOnlineFriends = await configRepository.getBool('VRCX_isFriendsGroupOnline', true);
|
||||
this.isActiveFriends = await configRepository.getBool('VRCX_isFriendsGroupActive', false);
|
||||
this.isOfflineFriends = await configRepository.getBool('VRCX_isFriendsGroupOffline', false);
|
||||
},
|
||||
isRealInstance(locationTag) {
|
||||
return utils.isRealInstance(locationTag);
|
||||
},
|
||||
toggleSwitchGroupByInstanceCollapsed() {
|
||||
this.isSidebarGroupByInstanceCollapsed = !this.isSidebarGroupByInstanceCollapsed;
|
||||
configRepository.setBool(
|
||||
'VRCX_sidebarGroupByInstanceCollapsed',
|
||||
this.isSidebarGroupByInstanceCollapsed
|
||||
);
|
||||
},
|
||||
getFriendsLocations(friendsArr) {
|
||||
// prevent the instance title display as "Traveling".
|
||||
if (!friendsArr?.length) {
|
||||
return '';
|
||||
}
|
||||
for (const friend of friendsArr) {
|
||||
if (friend.ref?.location !== 'traveling') {
|
||||
return friend.ref.location;
|
||||
}
|
||||
if (utils.isRealInstance(friend.ref?.travelingToLocation)) {
|
||||
return friend.ref.travelingToLocation;
|
||||
}
|
||||
if (this.lastLocation.friendList.has(friend.id)) {
|
||||
return this.lastLocation.name;
|
||||
}
|
||||
}
|
||||
return friendsArr[0].ref?.location;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.x-link:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.x-link:hover span {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
@@ -4,47 +4,50 @@
|
||||
<div
|
||||
:key="getGroupId(group)"
|
||||
class="x-friend-group x-link"
|
||||
:style="{ paddingTop: index === 0 ? '0px' : '10px' }"
|
||||
>
|
||||
:style="{ paddingTop: index === 0 ? '0px' : '10px' }">
|
||||
<div @click="toggleGroupSidebarCollapse(getGroupId(group))" style="display: flex; align-items: center">
|
||||
<i
|
||||
class="el-icon-arrow-right"
|
||||
:style="{
|
||||
transform: groupInstancesCfg[getGroupId(group)].isCollapsed ? '' : 'rotate(90deg)',
|
||||
transition: 'transform 0.3s'
|
||||
}"
|
||||
></i>
|
||||
}"></i>
|
||||
<span style="margin-left: 5px">{{ group[0].group.name }} – {{ group.length }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="!groupInstancesCfg[getGroupId(group)].isCollapsed"
|
||||
v-for="ref in group"
|
||||
:key="ref.instance.id"
|
||||
class="x-friend-item"
|
||||
@click="showGroupDialog(ref.instance.ownerId)"
|
||||
>
|
||||
<div class="avatar">
|
||||
<img v-lazy="ref.group.iconUrl" />
|
||||
<template v-if="!groupInstancesCfg[getGroupId(group)].isCollapsed">
|
||||
<div
|
||||
v-for="ref in group"
|
||||
:key="ref.instance.id"
|
||||
class="x-friend-item"
|
||||
@click="$emit('show-group-dialog', ref.instance.ownerId)">
|
||||
<div class="avatar">
|
||||
<img v-lazy="ref.group.iconUrl" />
|
||||
</div>
|
||||
<div class="detail">
|
||||
<span class="name">
|
||||
<span v-text="ref.group.name"></span>
|
||||
<span style="font-weight: normal; margin-left: 5px"
|
||||
>({{ ref.instance.userCount }}/{{ ref.instance.capacity }})</span
|
||||
>
|
||||
</span>
|
||||
<location class="extra" :location="ref.instance.location" :link="false" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<span class="name">
|
||||
<span v-text="ref.group.name"></span>
|
||||
<span style="font-weight: normal; margin-left: 5px"
|
||||
>({{ ref.instance.userCount }}/{{ ref.instance.capacity }})</span
|
||||
>
|
||||
</span>
|
||||
<location class="extra" :location="ref.instance.location" :link="false" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Location from '../common/Location.vue';
|
||||
|
||||
export default {
|
||||
name: 'GroupsSidebar',
|
||||
components: {
|
||||
Location
|
||||
},
|
||||
props: {
|
||||
groupInstances: {
|
||||
type: Array,
|
||||
|
||||
+13
-24
@@ -36,24 +36,7 @@ html
|
||||
circle
|
||||
style='font-size: 14px; height: 50px; width: 50px')
|
||||
|
||||
el-menu(ref='menu' collapse @select='selectMenu' default-active='feed')
|
||||
mixin menuitem(index, name, icon)
|
||||
el-menu-item(index=index)
|
||||
i(class=icon)
|
||||
template(#title)
|
||||
span= name
|
||||
+menuitem('feed', "{{ $t('nav_tooltip.feed') }}", 'el-icon-news')
|
||||
+menuitem('gameLog', "{{ $t('nav_tooltip.game_log') }}", 'el-icon-s-data')
|
||||
+menuitem('playerList', "{{ $t('nav_tooltip.player_list') }}", 'el-icon-tickets')
|
||||
+menuitem('search', "{{ $t('nav_tooltip.search') }}", 'el-icon-search')
|
||||
+menuitem('favorite', "{{ $t('nav_tooltip.favorites') }}", 'el-icon-star-off')
|
||||
+menuitem('friendLog', "{{ $t('nav_tooltip.friend_log') }}", 'el-icon-notebook-2')
|
||||
+menuitem('moderation', "{{ $t('nav_tooltip.moderation') }}", 'el-icon-finished')
|
||||
+menuitem('notification', "{{ $t('nav_tooltip.notification') }}", 'el-icon-bell')
|
||||
+menuitem('friendsList', "{{ $t('nav_tooltip.friend_list') }}", 'el-icon-s-management')
|
||||
+menuitem('charts', "{{ $t('nav_tooltip.charts') }}", 'el-icon-data-analysis')
|
||||
+menuitem('profile', "{{ $t('nav_tooltip.profile') }}", 'el-icon-user')
|
||||
+menuitem('settings', "{{ $t('nav_tooltip.settings') }}", 'el-icon-s-tools')
|
||||
nav-menu(ref='menu' @select='selectMenu' :menu-active-index='menuActiveIndex')
|
||||
|
||||
//- ### Tabs ###
|
||||
template(v-if='API.isLoggedIn')
|
||||
@@ -83,7 +66,7 @@ html
|
||||
|
||||
//- moderation
|
||||
moderation-tab(
|
||||
v-if='$refs.menu?.activeIndex === "moderation"'
|
||||
v-if='menuActiveIndex === "moderation"'
|
||||
:table-data='playerModerationTable'
|
||||
:shift-held='shiftHeld'
|
||||
:hide-tooltips='hideTooltips')
|
||||
@@ -103,20 +86,26 @@ html
|
||||
//- charts
|
||||
keep-alive
|
||||
charts-tab(
|
||||
v-if='$refs.menu?.activeIndex === "charts"'
|
||||
v-if='menuActiveIndex === "charts"'
|
||||
:get-world-name='getWorldName'
|
||||
:is-dark-mode='isDarkMode'
|
||||
:dt-hour12='dtHour12'
|
||||
@open-previous-instance-info-dialog='showPreviousInstanceInfoDialog'
|
||||
:friends-map='friends'
|
||||
:local-favorite-friends='localFavoriteFriends')
|
||||
:local-favorite-friends='localFavoriteFriends'
|
||||
@open-previous-instance-info-dialog='showPreviousInstanceInfoDialog')
|
||||
|
||||
//- settings
|
||||
include ./mixins/tabs/settings.pug
|
||||
+settingsTab
|
||||
|
||||
include ./mixins/friendsListSidebar.pug
|
||||
+friendsListSidebar
|
||||
side-bar(
|
||||
v-show='isSideBarTabShow'
|
||||
v-bind='sideBarTabProps'
|
||||
@show-group-dialog='showGroupDialog'
|
||||
@quick-search-change='quickSearchChange'
|
||||
@direct-access-paste='directAccessPaste'
|
||||
@refresh-friends-list='refreshFriendsList'
|
||||
@confirm-delete-friend='confirmDeleteFriend')
|
||||
|
||||
//- ## Dialogs ## -\\
|
||||
include ./mixins/dialogs/userDialog.pug
|
||||
|
||||
@@ -1,296 +0,0 @@
|
||||
mixin friendsListSidebar
|
||||
#aside.x-aside-container(
|
||||
:style='{ width: `${asideWidth}px` }'
|
||||
v-show='$refs.menu && !($refs.menu.activeIndex === "friendsList" || $refs.menu.activeIndex === "charts") ')
|
||||
div(style='display: flex; align-items: baseline')
|
||||
el-select(
|
||||
v-model='quickSearch'
|
||||
clearable
|
||||
:placeholder='$t("side_panel.search_placeholder")'
|
||||
filterable
|
||||
remote
|
||||
:remote-method='quickSearchRemoteMethod'
|
||||
popper-class='x-quick-search'
|
||||
@change='quickSearchChange'
|
||||
@visible-change='quickSearchVisibleChange'
|
||||
style='flex: 1; padding: 10px')
|
||||
el-option(v-for='item in quickSearchItems' :key='item.value' :value='item.value' :label='item.label')
|
||||
.x-friend-item
|
||||
template(v-if='item.ref')
|
||||
.detail
|
||||
span.name(v-text='item.ref.displayName' :style='{ color: item.ref.$userColour }')
|
||||
span.extra(v-if='!item.ref.isFriend')
|
||||
span.extra(v-else-if='item.ref.state === "offline"') {{ $t('side_panel.search_result_active') }}
|
||||
span.extra(v-else-if='item.ref.state === "active"') {{ $t('side_panel.search_result_offline') }}
|
||||
location.extra(
|
||||
v-else
|
||||
:location='item.ref.location'
|
||||
:traveling='item.ref.travelingToLocation'
|
||||
:link='false')
|
||||
img.avatar(v-lazy='userImage(item.ref)')
|
||||
span(v-else) {{ $t('side_panel.search_result_more') }} #[span(v-text='item.label' style='font-weight: bold')]
|
||||
el-tooltip(placement='bottom' :content='$t("side_panel.direct_access_tooltip")' :disabled='hideTooltips')
|
||||
el-button(type='default' @click='directAccessPaste' size='mini' icon='el-icon-discover' circle)
|
||||
el-tooltip(placement='bottom' :content='$t("side_panel.refresh_tooltip")' :disabled='hideTooltips')
|
||||
el-button(
|
||||
type='default'
|
||||
@click='refreshFriendsList'
|
||||
:loading='API.isRefreshFriendsLoading'
|
||||
size='mini'
|
||||
icon='el-icon-refresh'
|
||||
circle
|
||||
style='margin-right: 10px')
|
||||
el-tabs.zero-margin-tabs(stretch style='height: calc(100% - 60px); margin-top: 5px')
|
||||
el-tab-pane
|
||||
template(#label)
|
||||
span {{ $t('side_panel.friends') }}
|
||||
span(style='color: #909399; font-size: 12px; margin-left: 10px') ({{ onlineFriendCount }}/{{ friends.size }})
|
||||
.x-friend-list(style='padding: 10px 5px')
|
||||
.x-friend-group.x-link(
|
||||
@click='isFriendsGroupMe = !isFriendsGroupMe; saveFriendsGroupStates()'
|
||||
style='padding: 0px 0px 5px')
|
||||
i.el-icon-arrow-right(:class='{ rotate: isFriendsGroupMe }')
|
||||
span(style='margin-left: 5px') {{ $t('side_panel.me') }}
|
||||
div(v-show='isFriendsGroupMe')
|
||||
.x-friend-item(:key='API.currentUser.id' @click='showUserDialog(API.currentUser.id)')
|
||||
.avatar(:class='userStatusClass(API.currentUser)')
|
||||
img(v-lazy='userImage(API.currentUser)')
|
||||
.detail
|
||||
span.name(
|
||||
v-text='API.currentUser.displayName'
|
||||
:style='{ color: API.currentUser.$userColour }')
|
||||
location.extra(
|
||||
v-if='isGameRunning && !gameLogDisabled'
|
||||
:location='lastLocation.location'
|
||||
:traveling='lastLocationDestination'
|
||||
:link='false')
|
||||
location.extra(
|
||||
v-else-if='isRealInstance(API.currentUser.$locationTag) || isRealInstance(API.currentUser.$travelingToLocation)'
|
||||
:location='API.currentUser.$locationTag'
|
||||
:traveling='API.currentUser.$travelingToLocation'
|
||||
:link='false')
|
||||
span.extra(v-else v-text='API.currentUser.statusDescription')
|
||||
.x-friend-group.x-link(
|
||||
@click='isVIPFriends = !isVIPFriends; saveFriendsGroupStates()'
|
||||
v-show='vipFriendsByGroupStatus.length')
|
||||
i.el-icon-arrow-right(:class='{ rotate: isVIPFriends }')
|
||||
span(style='margin-left: 5px') {{ $t('side_panel.favorite') }} ― {{ vipFriendsByGroupStatus.length }}
|
||||
div(v-show='isVIPFriends')
|
||||
template(v-if='isSidebarDivideByFriendGroup')
|
||||
div(v-for='(group, idx) in vipFriendsDivideByGroup' :key='idx')
|
||||
div(style='margin-bottom: 3px')
|
||||
span.extra {{ group.displayName }}
|
||||
span.extra(style='margin-left: 5px') {{ `(${group.value.length})` }}
|
||||
div(style='margin-bottom: 10px')
|
||||
.x-friend-item(
|
||||
v-if='group.value && group.value.length'
|
||||
v-for='friend in group.value'
|
||||
:key='friend.id'
|
||||
@click='showUserDialog(friend.id)')
|
||||
template(v-if='friend.ref')
|
||||
.avatar(:class='userStatusClass(friend.ref, friend.pendingOffline)')
|
||||
img(v-lazy='userImage(friend.ref)')
|
||||
.detail
|
||||
span.name(
|
||||
v-if='!hideNicknames && friend.$nickName'
|
||||
:style='{ color: friend.ref.$userColour }') {{ friend.ref.displayName }} ({{ friend.$nickName }})
|
||||
span.name(
|
||||
v-else
|
||||
v-text='friend.ref.displayName'
|
||||
:style='{ color: friend.ref.$userColour }')
|
||||
span.extra(v-if='friend.pendingOffline') #[i.el-icon-warning-outline] {{ $t('side_panel.pending_offline') }}
|
||||
location.extra(
|
||||
v-else
|
||||
:location='friend.ref.location'
|
||||
:traveling='friend.ref.travelingToLocation'
|
||||
:link='false')
|
||||
template(v-else)
|
||||
span(v-text='friend.name || friend.id')
|
||||
el-button(
|
||||
type='text'
|
||||
icon='el-icon-close'
|
||||
size='mini'
|
||||
@click.stop='confirmDeleteFriend(friend.id)'
|
||||
style='margin-left: 5px')
|
||||
template(v-else)
|
||||
.x-friend-item(
|
||||
v-for='friend in vipFriendsByGroupStatus'
|
||||
:key='friend.id'
|
||||
@click='showUserDialog(friend.id)')
|
||||
template(v-if='friend.ref')
|
||||
.avatar(:class='userStatusClass(friend.ref, friend.pendingOffline)')
|
||||
img(v-lazy='userImage(friend.ref)')
|
||||
.detail
|
||||
span.name(
|
||||
v-if='!hideNicknames && friend.$nickName'
|
||||
:style='{ color: friend.ref.$userColour }') {{ friend.ref.displayName }} ({{ friend.$nickName }})
|
||||
span.name(
|
||||
v-else
|
||||
v-text='friend.ref.displayName'
|
||||
:style='{ color: friend.ref.$userColour }')
|
||||
span.extra(v-if='friend.pendingOffline') #[i.el-icon-warning-outline] {{ $t('side_panel.pending_offline') }}
|
||||
location.extra(
|
||||
v-else
|
||||
:location='friend.ref.location'
|
||||
:traveling='friend.ref.travelingToLocation'
|
||||
:link='false')
|
||||
template(v-else)
|
||||
span(v-text='friend.name || friend.id')
|
||||
el-button(
|
||||
type='text'
|
||||
icon='el-icon-close'
|
||||
size='mini'
|
||||
@click.stop='confirmDeleteFriend(friend.id)'
|
||||
style='margin-left: 5px')
|
||||
//- Group By Instance
|
||||
template(v-if='isSidebarGroupByInstance && friendsInSameInstance.length')
|
||||
.x-friend-group.x-link(@click='toggleSwitchGroupByInstanceCollapsed')
|
||||
i.el-icon-arrow-right(:class='{ rotate: !isSidebarGroupByInstanceCollapsed }')
|
||||
span(style='margin-left: 5px') {{ $t('side_panel.same_instance') }} ― {{ friendsInSameInstance.length }}
|
||||
div(v-show='!isSidebarGroupByInstanceCollapsed')
|
||||
div(v-for='friendArr in friendsInSameInstance' :key='friendArr[0].ref?.$location.tag')
|
||||
div(style='margin-bottom: 3px')
|
||||
location.extra(:location='getFriendsLocations(friendArr)')
|
||||
span.extra(style='margin-left: 5px') {{ `(${friendArr.length})` }}
|
||||
div
|
||||
.x-friend-item(
|
||||
v-if='friendArr && friendArr.length'
|
||||
v-for='(friend, idx) in friendArr'
|
||||
:key='friend.id'
|
||||
@click='showUserDialog(friend.id)'
|
||||
:style='{ "margin-bottom": idx === friendArr.length - 1 ? "5px" : undefined }')
|
||||
template(v-if='friend.ref')
|
||||
.avatar(:class='userStatusClass(friend.ref, friend.pendingOffline)')
|
||||
img(v-lazy='userImage(friend.ref)')
|
||||
.detail
|
||||
span.name(style='display: flex; align-items: center')
|
||||
span(
|
||||
v-if='!hideNicknames && friend.$nickName'
|
||||
:style='{ color: friend.ref.$userColour }') {{ friend.ref.displayName }} ({{ friend.$nickName }})
|
||||
span(
|
||||
v-else
|
||||
v-text='friend.ref.displayName'
|
||||
:style='{ color: friend.ref.$userColour }')
|
||||
span(v-if='friend.isVIP' style='margin-left: 2px') ⭐
|
||||
span.extra(v-if='friend.pendingOffline') #[i.el-icon-warning-outline] {{ $t('side_panel.pending_offline') }}
|
||||
template(v-else)
|
||||
template(v-if='friend.ref.location === "traveling"')
|
||||
i.el-icon.el-icon-loading(
|
||||
style='display: inline-block; margin-right: 5px')
|
||||
timer.extra(
|
||||
:epoch='friend.ref?.$travelingToTime'
|
||||
style='display: inline-block; overflow: unset')
|
||||
template(v-else)
|
||||
timer.extra(:epoch='friend.ref?.$location_at')
|
||||
template(v-else)
|
||||
span(v-text='friend.name || friend.id')
|
||||
el-button(
|
||||
type='text'
|
||||
icon='el-icon-close'
|
||||
size='mini'
|
||||
@click.stop='confirmDeleteFriend(friend.id)'
|
||||
style='margin-left: 5px')
|
||||
|
||||
.x-friend-group.x-link(
|
||||
@click='isOnlineFriends = !isOnlineFriends; saveFriendsGroupStates()'
|
||||
v-show='onlineFriendsByGroupStatus.length')
|
||||
i.el-icon-arrow-right(:class='{ rotate: isOnlineFriends }')
|
||||
span(style='margin-left: 5px') {{ $t('side_panel.online') }} ― {{ onlineFriendsByGroupStatus.length }}
|
||||
div(v-show='isOnlineFriends')
|
||||
.x-friend-item(
|
||||
v-for='friend in onlineFriendsByGroupStatus'
|
||||
:key='friend.id'
|
||||
@click='showUserDialog(friend.id)')
|
||||
template(v-if='friend.ref')
|
||||
.avatar(:class='userStatusClass(friend.ref, friend.pendingOffline)')
|
||||
img(v-lazy='userImage(friend.ref)')
|
||||
.detail
|
||||
span.name(
|
||||
v-if='!hideNicknames && friend.$nickName'
|
||||
:style='{ color: friend.ref.$userColour }') {{ friend.ref.displayName }} ({{ friend.$nickName }})
|
||||
span.name(
|
||||
v-else
|
||||
v-text='friend.ref.displayName'
|
||||
:style='{ color: friend.ref.$userColour }')
|
||||
span.extra(v-if='friend.pendingOffline') #[i.el-icon-warning-outline] {{ $t('side_panel.pending_offline') }}
|
||||
location.extra(
|
||||
v-else
|
||||
:location='friend.ref.location'
|
||||
:traveling='friend.ref.travelingToLocation'
|
||||
:link='false')
|
||||
template(v-else)
|
||||
span(v-text='friend.name || friend.id')
|
||||
el-button(
|
||||
type='text'
|
||||
icon='el-icon-close'
|
||||
size='mini'
|
||||
@click.stop='confirmDeleteFriend(friend.id)'
|
||||
style='margin-left: 5px')
|
||||
.x-friend-group.x-link(
|
||||
@click='isActiveFriends = !isActiveFriends; saveFriendsGroupStates()'
|
||||
v-show='activeFriends.length')
|
||||
i.el-icon-arrow-right(:class='{ rotate: isActiveFriends }')
|
||||
span(style='margin-left: 5px') {{ $t('side_panel.active') }} ― {{ activeFriends.length }}
|
||||
div(v-show='isActiveFriends')
|
||||
.x-friend-item(
|
||||
v-for='friend in activeFriends'
|
||||
:key='friend.id'
|
||||
@click='showUserDialog(friend.id)')
|
||||
template(v-if='friend.ref')
|
||||
.avatar
|
||||
img(v-lazy='userImage(friend.ref)')
|
||||
.detail
|
||||
span.name(
|
||||
v-if='!hideNicknames && friend.$nickName'
|
||||
:style='{ color: friend.ref.$userColour }') {{ friend.ref.displayName }} ({{ friend.$nickName }})
|
||||
span.name(
|
||||
v-else
|
||||
v-text='friend.ref.displayName'
|
||||
:style='{ color: friend.ref.$userColour }')
|
||||
span.extra(v-text='friend.ref.statusDescription' :link='false')
|
||||
template(v-else)
|
||||
span(v-text='friend.name || friend.id')
|
||||
el-button(
|
||||
type='text'
|
||||
icon='el-icon-close'
|
||||
size='mini'
|
||||
@click.stop='confirmDeleteFriend(friend.id)'
|
||||
style='margin-left: 5px')
|
||||
.x-friend-group.x-link(
|
||||
@click='isOfflineFriends = !isOfflineFriends; saveFriendsGroupStates()'
|
||||
v-show='offlineFriends.length')
|
||||
i.el-icon-arrow-right(:class='{ rotate: isOfflineFriends }')
|
||||
span(style='margin-left: 5px') {{ $t('side_panel.offline') }} ― {{ offlineFriends.length }}
|
||||
div(v-show='isOfflineFriends')
|
||||
.x-friend-item(
|
||||
v-for='friend in offlineFriends'
|
||||
:key='friend.id'
|
||||
@click='showUserDialog(friend.id)')
|
||||
template(v-if='friend.ref')
|
||||
.avatar
|
||||
img(v-lazy='userImage(friend.ref)')
|
||||
.detail
|
||||
span.name(
|
||||
v-if='!hideNicknames && friend.$nickName'
|
||||
:style='{ color: friend.ref.$userColour }') {{ friend.ref.displayName }} ({{ friend.$nickName }})
|
||||
span.name(
|
||||
v-else
|
||||
v-text='friend.ref.displayName'
|
||||
:style='{ color: friend.ref.$userColour }')
|
||||
span.extra(v-text='friend.ref.statusDescription')
|
||||
template(v-else)
|
||||
span(v-text='friend.name || friend.id')
|
||||
el-button(
|
||||
type='text'
|
||||
icon='el-icon-close'
|
||||
size='mini'
|
||||
@click.stop='confirmDeleteFriend(friend.id)'
|
||||
style='margin-left: 5px')
|
||||
el-tab-pane(lazy)
|
||||
template(#label)
|
||||
span {{ $t('side_panel.groups') }}
|
||||
span(style='color: #909399; font-size: 12px; margin-left: 10px') ({{ groupInstances.length }})
|
||||
groups-sidebar(
|
||||
:group-instances='groupInstances'
|
||||
:group-order='inGameGroupOrder'
|
||||
@show-group-dialog='showGroupDialog')
|
||||
@@ -1,5 +1,5 @@
|
||||
mixin favoritesTab
|
||||
.x-container(v-show='$refs.menu && $refs.menu.activeIndex === "favorite"')
|
||||
.x-container(v-show='menuActiveIndex === "favorite"')
|
||||
div(style='font-size: 13px; position: absolute; display: flex; right: 0; z-index: 1; margin-right: 15px')
|
||||
div(v-if='editFavoritesMode' style='display: inline-block; margin-right: 10px')
|
||||
el-button(size='small' @click='clearBulkFavoriteSelection') {{ $t('view.favorite.clear') }}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mixin feedTab
|
||||
.x-container(v-show='$refs.menu && $refs.menu.activeIndex === \'feed\'')
|
||||
.x-container(v-show='menuActiveIndex === "feed"')
|
||||
div(style='margin: 0 0 10px; display: flex; align-items: center')
|
||||
div(style='flex: none; margin-right: 10px; display: flex; align-items: center')
|
||||
el-tooltip(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mixin friendLogTab
|
||||
.x-container(v-if='$refs.menu && $refs.menu.activeIndex === "friendLog"')
|
||||
.x-container(v-if='menuActiveIndex === "friendLog"')
|
||||
data-tables(v-bind='friendLogTable' ref='friendLogTableRef')
|
||||
template(#tool)
|
||||
div(style='margin: 0 0 10px; display: flex; align-items: center')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mixin friendsListTab
|
||||
.x-container(v-show='$refs.menu && $refs.menu.activeIndex === "friendsList"')
|
||||
.x-container(v-show='menuActiveIndex === "friendsList"')
|
||||
div(style='padding: 0px 10px 0px 10px')
|
||||
span.header {{ $t('view.friend_list.header') }}
|
||||
div(style='float: right; font-size: 13px')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mixin gameLogTab
|
||||
.x-container(v-show='$refs.menu && $refs.menu.activeIndex === \'gameLog\'')
|
||||
.x-container(v-show='menuActiveIndex === "gameLog"')
|
||||
data-tables(v-bind='gameLogTable' v-loading='gameLogTable.loading')
|
||||
template(#tool)
|
||||
div(style='margin: 0 0 10px; display: flex; align-items: center')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mixin notificationsTab
|
||||
.x-container(v-if='$refs.menu && $refs.menu.activeIndex === "notification"' v-loading='API.isNotificationsLoading')
|
||||
.x-container(v-if='menuActiveIndex === "notification"' v-loading='API.isNotificationsLoading')
|
||||
data-tables.notification-table(v-bind='notificationTable' ref='notificationTableRef')
|
||||
template(#tool)
|
||||
div(style='margin: 0 0 10px; display: flex; align-items: center')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mixin playerListTab
|
||||
.x-container(v-show='$refs.menu && $refs.menu.activeIndex === \'playerList\'' style='padding-top: 5px')
|
||||
.x-container(v-show='menuActiveIndex === "playerList"' style='padding-top: 5px')
|
||||
div(style='display: flex; flex-direction: column; height: 100%')
|
||||
div(v-if='currentInstanceWorld.ref.id' style='display: flex')
|
||||
el-popover(placement='right' width='500px' trigger='click' style='height: 120px')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mixin profileTab
|
||||
.x-container(v-if='$refs.menu && $refs.menu.activeIndex === "profile"')
|
||||
.x-container(v-if='menuActiveIndex === "profile"')
|
||||
.options-container(style='margin-top: 0')
|
||||
span.header {{ $t('view.profile.profile.header') }}
|
||||
.x-friend-list(style='margin-top: 10px')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mixin searchTab
|
||||
.x-container(v-show='$refs.menu && $refs.menu.activeIndex === \'search\'')
|
||||
.x-container(v-show='menuActiveIndex === "search"')
|
||||
div(style='margin: 0 0 10px; display: flex; align-items: center')
|
||||
el-input(
|
||||
v-model='searchText'
|
||||
@@ -14,7 +14,10 @@ mixin searchTab
|
||||
circle
|
||||
style='flex: none; margin-left: 10px')
|
||||
el-tabs(ref='searchTab' type='card' style='margin-top: 15px' @tab-click='searchText = ""')
|
||||
el-tab-pane(:label='$t("view.search.user.header")' v-loading='isSearchUserLoading' style='min-height: 60px')
|
||||
el-tab-pane(
|
||||
:label='$t("view.search.user.header")'
|
||||
v-loading='isSearchUserLoading'
|
||||
style='min-height: 60px')
|
||||
el-checkbox(v-model='searchUserByBio' style='margin-left: 10px') {{ $t('view.search.user.search_by_bio') }}
|
||||
el-checkbox(v-model='searchUserSortByLastLoggedIn' style='margin-left: 10px') {{ $t('view.search.user.sort_by_last_logged_in') }}
|
||||
.x-friend-list(style='min-height: 500px')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mixin settingsTab
|
||||
.x-container(v-if='$refs.menu && $refs.menu.activeIndex === "settings"')
|
||||
.x-container(v-if='menuActiveIndex === "settings"')
|
||||
.options-container(style='margin-top: 0; padding: 5px')
|
||||
span.header {{ $t('view.settings.header') }}
|
||||
el-tabs(type='card' style='height: calc(100% - 51px)')
|
||||
|
||||
@@ -476,3 +476,11 @@ button {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
// Date picker end
|
||||
|
||||
// el-skeleton
|
||||
.el-skeleton.is-animated .el-skeleton__item {
|
||||
background: linear-gradient(90deg, #333 25%, #555 37%, #333 63%);
|
||||
background-size: 400% 100%;
|
||||
animation: el-skeleton-loading 1.4s ease infinite;
|
||||
}
|
||||
// el-sekeleton end
|
||||
@@ -2057,3 +2057,8 @@ i.x-user-status {
|
||||
.el-month-table td .cell:hover {
|
||||
color: rgb(48, 46, 53);
|
||||
}
|
||||
.el-skeleton.is-animated .el-skeleton__item {
|
||||
background: linear-gradient(90deg, #302E34 25%, #423F46 37%, #302E34 63%);
|
||||
background-size: 400% 100%;
|
||||
animation: el-skeleton-loading 1.4s ease infinite;
|
||||
}
|
||||
@@ -413,3 +413,9 @@ input[type='checkbox']:checked + .el-switch__core {
|
||||
.el-date-table td.disabled div {
|
||||
background-color: #3a2b2b
|
||||
}
|
||||
|
||||
.el-skeleton.is-animated .el-skeleton__item {
|
||||
background: linear-gradient(90deg, #4a3d3d 25%, #665252 37%, #4a3d3d 63%);
|
||||
background-size: 400% 100%;
|
||||
animation: el-skeleton-loading 1.4s ease infinite;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<el-menu
|
||||
ref="navRef"
|
||||
collapse
|
||||
@select="$emit('select', $event)"
|
||||
:default-active="menuActiveIndex"
|
||||
:collapse-transition="false">
|
||||
<el-menu-item index="feed">
|
||||
<i class="el-icon-news"></i>
|
||||
<template slot="title">
|
||||
<span>{{ $t('nav_tooltip.feed') }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="gameLog">
|
||||
<i class="el-icon-s-data"></i>
|
||||
<template slot="title">
|
||||
<span>{{ $t('nav_tooltip.game_log') }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="playerList">
|
||||
<i class="el-icon-tickets"></i>
|
||||
<template slot="title">
|
||||
<span>{{ $t('nav_tooltip.player_list') }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="search">
|
||||
<i class="el-icon-search"></i>
|
||||
<template slot="title">
|
||||
<span>{{ $t('nav_tooltip.search') }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="favorite">
|
||||
<i class="el-icon-star-off"></i>
|
||||
<template slot="title">
|
||||
<span>{{ $t('nav_tooltip.favorites') }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="friendLog">
|
||||
<i class="el-icon-notebook-2"></i>
|
||||
<template slot="title">
|
||||
<span>{{ $t('nav_tooltip.friend_log') }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="moderation">
|
||||
<i class="el-icon-finished"></i>
|
||||
<template slot="title">
|
||||
<span>{{ $t('nav_tooltip.moderation') }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="notification">
|
||||
<i class="el-icon-bell"></i>
|
||||
<template slot="title">
|
||||
<span>{{ $t('nav_tooltip.notification') }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="friendsList">
|
||||
<i class="el-icon-s-management"></i>
|
||||
<template slot="title">
|
||||
<span>{{ $t('nav_tooltip.friend_list') }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="charts">
|
||||
<i class="el-icon-data-analysis"></i>
|
||||
<template slot="title">
|
||||
<span>{{ $t('nav_tooltip.charts') }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="profile">
|
||||
<i class="el-icon-user"></i>
|
||||
<template slot="title">
|
||||
<span>{{ $t('nav_tooltip.profile') }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="settings">
|
||||
<i class="el-icon-s-tools"></i>
|
||||
<template slot="title">
|
||||
<span>{{ $t('nav_tooltip.settings') }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'NavMenu',
|
||||
props: {
|
||||
menuActiveIndex: {
|
||||
type: String,
|
||||
default: 'feed'
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div id="aside" class="x-aside-container">
|
||||
<div style="display: flex; align-items: baseline">
|
||||
<el-select
|
||||
value=""
|
||||
clearable
|
||||
:placeholder="$t('side_panel.search_placeholder')"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="quickSearchRemoteMethod"
|
||||
popper-class="x-quick-search"
|
||||
style="flex: 1; padding: 10px"
|
||||
@change="$emit('quick-search-change', $event)">
|
||||
<el-option v-for="item in quickSearchItems" :key="item.value" :value="item.value" :label="item.label">
|
||||
<div class="x-friend-item">
|
||||
<template v-if="item.ref">
|
||||
<div class="detail">
|
||||
<span class="name" :style="{ color: item.ref.$userColour }">{{
|
||||
item.ref.displayName
|
||||
}}</span>
|
||||
<span v-if="!item.ref.isFriend" class="extra"></span>
|
||||
<span v-else-if="item.ref.state === 'offline'" class="extra">{{
|
||||
$t('side_panel.search_result_active')
|
||||
}}</span>
|
||||
<span v-else-if="item.ref.state === 'active'" class="extra">{{
|
||||
$t('side_panel.search_result_offline')
|
||||
}}</span>
|
||||
<location
|
||||
v-else
|
||||
class="extra"
|
||||
:location="item.ref.location"
|
||||
:traveling="item.ref.travelingToLocation"
|
||||
:link="false"></location>
|
||||
</div>
|
||||
<img class="avatar" v-lazy="userImage(item.ref)" />
|
||||
</template>
|
||||
<span v-else>
|
||||
{{ $t('side_panel.search_result_more') }}
|
||||
<span style="font-weight: bold">{{ item.label }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-tooltip placement="bottom" :content="$t('side_panel.direct_access_tooltip')" :disabled="hideTooltips">
|
||||
<el-button
|
||||
type="default"
|
||||
size="mini"
|
||||
icon="el-icon-discover"
|
||||
circle
|
||||
@click="$emit('direct-access-paste')"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="bottom" :content="$t('side_panel.refresh_tooltip')" :disabled="hideTooltips">
|
||||
<el-button
|
||||
type="default"
|
||||
:loading="API.isRefreshFriendsLoading"
|
||||
size="mini"
|
||||
icon="el-icon-refresh"
|
||||
circle
|
||||
style="margin-right: 10px"
|
||||
@click="$emit('refresh-friends-list')"></el-button>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-tabs class="zero-margin-tabs" stretch style="height: calc(100% - 60px); margin-top: 5px">
|
||||
<el-tab-pane>
|
||||
<template slot="label">
|
||||
<span>{{ $t('side_panel.friends') }}</span>
|
||||
<span style="color: #909399; font-size: 12px; margin-left: 10px">
|
||||
({{ onlineFriendCount }}/{{ friends.size }})
|
||||
</span>
|
||||
</template>
|
||||
<el-backtop target=".zero-margin-tabs .el-tabs__content" :bottom="20" :right="20"></el-backtop>
|
||||
<friends-sidebar
|
||||
@confirm-delete-friend="$emit('confirm-delete-friend', $event)"
|
||||
:is-game-running="isGameRunning"
|
||||
:is-sidebar-divide-by-friend-group="isSidebarDivideByFriendGroup"
|
||||
:is-sidebar-group-by-instance="isSidebarGroupByInstance"
|
||||
:game-log-disabled="gameLogDisabled"
|
||||
:last-location="lastLocation"
|
||||
:last-location-destination="lastLocationDestination"
|
||||
:hide-nicknames="hideNicknames"
|
||||
:active-friends="activeFriends"
|
||||
:offline-friends="offlineFriends"
|
||||
:online-friends="onlineFriends"
|
||||
:vip-friends="vipFriends"
|
||||
:is-hide-friends-in-same-instance="isHideFriendsInSameInstance"
|
||||
:grouped-by-group-key-favorite-friends="groupedByGroupKeyFavoriteFriends"></friends-sidebar>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane lazy>
|
||||
<template slot="label">
|
||||
<span>{{ $t('side_panel.groups') }}</span>
|
||||
<span style="color: #909399; font-size: 12px; margin-left: 10px">
|
||||
({{ groupInstances.length }})
|
||||
</span>
|
||||
</template>
|
||||
<groups-sidebar
|
||||
:group-instances="groupInstances"
|
||||
:group-order="inGameGroupOrder"
|
||||
@show-group-dialog="$emit('show-group-dialog', $event)"></groups-sidebar>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FriendsSidebar from '../components/sidebar/FriendsSidebar.vue';
|
||||
import GroupsSidebar from '../components/sidebar/GroupsSidebar.vue';
|
||||
import Location from '../components/common/Location.vue';
|
||||
|
||||
export default {
|
||||
name: 'SideBar',
|
||||
inject: ['API', 'userImage'],
|
||||
components: {
|
||||
FriendsSidebar,
|
||||
GroupsSidebar,
|
||||
Location
|
||||
},
|
||||
props: {
|
||||
// settings
|
||||
// remove these props when have a state manager.
|
||||
hideTooltips: Boolean,
|
||||
isGameRunning: Boolean,
|
||||
isSidebarDivideByFriendGroup: Boolean,
|
||||
isSidebarGroupByInstance: Boolean,
|
||||
gameLogDisabled: Boolean,
|
||||
hideNicknames: Boolean,
|
||||
isHideFriendsInSameInstance: Boolean,
|
||||
|
||||
quickSearchRemoteMethod: Function,
|
||||
quickSearchItems: Array,
|
||||
onlineFriendCount: Number,
|
||||
friends: Map,
|
||||
|
||||
lastLocation: Object,
|
||||
lastLocationDestination: String,
|
||||
|
||||
// friends
|
||||
vipFriends: Array,
|
||||
onlineFriends: Array,
|
||||
|
||||
// no
|
||||
activeFriends: Array,
|
||||
offlineFriends: Array,
|
||||
groupInstances: Array,
|
||||
inGameGroupOrder: Array,
|
||||
groupedByGroupKeyFavoriteFriends: Object
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* your component styles here */
|
||||
</style>
|
||||
@@ -6,16 +6,14 @@
|
||||
width="800px"
|
||||
@close="$emit('update:visible', false)"
|
||||
:fullscreen="fullscreen"
|
||||
destroy-on-close
|
||||
>
|
||||
destroy-on-close>
|
||||
<div style="display: flex; align-items: center; justify-content: space-between">
|
||||
<location :location="location.tag" style="font-size: 14px"></location>
|
||||
<el-input
|
||||
v-model="dataTable.filters[0].value"
|
||||
:placeholder="$t('dialog.previous_instances.search_placeholder')"
|
||||
style="width: 150px"
|
||||
clearable
|
||||
></el-input>
|
||||
clearable></el-input>
|
||||
</div>
|
||||
<data-tables v-loading="loading" v-bind="dataTable" style="margin-top: 10px">
|
||||
<el-table-column :label="$t('table.previous_instances.date')" prop="created_at" sortable width="110">
|
||||
@@ -63,9 +61,13 @@
|
||||
import utils from '../../classes/utils';
|
||||
import database from '../../repository/database';
|
||||
import dayjs from 'dayjs';
|
||||
import Location from '../../components/common/Location.vue';
|
||||
|
||||
export default {
|
||||
name: 'PreviousInstanceInfo',
|
||||
components: {
|
||||
Location
|
||||
},
|
||||
inject: ['adjustDialogZ'],
|
||||
props: {
|
||||
visible: {
|
||||
|
||||
Reference in New Issue
Block a user