mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-17 05:43:51 +02:00
feat: groups sidebar collapsible (#1094)
* wip * wip * add prettier formatter config for pug files * feat: groups sidebar collapsible (#1079) * rm old code
This commit is contained in:
@@ -8,5 +8,24 @@
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"vueIndentScriptAndStyle": true,
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
"endOfLine": "auto",
|
||||
"plugins": [
|
||||
"@prettier/plugin-pug"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.pug",
|
||||
"options": {
|
||||
"pugPrintWidth": 120,
|
||||
"pugAttributeSeparator": "none",
|
||||
"pugBracketSameLine": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.vue",
|
||||
"options": {
|
||||
"printWidth": 120
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
37
package-lock.json
generated
37
package-lock.json
generated
@@ -20,6 +20,7 @@
|
||||
"@fontsource/noto-sans-sc": "^5.1.0",
|
||||
"@fontsource/noto-sans-tc": "^5.1.0",
|
||||
"@infolektuell/noto-color-emoji": "^0.2.0",
|
||||
"@prettier/plugin-pug": "^3.2.0",
|
||||
"animate.css": "^4.1.1",
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"cross-env": "^7.0.3",
|
||||
@@ -34,7 +35,7 @@
|
||||
"mini-css-extract-plugin": "^2.9.2",
|
||||
"normalize.css": "^8.0.1",
|
||||
"noty": "^3.2.0-beta-deprecated",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier": "^3.4.2",
|
||||
"pug": "^3.0.3",
|
||||
"pug-plain-loader": "^1.1.0",
|
||||
"raw-loader": "^4.0.2",
|
||||
@@ -2715,6 +2716,33 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@prettier/plugin-pug": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@prettier/plugin-pug/-/plugin-pug-3.2.0.tgz",
|
||||
"integrity": "sha512-SJEDgNjLpgZ2utQJGAFG96yho1hxX/tXflL24HztHYxzkPlDus2/XcvaW7WKQgMej1I+Pk6hLKp2FWv/zgzvkA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/Shinigami92"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://www.paypal.com/donate/?hosted_button_id=L7GY729FBKTZY"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pug-lexer": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0",
|
||||
"npm": ">=9.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prettier": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sindresorhus/is": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
|
||||
@@ -8535,10 +8563,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
|
||||
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
|
||||
"integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"@fontsource/noto-sans-sc": "^5.1.0",
|
||||
"@fontsource/noto-sans-tc": "^5.1.0",
|
||||
"@infolektuell/noto-color-emoji": "^0.2.0",
|
||||
"@prettier/plugin-pug": "^3.2.0",
|
||||
"animate.css": "^4.1.1",
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"cross-env": "^7.0.3",
|
||||
@@ -49,7 +50,7 @@
|
||||
"mini-css-extract-plugin": "^2.9.2",
|
||||
"normalize.css": "^8.0.1",
|
||||
"noty": "^3.2.0-beta-deprecated",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier": "^3.4.2",
|
||||
"pug": "^3.0.3",
|
||||
"pug-plain-loader": "^1.1.0",
|
||||
"raw-loader": "^4.0.2",
|
||||
|
||||
14
src/app.js
14
src/app.js
@@ -36,6 +36,7 @@ import ModerationTab from './views/tabs/Moderation.vue';
|
||||
|
||||
// components
|
||||
import SimpleSwitch from './components/settings/SimpleSwitch.vue';
|
||||
import GroupsSidebar from './components/sidebar/GroupsSidebar.vue';
|
||||
|
||||
// main app classes
|
||||
import _sharedFeed from './classes/sharedFeed.js';
|
||||
@@ -166,7 +167,11 @@ console.log(`isLinux: ${LINUX}`);
|
||||
|
||||
// components
|
||||
// - settings
|
||||
SimpleSwitch
|
||||
SimpleSwitch,
|
||||
|
||||
// components
|
||||
// - sidebar(friendsListSidebar)
|
||||
GroupsSidebar
|
||||
},
|
||||
el: '#x-app',
|
||||
async mounted() {
|
||||
@@ -23120,7 +23125,9 @@ console.log(`isLinux: ${LINUX}`);
|
||||
return LINUX;
|
||||
};
|
||||
|
||||
// friendsListSiderBar
|
||||
// friendsListSidebar
|
||||
// - SidebarGroupByInstance
|
||||
|
||||
$app.methods.handleSwitchGroupByInstance = async function () {
|
||||
this.isSidebarGroupByInstance = !this.isSidebarGroupByInstance;
|
||||
await configRepository.setBool(
|
||||
@@ -23129,9 +23136,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
);
|
||||
};
|
||||
|
||||
// friendsListSidebar
|
||||
// - SidebarGroupByInstance
|
||||
|
||||
$app.data.isSidebarGroupByInstance = await configRepository.getBool(
|
||||
'VRCX_sidebarGroupByInstance',
|
||||
true
|
||||
|
||||
@@ -1216,7 +1216,7 @@ export default class extends baseClass {
|
||||
|
||||
API.$on('GROUP:USER:INSTANCES', function (args) {
|
||||
$app.groupInstances = [];
|
||||
for (var json of args.json.instances) {
|
||||
for (const json of args.json.instances) {
|
||||
if (args.json.fetchedAt) {
|
||||
// tack on fetchedAt
|
||||
json.$fetchedAt = args.json.fetchedAt;
|
||||
@@ -1227,7 +1227,7 @@ export default class extends baseClass {
|
||||
fetchedAt: args.json.fetchedAt
|
||||
}
|
||||
});
|
||||
var ref = this.cachedGroups.get(json.ownerId);
|
||||
const ref = this.cachedGroups.get(json.ownerId);
|
||||
if (typeof ref === 'undefined') {
|
||||
if ($app.friendLogInitStatus) {
|
||||
this.getGroup({ groupId: json.ownerId });
|
||||
|
||||
94
src/components/sidebar/GroupsSidebar.vue
Normal file
94
src/components/sidebar/GroupsSidebar.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<div class="x-friend-list" style="padding: 10px 5px">
|
||||
<template v-for="(group, index) in groupedGroupInstances">
|
||||
<div
|
||||
:key="getGroupId(group)"
|
||||
class="x-friend-group x-link sidebar-group-title"
|
||||
:style="{ paddingTop: index === 0 ? '0px' : '10px' }"
|
||||
>
|
||||
<div @click="toggleGroupSidebarCollapse(getGroupId(group))" style="display: flex; align-items: center">
|
||||
<i
|
||||
class="el-icon-arrow-right"
|
||||
:class="{ rotate: !groupInstancesCfg[getGroupId(group)].isCollapsed }"
|
||||
></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" />
|
||||
</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>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'GroupsSidebar',
|
||||
props: {
|
||||
groupInstances: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// temporary, sort feat not yet done
|
||||
// may be the data structure to be changed
|
||||
groupInstancesCfg: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
groupedGroupInstances() {
|
||||
const groupMap = new Map();
|
||||
|
||||
this.groupInstances.forEach((ref) => {
|
||||
const groupId = ref.group.groupId;
|
||||
if (!groupMap.has(groupId)) {
|
||||
groupMap.set(groupId, []);
|
||||
}
|
||||
groupMap.get(groupId).push(ref);
|
||||
|
||||
if (!this.groupInstancesCfg[ref.group?.groupId]) {
|
||||
this.groupInstancesCfg = {
|
||||
[ref.group.groupId]: {
|
||||
isCollapsed: false
|
||||
},
|
||||
...this.groupInstancesCfg
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(groupMap.values());
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleGroupSidebarCollapse(groupId) {
|
||||
this.groupInstancesCfg[groupId].isCollapsed = !this.groupInstancesCfg[groupId].isCollapsed;
|
||||
},
|
||||
showGroupDialog(ownerId) {
|
||||
this.$emit('show-group-dialog', ownerId);
|
||||
},
|
||||
getGroupId(group) {
|
||||
return group[0]?.group?.groupId || '';
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,181 +1,343 @@
|
||||
|
||||
mixin friendsListSidebar()
|
||||
.x-aside-container(v-show="$refs.menu && $refs.menu.activeIndex !== 'friendsList'" id="aside")
|
||||
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")
|
||||
mixin friendsListSidebar
|
||||
#aside.x-aside-container(v-show='$refs.menu && $refs.menu.activeIndex !== \'friendsList\'')
|
||||
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")
|
||||
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="true" style="height:calc(100% - 60px;margin-top:5px")
|
||||
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='true' 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)")
|
||||
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="vipFriends.length")
|
||||
i.el-icon-arrow-right(:class="{ rotate: isVIPFriends }")
|
||||
span(style="margin-left:5px") {{ $t('side_panel.favorite') }} ― {{ vipFriends.length }}
|
||||
div(v-show="isVIPFriends")
|
||||
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='vipFriends.length')
|
||||
i.el-icon-arrow-right(:class='{ rotate: isVIPFriends }')
|
||||
span(style='margin-left: 5px') {{ $t('side_panel.favorite') }} ― {{ vipFriends.length }}
|
||||
div(v-show='isVIPFriends')
|
||||
template(v-if='isSidebarGroupByInstance')
|
||||
div(v-for="(friendArr, idx) in vipFriendsInSameInstance" :key="friendArr[0].ref?.location.tag")
|
||||
div(style="margin-bottom: 3px")
|
||||
location.extra(:location="friendArr[0].ref?.location" style="color:#c7c7c7")
|
||||
span(style="margin-left: 5px") {{ `(${friendArr.length})` }}
|
||||
div(style="margin-bottom: 10px")
|
||||
div.x-friend-item(v-if="friendArr && friendArr.length" v-for="friend in friendArr" :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)")
|
||||
div(
|
||||
v-for='(friendArr, idx) in vipFriendsInSameInstance'
|
||||
:key='friendArr[0].ref?.location.tag')
|
||||
div(style='margin-bottom: 3px')
|
||||
location.extra(:location='friendArr[0].ref?.location' style='color: #c7c7c7')
|
||||
span(style='margin-left: 5px') {{ `(${friendArr.length})` }}
|
||||
div(style='margin-bottom: 10px')
|
||||
.x-friend-item(
|
||||
v-if='friendArr && friendArr.length'
|
||||
v-for='friend in friendArr'
|
||||
: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') }}
|
||||
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') }}
|
||||
template(v-else)
|
||||
i(v-if="friend.ref.travelingToLocation" class="el-icon el-icon-loading" style="display:inline-block;margin-right:5px")
|
||||
timer(:epoch="friend.ref?.$location_at" style="color:#c7c7c7")
|
||||
i.el-icon.el-icon-loading(
|
||||
v-if='friend.ref.travelingToLocation'
|
||||
style='display: inline-block; margin-right: 5px')
|
||||
timer(:epoch='friend.ref?.$location_at' style='color: #c7c7c7')
|
||||
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")
|
||||
div(v-if="idx === vipFriendsInSameInstance.length - 1" style="color:#c7c7c7") {{ "Others" }}
|
||||
.x-friend-item(v-for="friend in vipFriendsNotInSameInstance" :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)")
|
||||
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')
|
||||
div(v-if='idx === vipFriendsInSameInstance.length - 1' style='color: #c7c7c7') {{ 'Others' }}
|
||||
.x-friend-item(
|
||||
v-for='friend in vipFriendsNotInSameInstance'
|
||||
: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")
|
||||
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")
|
||||
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 vipFriends" :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)")
|
||||
.x-friend-item(
|
||||
v-for='friend in vipFriends'
|
||||
: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")
|
||||
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="isOnlineFriends = !isOnlineFriends; saveFriendsGroupStates()" v-show="onlineFriends.length")
|
||||
i.el-icon-arrow-right(:class="{ rotate: isOnlineFriends }")
|
||||
span(style="margin-left:5px") {{ $t('side_panel.online') }} ― {{ onlineFriends.length }}
|
||||
div(v-show="isOnlineFriends")
|
||||
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='onlineFriends.length')
|
||||
i.el-icon-arrow-right(:class='{ rotate: isOnlineFriends }')
|
||||
span(style='margin-left: 5px') {{ $t('side_panel.online') }} ― {{ onlineFriends.length }}
|
||||
div(v-show='isOnlineFriends')
|
||||
template(v-if='isSidebarGroupByInstance')
|
||||
div(v-for="(friendArr, idx) in onlineFriendsInSameInstance" :key="friendArr[0].ref?.location.tag")
|
||||
div(style="margin-bottom: 3px")
|
||||
location.extra(:location="friendArr[0].ref?.location" style="color:#c7c7c7")
|
||||
span(style="margin-left: 5px") {{ `(${friendArr.length})` }}
|
||||
div(style="margin-bottom: 10px")
|
||||
div.x-friend-item(v-if="friendArr && friendArr.length" v-for="friend in friendArr" :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)")
|
||||
div(
|
||||
v-for='(friendArr, idx) in onlineFriendsInSameInstance'
|
||||
:key='friendArr[0].ref?.location.tag')
|
||||
div(style='margin-bottom: 3px')
|
||||
location.extra(:location='friendArr[0].ref?.location' style='color: #c7c7c7')
|
||||
span(style='margin-left: 5px') {{ `(${friendArr.length})` }}
|
||||
div(style='margin-bottom: 10px')
|
||||
.x-friend-item(
|
||||
v-if='friendArr && friendArr.length'
|
||||
v-for='friend in friendArr'
|
||||
: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') }}
|
||||
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') }}
|
||||
template(v-else)
|
||||
i(v-if="friend.ref.travelingToLocation" class="el-icon el-icon-loading" style="display:inline-block;margin-right:5px")
|
||||
timer(:epoch="friend.ref?.$location_at" style="color:#c7c7c7")
|
||||
i.el-icon.el-icon-loading(
|
||||
v-if='friend.ref.travelingToLocation'
|
||||
style='display: inline-block; margin-right: 5px')
|
||||
timer(:epoch='friend.ref?.$location_at' style='color: #c7c7c7')
|
||||
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")
|
||||
div(v-if="idx === onlineFriendsInSameInstance.length - 1" style="color:#c7c7c7") {{ "Others" }}
|
||||
.x-friend-item(v-for="friend in onlineFriendsNotInSameInstance" :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)")
|
||||
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')
|
||||
div(v-if='idx === onlineFriendsInSameInstance.length - 1' style='color: #c7c7c7') {{ 'Others' }}
|
||||
.x-friend-item(
|
||||
v-for='friend in onlineFriendsNotInSameInstance'
|
||||
: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")
|
||||
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")
|
||||
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 onlineFriends" :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)")
|
||||
.x-friend-item(
|
||||
v-for='friend in onlineFriends'
|
||||
: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")
|
||||
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")
|
||||
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)")
|
||||
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")
|
||||
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")
|
||||
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)")
|
||||
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")
|
||||
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
|
||||
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 }})
|
||||
.x-friend-list(style="padding:10px 5px")
|
||||
.x-friend-item(v-for="ref in groupInstances" :key="ref.instance.id" @click="showGroupDialog(ref.instance.ownerId)")
|
||||
.avatar
|
||||
img(v-lazy="ref.group.iconUrl")
|
||||
.detail
|
||||
span.name
|
||||
span(v-text="ref.group.name")
|
||||
span(style="font-weight:normal;margin-left:5px") ({{ ref.instance.userCount }}/{{ ref.instance.capacity }})
|
||||
location.extra(:location="ref.instance.location" :link="false")
|
||||
span(style='color: #909399; font-size: 12px; margin-left: 10px') ({{ groupInstances.length }})
|
||||
groups-sidebar(:group-instances='groupInstances' @show-group-dialog='showGroupDialog')
|
||||
|
||||
Reference in New Issue
Block a user