diff --git a/.prettierrc.json b/.prettierrc.json index 9068de5d..c84531d0 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -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 + } + } + ] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2c7809b0..bbfe5a4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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" }, diff --git a/package.json b/package.json index 66ba2053..d2754e6e 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/app.js b/src/app.js index 0822f25c..81c08663 100644 --- a/src/app.js +++ b/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 diff --git a/src/classes/groups.js b/src/classes/groups.js index 80567c73..a58d02d0 100644 --- a/src/classes/groups.js +++ b/src/classes/groups.js @@ -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 }); diff --git a/src/components/sidebar/GroupsSidebar.vue b/src/components/sidebar/GroupsSidebar.vue new file mode 100644 index 00000000..ab7c6a0b --- /dev/null +++ b/src/components/sidebar/GroupsSidebar.vue @@ -0,0 +1,94 @@ + + + + + + + {{ group[0].group.name }} – {{ group.length }} + + + + + + + + + + + ({{ ref.instance.userCount }}/{{ ref.instance.capacity }}) + + + + + + + + + diff --git a/src/mixins/friendsListSidebar.pug b/src/mixins/friendsListSidebar.pug index c753a953..2c801381 100644 --- a/src/mixins/friendsListSidebar.pug +++ b/src/mixins/friendsListSidebar.pug @@ -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')