improve: UI (#1152)

* improve: UI (#1033)

* fix: instance activity chart not displaying properly

* fix
This commit is contained in:
pa
2025-02-24 22:57:43 +09:00
committed by GitHub
parent 870c1a9c5e
commit d5e789ef0e
25 changed files with 476 additions and 392 deletions

View File

@@ -42,6 +42,7 @@ import ChartsTab from './views/tabs/Charts.vue';
// components
import SimpleSwitch from './components/settings/SimpleSwitch.vue';
import GroupsSidebar from './components/sidebar/GroupsSidebar.vue';
import PreviousInstanceInfo from './views/dialogs/PreviousInstanceInfo.vue';
// main app classes
import _sharedFeed from './classes/sharedFeed.js';
@@ -114,13 +115,6 @@ console.log(`isLinux: ${LINUX}`);
});
// #endregion
// #region | date utility library
// - dayjs plugin init
dayjs.extend(duration);
dayjs.extend(utc);
dayjs.extend(timezone);
// #endregion
// everything in this program is global stored in $app, I hate it, it is what it is
let $app = {};
const API = new _apiInit($app);
@@ -184,12 +178,15 @@ console.log(`isLinux: ${LINUX}`);
// components
// - sidebar(friendsListSidebar)
GroupsSidebar
GroupsSidebar,
// - dialogs
PreviousInstanceInfo
},
provide() {
return {
API,
showUserDialog: this.showUserDialog
showUserDialog: this.showUserDialog,
adjustDialogZ: this.adjustDialogZ
};
},
el: '#x-app',
@@ -224,9 +221,6 @@ console.log(`isLinux: ${LINUX}`);
API.$on('SHOW_GROUP_DIALOG', (groupId) =>
this.showGroupDialog(groupId)
);
API.$on('SHOW_LAUNCH_DIALOG', (tag, shortName) =>
this.showLaunchDialog(tag, shortName)
);
this.updateLoop();
this.getGameLogTable();
this.refreshCustomCss();
@@ -338,7 +332,7 @@ console.log(`isLinux: ${LINUX}`);
// #endregion
// #region | Init: Noty, Vue, Vue-Markdown, ElementUI, VueI18n, VueLazyLoad, Vue filters, dark stylesheet
// #region | Init: Noty, Vue, Vue-Markdown, ElementUI, VueI18n, VueLazyLoad, Vue filters, dark stylesheet, dayjs
Noty.overrideDefaults({
animation: {
@@ -365,6 +359,10 @@ console.log(`isLinux: ${LINUX}`);
Vue.use(DataTables);
dayjs.extend(duration);
dayjs.extend(utc);
dayjs.extend(timezone);
// #endregion
// #endregion
@@ -485,23 +483,24 @@ console.log(`isLinux: ${LINUX}`);
}
};
// FIXME: it may performance issue. review here
API.applyUserLanguage = function (ref) {
if (!ref || !ref.tags || !$app.subsetOfLanguages) {
return;
}
ref.$languages = [];
var { tags } = ref;
for (var tag of tags) {
if (tag.startsWith('language_') === false) {
continue;
const languagePrefix = 'language_';
const prefixLength = languagePrefix.length;
for (const tag of ref.tags) {
if (tag.startsWith(languagePrefix)) {
const key = tag.substring(prefixLength);
const value = $app.subsetOfLanguages[key];
if (value !== undefined) {
ref.$languages.push({ key, value });
}
}
var key = tag.substr(9);
var value = $app.subsetOfLanguages[key];
if (typeof value === 'undefined') {
continue;
}
ref.$languages.push({
key,
value
});
}
};
@@ -3891,12 +3890,6 @@ console.log(`isLinux: ${LINUX}`);
};
$app.methods.selectMenu = function (index) {
// NOTE
// 툴팁이 쌓여서 느려지기 때문에 날려줌.
// 근데 이 방법이 안전한지는 모르겠음
document.querySelectorAll('[role="tooltip"]').forEach((node) => {
node.remove();
});
var item = this.$refs.menu.items[index];
if (item) {
item.$el.classList.remove('notify');
@@ -3906,27 +3899,6 @@ console.log(`isLinux: ${LINUX}`);
} else if (index === 'friendsList') {
this.friendsListSearchChange();
}
workerTimers.setTimeout(() => {
// fix some weird sorting bug when disabling data tables
// looks like it's not needed anymore
// if (
// typeof this.$refs.playerModerationTableRef?.sortData !==
// 'undefined'
// ) {
// this.$refs.playerModerationTableRef.sortData.prop = 'created';
// }
if (
typeof this.$refs.notificationTableRef?.sortData !== 'undefined'
) {
this.$refs.notificationTableRef.sortData.prop = 'created_at';
}
if (typeof this.$refs.friendLogTableRef?.sortData !== 'undefined') {
this.$refs.friendLogTableRef.sortData.prop = 'created_at';
}
}, 100);
};
$app.data.twoFactorAuthDialogVisible = false;
@@ -4933,25 +4905,6 @@ console.log(`isLinux: ${LINUX}`);
return 0;
};
// descending
var compareByCreatedAt = function (a, b) {
if (
typeof a.created_at !== 'string' ||
typeof b.created_at !== 'string'
) {
return 0;
}
var A = a.created_at.toUpperCase();
var B = b.created_at.toUpperCase();
if (A < B) {
return 1;
}
if (A > B) {
return -1;
}
return 0;
};
var compareByMemberCount = function (a, b) {
if (
typeof a.memberCount !== 'number' ||
@@ -6894,7 +6847,7 @@ console.log(`isLinux: ${LINUX}`);
avatarsArray.sort(compareByUpdatedAt);
break;
case 'created':
avatarsArray.sort(compareByCreatedAt);
avatarsArray.sort($utils.compareByCreatedAt);
break;
case 'name':
avatarsArray.sort(compareByName);
@@ -8236,18 +8189,6 @@ console.log(`isLinux: ${LINUX}`);
'VRCX_sidePanelWidth',
300
);
if (await configRepository.getInt('VRCX_asidewidth')) {
// migrate to new defaults
$app.data.asideWidth = await configRepository.getInt('VRCX_asidewidth');
if ($app.data.asideWidth < 300) {
$app.data.asideWidth = 300;
}
await configRepository.setInt(
'VRCX_sidePanelWidth',
$app.data.asideWidth
);
await configRepository.remove('VRCX_asidewidth');
}
$app.data.autoUpdateVRCX = await configRepository.getString(
'VRCX_autoUpdateVRCX',
'Auto Download'
@@ -11442,8 +11383,9 @@ console.log(`isLinux: ${LINUX}`);
D.treeData = $utils.buildTreeData(D.ref);
};
$app.methods.changeUserDialogAvatarSorting = function () {
var D = this.userDialog;
$app.methods.changeUserDialogAvatarSorting = function (sortOption) {
const D = this.userDialog;
D.avatarSorting = sortOption;
this.sortUserDialogAvatars(D.avatars);
};
@@ -15396,18 +15338,20 @@ console.log(`isLinux: ${LINUX}`);
// };
$app.methods.friendsListSearchChange = function () {
let query;
let cleanedQuery;
this.friendsListTable.data = [];
var filters = [...this.friendsListSearchFilters];
let filters = [...this.friendsListSearchFilters];
if (filters.length === 0) {
filters = ['Display Name', 'Rank', 'Status', 'Bio', 'Memo'];
}
var results = [];
const results = [];
if (this.friendsListSearch) {
var query = this.friendsListSearch;
var cleanedQuery = removeWhitespace(query);
query = this.friendsListSearch;
cleanedQuery = removeWhitespace(query);
}
for (var ctx of this.friends.values()) {
for (const ctx of this.friends.values()) {
if (typeof ctx.ref === 'undefined') {
continue;
}
@@ -15418,7 +15362,7 @@ console.log(`isLinux: ${LINUX}`);
continue;
}
if (query && filters) {
var match = false;
let match = false;
if (
!match &&
filters.includes('Display Name') &&
@@ -15473,7 +15417,9 @@ console.log(`isLinux: ${LINUX}`);
results.push(ctx.ref);
}
this.getAllUserStats();
this.friendsListTable.data = results;
requestAnimationFrame(() => {
this.friendsListTable.data = results;
});
};
$app.methods.getAllUserStats = async function () {
@@ -19016,7 +18962,6 @@ console.log(`isLinux: ${LINUX}`);
};
$app.methods.setAsideWidth = async function () {
document.getElementById('aside').style.width = `${this.asideWidth}px`;
await configRepository.setInt('VRCX_sidePanelWidth', this.asideWidth);
};
@@ -19574,7 +19519,7 @@ console.log(`isLinux: ${LINUX}`);
}
array.push(ref);
}
array.sort(compareByCreatedAt);
array.sort($utils.compareByCreatedAt);
this.previousInstancesUserDialogTable.data = array;
D.loading = false;
workerTimers.setTimeout(() => D.forceUpdate++, 150);
@@ -19677,7 +19622,7 @@ console.log(`isLinux: ${LINUX}`);
}
array.push(ref);
}
array.sort(compareByCreatedAt);
array.sort($utils.compareByCreatedAt);
this.previousInstancesWorldDialogTable.data = array;
D.loading = false;
workerTimers.setTimeout(() => D.forceUpdate++, 150);
@@ -19707,61 +19652,12 @@ console.log(`isLinux: ${LINUX}`);
// #endregion
// #region | App: Previous Instance Info Dialog
$app.data.previousInstanceInfoDialogTable = {
data: [],
filters: [
{
prop: 'displayName',
value: ''
}
],
tableProps: {
stripe: true,
size: 'mini',
defaultSort: {
prop: 'created_at',
order: 'descending'
}
},
pageSize: 10,
paginationProps: {
small: true,
layout: 'sizes,prev,pager,next,total',
pageSizes: [10, 25, 50, 100]
}
};
$app.data.previousInstanceInfoDialog = {
visible: false,
loading: false,
forceUpdate: 0,
$location: {}
};
$app.data.previousInstanceInfoDialogVisible = false;
$app.data.previousInstanceInfoDialogInstanceId = '';
$app.methods.showPreviousInstanceInfoDialog = function (instanceId) {
this.$nextTick(() =>
$app.adjustDialogZ(this.$refs.previousInstanceInfoDialog.$el)
);
var D = this.previousInstanceInfoDialog;
D.$location = $utils.parseLocation(instanceId);
D.visible = true;
D.loading = true;
this.refreshPreviousInstanceInfoTable();
};
$app.methods.refreshPreviousInstanceInfoTable = function () {
var D = this.previousInstanceInfoDialog;
database.getPlayersFromInstance(D.$location.tag).then((data) => {
var array = [];
for (var entry of Array.from(data.values())) {
entry.timer = $app.timeToText(entry.time);
array.push(entry);
}
array.sort(compareByCreatedAt);
this.previousInstanceInfoDialogTable.data = array;
D.loading = false;
workerTimers.setTimeout(() => D.forceUpdate++, 150);
});
this.previousInstanceInfoDialogVisible = true;
this.previousInstanceInfoDialogInstanceId = instanceId;
};
$app.data.dtHour12 = await configRepository.getBool('VRCX_dtHour12', false);
@@ -22231,7 +22127,7 @@ console.log(`isLinux: ${LINUX}`);
$app.methods.updateLocalFavoriteFriends = function () {
this.localFavoriteFriends.clear();
this.localFavoriteFriendsDivideByGroup.clear();
for (var ref of API.cachedFavorites.values()) {
for (const ref of API.cachedFavorites.values()) {
if (
!ref.$isDeleted &&
ref.type === 'friend' &&
@@ -23471,7 +23367,9 @@ console.log(`isLinux: ${LINUX}`);
}
}
}
if (!locationTag) return;
if (!locationTag) {
return;
}
if (!friendsList[locationTag]) {
friendsList[locationTag] = [];

View File

@@ -672,8 +672,8 @@ i.x-status-icon.red {
}
.x-tag-age-verification {
color: #5C70EC !important;
border-color: #5C70EC !important;
color: #5c70ec !important;
border-color: #5c70ec !important;
}
.x-grey {
@@ -865,10 +865,6 @@ i.x-status-icon.red {
margin-right: 20px;
}
.el-tab-pane {
height: 100%;
}
.el-tabs {
display: flex;
flex-direction: column;

View File

@@ -108,7 +108,6 @@ export default class extends baseClass {
visible: false,
loading: false,
languageChoice: false,
languageValue: '',
languages: []
}
};

View File

@@ -12,9 +12,10 @@ export default class extends baseClass {
Vue.component('launch', {
template:
'<el-button @click="confirm" size="mini" icon="el-icon-info" circle></el-button>',
'<el-tooltip placement="top" :content="$t(`dialog.user.info.launch_invite_tooltip`)" :disabled="hideTooltips"><el-button @click="confirm" size="mini" icon="el-icon-switch-button" circle></el-button></el-tooltip>',
props: {
location: String
location: String,
hideTooltips: Boolean
},
methods: {
parse() {
@@ -25,7 +26,7 @@ export default class extends baseClass {
: 'none';
},
confirm() {
API.$emit('SHOW_LAUNCH_DIALOG', this.location);
this.$emit('show-launch-dialog', this.location);
}
},
watch: {
@@ -279,8 +280,8 @@ export default class extends baseClass {
}
},
showLaunchDialog() {
API.$emit(
'SHOW_LAUNCH_DIALOG',
this.$emit(
'show-launch-dialog',
this.location,
this.shortName
);
@@ -308,12 +309,12 @@ export default class extends baseClass {
Vue.component('last-join', {
template:
'<span>' +
'<el-tooltip placement="top" style="margin-left:5px" v-if="lastJoin">' +
'<span v-if="lastJoin">' +
'<el-tooltip placement="top" style="margin-left:5px" >' +
'<div slot="content">' +
'<span>{{ $t("dialog.user.info.last_join") }} <timer :epoch="lastJoin"></timer></span>' +
'</div>' +
'<i v-if="lastJoin" class="el-icon el-icon-location-outline" style="display:inline-block"></i>' +
'<i class="el-icon el-icon-location-outline" style="display:inline-block"></i>' +
'</el-tooltip>' +
'</span>',
props: {

View File

@@ -322,6 +322,26 @@ export default {
});
return node;
},
// app.js 4900ln
// descending
compareByCreatedAt(a, b) {
if (
typeof a.created_at !== 'string' ||
typeof b.created_at !== 'string'
) {
return 0;
}
var A = a.created_at.toUpperCase();
var B = b.created_at.toUpperCase();
if (A < B) {
return 1;
}
if (A > B) {
return -1;
}
return 0;
},
// lazy load echarts
loadEcharts() {
if (echarts) {

View File

@@ -15,8 +15,8 @@
</div>
<i
class="el-icon-info"
slot="reference"
class="el-icon-info"
style="margin-left: 5px; font-size: 12px; opacity: 0.7"
></i>
</el-popover>
@@ -103,7 +103,7 @@
</div>
<transition name="el-fade-in-linear">
<div v-show="isDetailVisible && !isLoading" class="divider">
<div v-show="isDetailVisible && !isLoading && !activityData.length === 0" class="divider">
<el-divider>·</el-divider>
</div>
</transition>
@@ -255,19 +255,19 @@
},
async mounted() {
try {
this.getAllDateOfActivity();
const [echartsModule] = await Promise.all([
// lazy load echarts
utils.loadEcharts().catch((error) => {
console.error('lazy load echarts failed', error);
return null;
}),
this.getActivityData(),
this.getAllDateOfActivity()
this.getActivityData()
]);
if (echartsModule) {
this.echarts = echartsModule;
}
if (this.activityData.length && this.echarts) {
if (echartsModule) {
// activity data is ready, but world name data isn't ready
// so init echarts with empty data, reduce the render time of init screen
this.initEcharts(true);
@@ -284,10 +284,12 @@
this.isLoading = true;
await this.getActivityData();
this.getWorldNameData();
// possibility past 24:00
this.getAllDateOfActivity();
},
// echarts - start
initEcharts(isFirstTime = false) {
initEcharts() {
const chartsHeight = this.activityData.length * (this.barWidth + 10) + 200;
const chartDom = this.$refs.activityChartRef;
if (!this.echartsInstance) {
@@ -322,11 +324,13 @@
}
};
this.echartsInstance.setOption(this.getNewOption(isFirstTime), { lazyUpdate: true });
const options = this.activityData.length ? this.getNewOption() : {};
this.echartsInstance.setOption(options, { lazyUpdate: true });
this.echartsInstance.on('click', 'yAxis', handleClickYAxisLabel);
this.isLoading = false;
},
getNewOption(isFirstTime) {
getNewOption() {
const getTooltip = (params) => {
const activityData = this.activityData;
const param = params[1];
@@ -412,17 +416,15 @@
color: 'transparent'
}
},
data: isFirstTime
? []
: this.activityData.map((item, idx) => {
if (idx === 0) {
const midnight = dayjs.tz(this.selectedDate).startOf('day');
if (midnight.isAfter(item.joinTime)) {
return 0;
}
}
return item.joinTime - dayjs.tz(this.selectedDate).startOf('day');
})
data: this.activityData.map((item, idx) => {
if (idx === 0) {
const midnight = dayjs.tz(this.selectedDate).startOf('day');
if (midnight.isAfter(item.joinTime)) {
return 0;
}
}
return item.joinTime - dayjs.tz(this.selectedDate).startOf('day');
})
},
{
name: 'Time',
@@ -439,19 +441,17 @@
shadowOffsetX: 0.7,
shadowOffsetY: 0.5
},
data: isFirstTime
? []
: this.activityData.map((item, idx) => {
// If the joinTime of the first data is on the previous day,
// and the data traverses midnight, the duration starts at midnight
if (idx === 0) {
const midnight = dayjs.tz(this.selectedDate).startOf('day');
if (midnight.isAfter(item.joinTime)) {
return item.leaveTime - dayjs.tz(midnight);
}
}
return item.time;
})
data: this.activityData.map((item, idx) => {
// If the joinTime of the first data is on the previous day,
// and the data traverses midnight, the duration starts at midnight
if (idx === 0) {
const midnight = dayjs.tz(this.selectedDate).startOf('day');
if (midnight.isAfter(item.joinTime)) {
return item.leaveTime - dayjs.tz(midnight);
}
}
return item.time;
})
}
],
backgroundColor: 'transparent'
@@ -545,7 +545,8 @@
}
})
);
if (this.worldNameArray && this.echartsInstance) {
if (this.worldNameArray) {
this.initEcharts();
}
},
@@ -599,9 +600,11 @@
this.API.currentUser.id
);
this.$nextTick(() => {
this.handleIntersectionObserver();
});
if (this.activityDetailData.length) {
this.$nextTick(() => {
this.handleIntersectionObserver();
});
}
},
handleSplitActivityDetailData(activityDetailData, currentUserId) {
function countTargetIdOccurrences(innerArray, targetId) {
@@ -685,11 +688,7 @@
// intersection observer - start
handleIntersectionObserver() {
if (!this.$refs.activityDetailChartRef) {
console.error('handleIntersectionObserver failed');
return;
}
this.$refs.activityDetailChartRef.forEach((child, index) => {
this.$refs.activityDetailChartRef?.forEach((child, index) => {
const observer = new IntersectionObserver(this.handleIntersection.bind(this, index));
observer.observe(child.$el);
this.intersectionObservers[index] = observer;
@@ -771,7 +770,7 @@
display: flex;
align-items: center;
justify-content: center;
margin-top: 200px;
margin-top: 100px;
color: #5c5c5c;
}
.divider {

View File

@@ -109,8 +109,7 @@ html
:dt-hour12='dtHour12'
@open-previous-instance-info-dialog='showPreviousInstanceInfoDialog'
:friends-map='friends'
:local-favorite-friends='localFavoriteFriends'
)
:local-favorite-friends='localFavoriteFriends')
//- settings
include ./mixins/tabs/settings.pug

View File

@@ -710,8 +710,8 @@
"avatars": {
"header": "Avatars",
"total_count": "Total {count}",
"sort_by_name": "Sort by name",
"sort_by_update": "Sort by update",
"sort_by_name": "Name",
"sort_by_update": "Updated",
"all": "All",
"public": "Public",
"private": "Private"

View File

@@ -782,7 +782,8 @@
"instance_closed": "closed",
"instance_hard_closed": "hard closed",
"close_instance": "Close Instance",
"instance_age_gated": "age gated"
"instance_age_gated": "age gated",
"open_previouse_instance": "Open Previous Instance"
},
"groups": {
"header": "Groups",
@@ -824,11 +825,13 @@
"avatars": {
"header": "Avatars",
"total_count": "Total {count}",
"sort_by_name": "Sort by name",
"sort_by_update": "Sort by update",
"sort_by": "Sort by:",
"sort_by_name": "Name",
"sort_by_update": "Updated",
"all": "All",
"public": "Public",
"private": "Private"
"private": "Private",
"group_by": "Group by:"
},
"json": {
"header": "JSON"

View File

@@ -815,6 +815,7 @@
"avatars": {
"header": "アバター",
"total_count": "{count} 個のアバター",
"sort_by": "並べ替え:",
"sort_by_name": "名前順",
"sort_by_update": "更新順",
"all": "全て",

View File

@@ -821,8 +821,10 @@
"avatars": {
"header": "创建的模型",
"total_count": "总共 {count} 个",
"sort_by_name": "按名称排序",
"sort_by_update": "按更新时间排序",
"sort_by": "排序方式:",
"sort_by_name": "名称",
"sort_by_update": "更新时间",
"group_by": "分组方式:",
"all": "所有",
"public": "公开",
"private": "私人"

View File

@@ -787,8 +787,9 @@
"avatars": {
"header": "角色",
"total_count": "總共 {count}",
"sort_by_name": "依名稱排序",
"sort_by_update": "依更新排序",
"sort_by": "分類依據:",
"sort_by_name": "名稱",
"sort_by_update": "更新",
"all": "所有",
"public": "公開",
"private": "私人"

View File

@@ -52,10 +52,8 @@ mixin currentUser
:title='$t("dialog.language.header")'
width='400px')
div(v-loading='languageDialog.loading')
div(style='margin: 5px 0')
div(style='margin: 6px 0' v-for='item in API.currentUser.$languages' :key='item.key')
el-tag(
v-for='item in API.currentUser.$languages'
:key='item.key'
size='small'
type='info'
effect='plain'
@@ -63,26 +61,20 @@ mixin currentUser
@close='removeUserLanguage(item.key)'
style='margin-right: 5px')
span.flags(:class='languageClass(item.key)' style='display: inline-block; margin-right: 5px')
| {{ item.value }} ({{ item.key }})
div(v-if='languageDialog.languageChoice === true')
el-select(
v-model='languageDialog.languageValue'
:placeholder='$t("dialog.language.select_language")'
size='mini')
el-option(
v-for='item in languageDialog.languages'
:key='item.key'
:value='item.key'
:label='item.value')
span.flags(:class='languageClass(item.key)' style='display: inline-block; margin-right: 5px')
| {{ item.value }} ({{ item.key }})
el-button(
@click='languageDialog.languageChoice = false; addUserLanguage(languageDialog.languageValue)'
size='mini') {{ $t('dialog.language.ok') }}
el-button(@click='languageDialog.languageChoice = false' size='mini' style='margin-left: 0') {{ $t('dialog.language.cancel') }}
div(v-else)
el-button(@click='languageDialog.languageValue = ""; languageDialog.languageChoice = true' size='mini') {{ $t('dialog.language.add_language') }}
| {{ item.value }} ({{ item.key.toUpperCase() }})
el-select(
value=''
:disabled='languageDialog.loading || (API.currentUser.$languages && API.currentUser.$languages.length === 3)'
:placeholder='$t("dialog.language.select_language")'
@change='addUserLanguage'
style='margin-top: 14px')
el-option(
v-for='item in languageDialog.languages'
:key='item.key'
:value='item.key'
:label='item.value')
span.flags(:class='languageClass(item.key)' style='display: inline-block; margin-right: 5px')
| {{ item.value }} ({{ item.key.toUpperCase() }})
//- dialog: bio
el-dialog.x-dialog(
:before-close='beforeDialogClose'
@@ -311,7 +303,7 @@ mixin currentUser
.vrcplus-icon(
v-if='image.versions[image.versions.length - 1].file.url'
style='overflow: hidden'
@click='showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url, getEmojiFileName(image))')
@click='showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url, getEmojiFileName(image))')
template(v-if='image.frames')
.avatar(
:style='generateEmojiStyle(image.versions[image.versions.length - 1].file.url, image.framesOverTime, image.frames, image.loopStyle)')
@@ -365,7 +357,7 @@ mixin currentUser
.vrcplus-icon(
v-if='image.versions[image.versions.length - 1].file.url'
style='overflow: hidden'
@click='showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)')
@click='showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)')
img.avatar(v-lazy='image.versions[image.versions.length - 1].file.url')
div(style='float: right; margin-top: 5px')
el-button(
@@ -413,7 +405,7 @@ mixin currentUser
style='display: inline-block; margin-top: 10px; width: unset; cursor: default')
.vrcplus-icon(
style='overflow: hidden'
@click='showFullscreenImageDialog(image.files.image, getPrintFileName(image))')
@click='showFullscreenImageDialog(image.files.image, getPrintFileName(image))')
img.avatar(v-lazy='image.files.image')
div(style='margin-top: 5px; width: 208px')
span.x-ellipsis(v-if='image.note' v-text='image.note' style='display: block')

View File

@@ -470,7 +470,7 @@ mixin groupDialog
span(:key='pIndex') {{ permission }}
br
span {{ role.name }}{{ rIndex < groupDialog.memberRoles.length - 1 ? ', ' : '' }}
el-tab-pane(:label='$t("dialog.group.posts.header")')
el-tab-pane(:label='$t("dialog.group.posts.header")' lazy)
template(v-if='groupDialog.visible')
span(style='margin-right: 10px') {{ $t('dialog.group.posts.posts_count') }} {{ groupDialog.posts.length }}
el-input(
@@ -544,7 +544,7 @@ mixin groupDialog
size='mini'
style='margin-left: 5px'
@click='confirmDeleteGroupPost(post)')
el-tab-pane(:label='$t("dialog.group.members.header")')
el-tab-pane(:label='$t("dialog.group.members.header")' lazy)
template(v-if='groupDialog.visible')
span(
v-if='hasGroupPermission(groupDialog.ref, "group-members-viewall")'
@@ -704,7 +704,7 @@ mixin groupDialog
@click='loadMoreGroupMembers')
.detail(v-if='!isGroupMembersLoading')
span.name {{ $t('dialog.group.members.load_more') }}
el-tab-pane(:label='$t("dialog.group.gallery.header")')
el-tab-pane(:label='$t("dialog.group.gallery.header")' lazy)
el-button(
type='default'
size='mini'
@@ -737,7 +737,7 @@ mixin groupDialog
v-lazy='image.imageUrl'
style='height: 700px'
@click='showFullscreenImageDialog(image.imageUrl)')
el-tab-pane(:label='$t("dialog.group.json.header")')
el-tab-pane(:label='$t("dialog.group.json.header")' lazy)
el-button(
type='default'
@click='refreshGroupDialogTreeData()'

View File

@@ -8,11 +8,12 @@ mixin previousInstances
:visible.sync='previousInstancesUserDialog.visible'
:title='$t("dialog.previous_instances.header")'
width='1000px')
span(v-text='previousInstancesUserDialog.userRef.displayName' style='font-size: 14px')
el-input(
v-model='previousInstancesUserDialogTable.filters[0].value'
:placeholder='$t("dialog.previous_instances.search_placeholder")'
style='display: block; width: 150px; margin-top: 15px')
div(style='display: flex; align-items: center; justify-content: space-between')
span(v-text='previousInstancesUserDialog.userRef.displayName' style='font-size: 14px')
el-input(
v-model='previousInstancesUserDialogTable.filters[0].value'
:placeholder='$t("dialog.previous_instances.search_placeholder")'
style='display: block; width: 150px')
data-tables(
v-if='previousInstancesUserDialog.visible'
v-bind='previousInstancesUserDialogTable'
@@ -40,12 +41,12 @@ mixin previousInstances
template(#default='scope')
el-button(
type='text'
icon='el-icon-info'
icon='el-icon-switch-button'
size='mini'
@click='showLaunchDialog(scope.row.location)')
el-button(
type='text'
icon='el-icon-tickets'
icon='el-icon-s-data'
size='mini'
@click='showPreviousInstanceInfoDialog(scope.row.location)')
el-button(
@@ -71,11 +72,12 @@ mixin previousInstances
:visible.sync='previousInstancesWorldDialog.visible'
:title='$t("dialog.previous_instances.header")'
width='1000px')
span(v-text='previousInstancesWorldDialog.worldRef.name' style='font-size: 14px')
el-input(
v-model='previousInstancesWorldDialogTable.filters[0].value'
:placeholder='$t("dialog.previous_instances.search_placeholder")'
style='display: block; width: 150px; margin-top: 15px')
div(style='display: flex; align-items: center; justify-content: space-between')
span(v-text='previousInstancesWorldDialog.worldRef.name' style='font-size: 14px')
el-input(
v-model='previousInstancesWorldDialogTable.filters[0].value'
:placeholder='$t("dialog.previous_instances.search_placeholder")'
style='display: block; width: 150px')
data-tables(
v-if='previousInstancesWorldDialog.visible'
v-bind='previousInstancesWorldDialogTable'
@@ -89,7 +91,8 @@ mixin previousInstances
location-world(
:locationobject='scope.row.$location'
:grouphint='scope.row.groupName'
:currentuserid='API.currentUser.id')
:currentuserid='API.currentUser.id'
@show-launch-dialog='showLaunchDialog')
el-table-column(:label='$t("table.previous_instances.instance_creator")' prop='location')
template(#default='scope')
display-name(
@@ -103,7 +106,7 @@ mixin previousInstances
template(#default='scope')
el-button(
type='text'
icon='el-icon-tickets'
icon='el-icon-s-data'
size='mini'
@click='showPreviousInstanceInfoDialog(scope.row.location)')
el-button(
@@ -120,46 +123,10 @@ mixin previousInstances
size='mini'
@click='deleteGameLogWorldInstancePrompt(scope.row)')
//- dialog Table: Previous Instance Info
el-dialog.x-dialog(
:before-close='beforeDialogClose'
@mousedown.native='dialogMouseDown'
@mouseup.native='dialogMouseUp'
ref='previousInstanceInfoDialog'
:visible.sync='previousInstanceInfoDialog.visible'
:title='$t("dialog.previous_instances.info")'
width='800px')
div(style='display: flex; align-items: center; justify-content: space-between')
location(:location='previousInstanceInfoDialog.$location.tag' style='font-size: 14px')
el-input(
v-model='previousInstanceInfoDialogTable.filters[0].value'
:placeholder='$t("dialog.previous_instances.search_placeholder")'
style='width: 150px'
clearable)
data-tables(
v-if='previousInstanceInfoDialog.visible'
v-bind='previousInstanceInfoDialogTable'
v-loading='previousInstanceInfoDialog.loading'
style='margin-top: 10px')
el-table-column(:label='$t("table.previous_instances.date")' prop='created_at' sortable width='110')
template(v-once #default='scope')
el-tooltip(placement='left')
template(#content)
span {{ scope.row.created_at | formatDate('long') }}
span {{ scope.row.created_at | formatDate('short') }}
el-table-column(:label='$t("table.gameLog.icon")' prop='isFriend' width='70' align='center')
template(#default='scope')
template(v-if='gameLogIsFriend(scope.row)')
el-tooltip(v-if='gameLogIsFavorite(scope.row)' placement='top' content='Favorite')
span ⭐
el-tooltip(v-else placement='top' content='Friend')
span 💚
el-table-column(:label='$t("table.previous_instances.display_name")' prop='displayName' sortable)
template(#default='scope')
span.x-link(v-text='scope.row.displayName' @click='lookupUser(scope.row)')
el-table-column(:label='$t("table.previous_instances.time")' prop='time' width='100' sortable)
template(#default='scope')
span(v-text='scope.row.timer')
el-table-column(:label='$t("table.previous_instances.count")' prop='count' width='100' sortable)
template(#default='scope')
span(v-text='scope.row.count')
previous-instance-info(
:visible.sync='previousInstanceInfoDialogVisible'
:instance-id='previousInstanceInfoDialogInstanceId'
:game-log-is-friend='gameLogIsFriend'
:game-log-is-favorite='gameLogIsFavorite'
:lookup-user='lookupUser'
:is-dark-mode='isDarkMode')

View File

@@ -87,7 +87,7 @@ mixin screenshotMetadata
el-carousel(
ref='screenshotMetadataCarousel'
:interval='0'
initial-index='1'
:initial-index='1'
indicator-position='none'
arrow='always'
height='600px'

View File

@@ -331,11 +331,7 @@ mixin userDialog
style='display: flex; flex-direction: column; margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid #e4e7ed14')
div(style='flex: none')
template(v-if='isRealInstance(userDialog.$location.tag)')
el-tooltip(
placement='top'
:content='$t("dialog.user.info.launch_invite_tooltip")'
:disabled='hideTooltips')
launch(:location='userDialog.$location.tag')
launch(:location='userDialog.$location.tag' @show-launch-dialog='showLaunchDialog')
el-tooltip(
placement='top'
:content='$t("dialog.user.info.self_invite_tooltip")'
@@ -509,17 +505,21 @@ mixin userDialog
:content='$t("dialog.user.info.accuracy_notice")')
i.el-icon-warning
span.extra {{ userDialog.lastSeen | formatDate('long') }}
.x-friend-item(@click='showPreviousInstancesUserDialog(userDialog.ref)')
.detail
span.name {{ $t('dialog.user.info.join_count') }}
el-tooltip(
v-if='!hideTooltips'
placement='top'
style='margin-left: 5px'
:content='$t("dialog.user.info.accuracy_notice")')
i.el-icon-warning
span.extra(v-if='userDialog.joinCount === 0') -
span.extra(v-else v-text='userDialog.joinCount')
el-tooltip(
:disabled='hideTooltips'
placement='top'
:content='$t("dialog.user.info.open_previouse_instance")')
.x-friend-item(@click='showPreviousInstancesUserDialog(userDialog.ref)')
.detail
span.name {{ $t('dialog.user.info.join_count') }}
el-tooltip(
v-if='!hideTooltips'
placement='top'
style='margin-left: 5px'
:content='$t("dialog.user.info.accuracy_notice")')
i.el-icon-warning
span.extra(v-if='userDialog.joinCount === 0') -
span.extra(v-else v-text='userDialog.joinCount')
.x-friend-item(style='cursor: default')
.detail
span.name {{ $t('dialog.user.info.time_together') }}
@@ -532,6 +532,10 @@ mixin userDialog
span.extra(v-if='userDialog.timeSpent === 0') -
span.extra(v-else) {{ timeToText(userDialog.timeSpent) }}
template(v-else)
el-tooltip(
:disabled='hideTooltips || API.currentUser.id !== userDialog.id'
placement='top'
:content='$t("dialog.user.info.open_previouse_instance")')
.x-friend-item(@click='showPreviousInstancesUserDialog(userDialog.ref)')
.detail
span.name {{ $t('dialog.user.info.play_time') }}
@@ -544,7 +548,7 @@ mixin userDialog
span.extra(v-if='userDialog.timeSpent === 0') -
span.extra(v-else) {{ timeToText(userDialog.timeSpent) }}
.x-friend-item(style='cursor: default')
el-tooltip(placement='top')
el-tooltip(:placement='API.currentUser.id !== userDialog.id ? "bottom" : "top"')
template(#content)
span {{ userOnlineForTimestamp(userDialog) | formatDate('short') }}
.detail
@@ -564,7 +568,7 @@ mixin userDialog
i.el-icon-warning
span.extra {{ userOnlineFor(userDialog) }}
.x-friend-item(style='cursor: default')
el-tooltip(placement='top')
el-tooltip(:placement='API.currentUser.id !== userDialog.id ? "bottom" : "top"')
template(#content)
span {{ $t('dialog.user.info.last_login') }} {{ userDialog.ref.last_login | formatDate('short') }}
.detail
@@ -575,13 +579,11 @@ mixin userDialog
span.name {{ $t('dialog.user.info.date_joined') }}
span.extra(v-text='userDialog.ref.date_joined')
.x-friend-item(v-if='API.currentUser.id !== userDialog.id' style='cursor: default')
el-tooltip(placement='top')
el-tooltip(placement='top' :disabled='!userDialog.dateFriendedInfo.length')
template(#content v-if='userDialog.dateFriendedInfo.length')
template(v-for='ref in userDialog.dateFriendedInfo')
span {{ ref.type }}: {{ ref.created_at | formatDate('long') }}
br
template(#content v-else)
span -
.detail
span.name(v-if='userDialog.unFriended') {{ $t('dialog.user.info.unfriended') }}
el-tooltip(
@@ -912,26 +914,30 @@ mixin userDialog
span.extra(v-if='world.occupants') ({{ world.occupants }})
el-tab-pane(:label='$t("dialog.user.favorite_worlds.header")' lazy)
el-button(
v-if='userFavoriteWorlds && userFavoriteWorlds.length > 0'
type='default'
:loading='userDialog.isFavoriteWorldsLoading'
@click='getUserFavoriteWorlds(userDialog.id)'
size='mini'
size='small'
icon='el-icon-refresh'
circle)
circle
style='position: absolute; right: 15px; bottom: 15px; z-index: 99')
el-tabs.zero-margin-tabs(
type='card'
stretch
ref='favoriteWorlds'
v-loading='userDialog.isFavoriteWorldsLoading'
style='margin-top: 10px')
template(v-for='(list, index) in userFavoriteWorlds')
el-tab-pane(:key='index' lazy)
style='margin-top: 10px; height: 50vh')
template(v-if='userFavoriteWorlds && userFavoriteWorlds.length > 0')
el-tab-pane(v-for='(list, index) in userFavoriteWorlds' :key='index' lazy)
span(slot='label')
span(v-text='list[0]' style='font-weight: bold; font-size: 16px')
i.x-status-icon(
style='margin-left: 5px'
style='margin-right: 6px'
:class='userFavoriteWorldsStatus(list[1])')
span(style='color: #909399; font-size: 12px; margin-left: 5px') {{ list[2].length }}/{{ API.favoriteLimits.maxFavoritesPerGroup.world }}
.x-friend-list(style='margin-top: 10px; margin-bottom: 15px; min-height: 60px')
span(v-text='list[0]' style='font-weight: bold; font-size: 14px')
span(style='color: #909399; font-size: 10px; margin-left: 5px') {{ list[2].length }}/{{ API.favoriteLimits.maxFavoritesPerGroup.world }}
.x-friend-list(
style='margin-top: 10px; margin-bottom: 15px; min-height: 60px; max-height: none')
.x-friend-item.x-friend-item-border(
v-for='world in list[2]'
:key='world.favoriteId'
@@ -941,6 +947,9 @@ mixin userDialog
.detail
span.name(v-text='world.name')
span.extra(v-if='world.occupants') ({{ world.occupants }})
template(v-else-if='!userDialog.isFavoriteWorldsLoading')
div(style='display: flex; justify-content: center; align-items: center; height: 100%')
span(style='font-size: 16px') No favorite worlds found.
el-tab-pane(:label='$t("dialog.user.avatars.header")' lazy)
div(style='display: flex; align-items: center; justify-content: space-between')
div(style='display: flex; align-items: center')
@@ -962,22 +971,43 @@ mixin userDialog
circle)
span(style='margin-left: 5px') {{ $t('dialog.user.avatars.total_count', { count: userDialogAvatars.length }) }}
div
el-radio-group(
v-if='userDialog.ref.id === API.currentUser.id'
v-model='userDialog.avatarSorting'
size='mini'
@change='changeUserDialogAvatarSorting')
el-radio(label='name') {{ $t('dialog.user.avatars.sort_by_name') }}
el-radio(label='update') {{ $t('dialog.user.avatars.sort_by_update') }}
el-divider(direction='vertical')
el-radio-group(
v-if='userDialog.ref.id === API.currentUser.id'
v-model='userDialog.avatarReleaseStatus'
size='mini')
el-radio(label='all') {{ $t('dialog.user.avatars.all') }}
el-radio(label='public') {{ $t('dialog.user.avatars.public') }}
el-radio(label='private') {{ $t('dialog.user.avatars.private') }}
.x-friend-list(style='margin-top: 10px; min-height: 60px')
template(v-if='userDialog.ref.id === API.currentUser.id')
span(style='margin-right: 5px') {{ $t('dialog.user.avatars.sort_by') }}
el-dropdown(
@click.native.stop
trigger='click'
size='small'
style='margin-right: 5px'
:disabled='userDialog.isWorldsLoading')
el-button(size='mini')
span {{ $t(`dialog.user.avatars.sort_by_${userDialog.avatarSorting}`) }} #[i.el-icon-arrow-down.el-icon--right]
el-dropdown-menu(#default='dropdown')
el-dropdown-item(
v-text='$t("dialog.user.avatars.sort_by_name")'
@click.native='changeUserDialogAvatarSorting("name")')
el-dropdown-item(
v-text='$t("dialog.user.avatars.sort_by_update")'
@click.native='changeUserDialogAvatarSorting("update")')
span(style='margin-right: 5px; margin-left: 10px') {{ $t('dialog.user.avatars.group_by') }}
el-dropdown(
@click.native.stop
trigger='click'
size='small'
style='margin-right: 5px'
:disabled='userDialog.isWorldsLoading')
el-button(size='mini')
span {{ $t(`dialog.user.avatars.${userDialog.avatarReleaseStatus}`) }} #[i.el-icon-arrow-down.el-icon--right]
el-dropdown-menu(#default='dropdown')
el-dropdown-item(
v-text='$t("dialog.user.avatars.all")'
@click.native='userDialog.avatarReleaseStatus = "all"')
el-dropdown-item(
v-text='$t("dialog.user.avatars.public")'
@click.native='userDialog.avatarReleaseStatus = "public"')
el-dropdown-item(
v-text='$t("dialog.user.avatars.private")'
@click.native='userDialog.avatarReleaseStatus = "private"')
.x-friend-list(style='margin-top: 10px; min-height: 60px; max-height: 50vh')
.x-friend-item.x-friend-item-border(
v-for='avatar in userDialogAvatars'
:key='avatar.id'
@@ -1009,7 +1039,7 @@ mixin userDialog
icon='el-icon-download'
circle
style='margin-left: 5px')
el-tree(:data='userDialog.treeData' style='margin-top: 5px; font-size: 12px')
el-tree(:data='userDialog.treeData' style='margin-top: 5px; font-size: 12px; height: 50vh')
template(#default='scope')
span
span(v-text='scope.data.key' style='font-weight: bold; margin-right: 5px')

View File

@@ -220,7 +220,12 @@ mixin worldDialog
location-world(
:locationobject='room.$location'
:currentuserid='API.currentUser.id'
:worlddialogshortname='worldDialog.$location.shortName')
:worlddialogshortname='worldDialog.$location.shortName'
@show-launch-dialog='showLaunchDialog')
launch(
:location='room.tag'
@show-launch-dialog='showLaunchDialog'
style='margin-left: 5px')
el-tooltip(
placement='top'
:content='$t("dialog.world.instances.self_invite_tooltip")'
@@ -239,6 +244,18 @@ mixin worldDialog
icon='el-icon-refresh'
style='margin-left: 5px'
circle)
el-tooltip(
v-if='instanceJoinHistory.get(room.$location.tag)'
placement='top'
:content='$t("dialog.previous_instances.info")'
:disabled='hideTooltips')
el-button(
@click='showPreviousInstanceInfoDialog(room.location)'
size='mini'
icon='el-icon-s-data'
style='margin-left: 5px'
plain
circle)
last-join(:location='room.$location.tag' :currentlocation='lastLocation.location')
instance-info(
:location='room.tag'
@@ -273,7 +290,7 @@ mixin worldDialog
timer(:epoch='user.$travelingToTime')
span.extra(v-else)
timer(:epoch='user.$location_at')
el-tab-pane(:label='$t("dialog.world.info.header")')
el-tab-pane(:label='$t("dialog.world.info.header")' lazy)
.x-friend-list(style='max-height: none')
.x-friend-item(style='width: 100%; cursor: default')
.detail
@@ -387,16 +404,20 @@ mixin worldDialog
:content='$t("dialog.world.info.accuracy_notice")')
i.el-icon-warning
span.extra {{ worldDialog.lastVisit | formatDate('long') }}
.x-friend-item(@click='showPreviousInstancesWorldDialog(worldDialog.ref)')
.detail
span.name {{ $t('dialog.world.info.visit_count') }}
el-tooltip(
v-if='!hideTooltips'
placement='top'
style='margin-left: 5px'
:content='$t("dialog.world.info.accuracy_notice")')
i.el-icon-warning
span.extra(v-text='worldDialog.visitCount')
el-tooltip(
:disabled='hideTooltips'
placement='top'
:content='$t("dialog.user.info.open_previouse_instance")')
.x-friend-item(@click='showPreviousInstancesWorldDialog(worldDialog.ref)')
.detail
span.name {{ $t('dialog.world.info.visit_count') }}
el-tooltip(
v-if='!hideTooltips'
placement='top'
style='margin-left: 5px'
:content='$t("dialog.world.info.accuracy_notice")')
i.el-icon-warning
span.extra(v-text='worldDialog.visitCount')
.x-friend-item(style='cursor: default')
.detail
span.name {{ $t('dialog.world.info.time_spent') }}
@@ -408,7 +429,7 @@ mixin worldDialog
i.el-icon-warning
span.extra(v-if='worldDialog.timeSpent === 0') -
span.extra(v-else) {{ timeToText(worldDialog.timeSpent) }}
el-tab-pane(:label='$t("dialog.world.json.header")')
el-tab-pane(:label='$t("dialog.world.json.header")' lazy)
el-button(
type='default'
@click='refreshWorldDialogTreeData()'

View File

@@ -1,6 +1,7 @@
mixin friendsListSidebar
#aside.x-aside-container(
v-show='$refs.menu && !($refs.menu.activeIndex == "friendsList" || $refs.menu.activeIndex == "charts") ')
: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'

View File

@@ -1,5 +1,5 @@
mixin friendsListTab
.x-container(v-if='$refs.menu && $refs.menu.activeIndex === "friendsList"')
.x-container(v-show='$refs.menu && $refs.menu.activeIndex === "friendsList"')
.options-container(style='margin-top: 0')
span.header {{ $t('view.friend_list.header') }}
div(style='float: right; font-size: 13px')

View File

@@ -103,10 +103,13 @@ mixin gameLogTab
icon='el-icon-delete'
size='mini'
@click='deleteGameLogEntryPrompt(scope.row)')
el-tooltip(placement='top' content='Open Instance Info' :disabled='hideTooltips')
el-tooltip(
placement='top'
:content='$t("dialog.previous_instances.info")'
:disabled='hideTooltips')
el-button(
v-if='scope.row.type === "Location"'
type='text'
icon='el-icon-tickets'
icon='el-icon-s-data'
size='mini'
@click='showPreviousInstanceInfoDialog(scope.row.location)')

View File

@@ -84,7 +84,8 @@ mixin playerListTab
div(style='margin-top: 5px')
location-world(
:locationobject='currentInstanceLocation'
:currentuserid='API.currentUser.id')
:currentuserid='API.currentUser.id'
@show-launch-dialog='showLaunchDialog')
span(v-if='lastLocation.playerList.size > 0' style='margin-left: 5px')
| {{ lastLocation.playerList.size }}
| #[template(v-if='lastLocation.friendList.size > 0') ({{ lastLocation.friendList.size }})]

View File

@@ -1,5 +1,5 @@
mixin settingsTab
.x-container(v-show='$refs.menu && $refs.menu.activeIndex === \'settings\'')
.x-container(v-if='$refs.menu && $refs.menu.activeIndex === "settings"')
.options-container(style='margin-top: 0; padding: 5px')
span.header {{ $t('view.settings.header') }}
el-tabs(type='card' style='height: calc(100% - 51px)')
@@ -211,7 +211,7 @@ mixin settingsTab
el-button(@click='ossDialog = true' size='small') {{ $t('view.settings.general.legal_notice.open_source_software_notice') }}
//- Appearance Tab
el-tab-pane(:label='$t("view.settings.category.appearance")')
el-tab-pane(lazy :label='$t("view.settings.category.appearance")')
//- Appearance | Appearance
.options-container(style='margin-top: 0')
span.header {{ $t('view.settings.appearance.appearance.header') }}
@@ -515,7 +515,7 @@ mixin settingsTab
span.color-picker.x-tag-troll(slot='trigger') Nuisance
//- Notifications Tab
el-tab-pane(:label='$t("view.settings.category.notifications")')
el-tab-pane(lazy :label='$t("view.settings.category.notifications")')
//- Notifications | Notifications
.options-container(style='margin-top: 0')
span.header {{ $t('view.settings.notifications.notifications.header') }}
@@ -653,7 +653,7 @@ mixin settingsTab
style='margin-left: 10px') {{ $t('view.settings.notifications.notifications.text_to_speech.play') }}
//- Wrist Overlay Tab
el-tab-pane(:label='$t("view.settings.category.wrist_overlay")' v-if='!isLinux()')
el-tab-pane(lazy :label='$t("view.settings.category.wrist_overlay")' v-if='!isLinux()')
//- Wrist Overlay | SteamVR Wrist Overlay
.options-container(style='margin-top: 0')
span.header {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.header') }}
@@ -735,7 +735,7 @@ mixin settingsTab
:disabled='!openVR || !overlayWrist')
//- Discord Presence Tab
el-tab-pane(:label='$t("view.settings.category.discord_presence")')
el-tab-pane(lazy :label='$t("view.settings.category.discord_presence")')
.options-container(style='margin-top: 0')
span.header {{ $t('view.settings.discord_presence.discord_presence.header') }}
.options-container-item
@@ -767,7 +767,7 @@ mixin settingsTab
:disabled='!discordActive')
//- "Advanced" Tab
el-tab-pane(:label='$t("view.settings.category.advanced")')
el-tab-pane(lazy :label='$t("view.settings.category.advanced")')
//- Advanced | Advanced
.options-container(style='margin-top: 0')
span.header {{ $t('view.settings.advanced.advanced.header') }}

View File

@@ -0,0 +1,158 @@
<template>
<el-dialog
ref="dialog"
:visible="visible"
:title="$t('dialog.previous_instances.info')"
width="800px"
@close="$emit('update:visible', false)"
:fullscreen="fullscreen"
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>
</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">
<template slot-scope="scope">
<el-tooltip placement="left">
<template slot="content">
<span>{{ scope.row.created_at | formatDate('long') }}</span>
</template>
<span>{{ scope.row.created_at | formatDate('short') }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column :label="$t('table.gameLog.icon')" prop="isFriend" width="70" align="center">
<template slot-scope="scope">
<template v-if="gameLogIsFriend(scope.row)">
<el-tooltip v-if="gameLogIsFavorite(scope.row)" placement="top" content="Favorite">
<span></span>
</el-tooltip>
<el-tooltip v-else placement="top" content="Friend">
<span>💚</span>
</el-tooltip>
</template>
</template>
</el-table-column>
<el-table-column :label="$t('table.previous_instances.display_name')" prop="displayName" sortable>
<template slot-scope="scope">
<span class="x-link" @click="lookupUser(scope.row)">{{ scope.row.displayName }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('table.previous_instances.time')" prop="time" width="100" sortable>
<template slot-scope="scope">
<span>{{ scope.row.timer }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('table.previous_instances.count')" prop="count" width="100" sortable>
<template slot-scope="scope">
<span>{{ scope.row.count }}</span>
</template>
</el-table-column>
</data-tables>
</el-dialog>
</template>
<script>
import utils from '../../classes/utils';
import database from '../../repository/database';
import dayjs from 'dayjs';
export default {
name: 'PreviousInstanceInfo',
inject: ['adjustDialogZ'],
props: {
visible: {
type: Boolean,
default: false
},
instanceId: { type: String, required: true },
gameLogIsFriend: { type: Function, required: true },
gameLogIsFavorite: { type: Function, required: true },
lookupUser: { type: Function, required: true },
isDarkMode: { type: Boolean, required: true }
},
data() {
return {
echarts: null,
echartsInstance: null,
loading: false,
location: {},
currentTab: 'table',
dataTable: {
data: [],
filters: [
{
prop: 'displayName',
value: ''
}
],
tableProps: {
stripe: true,
size: 'mini',
defaultSort: {
prop: 'created_at',
order: 'descending'
}
},
pageSize: 10,
paginationProps: {
small: true,
layout: 'sizes,prev,pager,next,total',
pageSizes: [10, 25, 50, 100]
}
},
fullscreen: false
};
},
watch: {
visible(value) {
if (value) {
this.$nextTick(() => {
this.init();
this.refreshPreviousInstanceInfoTable();
});
utils.loadEcharts().then((echarts) => {
this.echarts = echarts;
});
}
}
},
computed: {
activityDetailData() {
return this.dataTable.data.map((item) => ({
displayName: item.displayName,
joinTime: dayjs(item.created_at),
leaveTime: dayjs(item.created_at).add(item.time, 'ms'),
time: item.time,
timer: item.timer
}));
}
},
methods: {
init() {
this.adjustDialogZ(this.$refs.dialog.$el);
this.loading = true;
this.location = utils.parseLocation(this.instanceId);
},
refreshPreviousInstanceInfoTable() {
database.getPlayersFromInstance(this.location.tag).then((data) => {
const array = [];
for (const entry of Array.from(data.values())) {
entry.timer = utils.timeToText(entry.time);
array.push(entry);
}
array.sort(utils.compareByCreatedAt);
this.dataTable.data = array;
this.loading = false;
});
}
}
};
</script>

View File

@@ -48,15 +48,7 @@ module.exports = {
},
{
test: /\.pug$/,
oneOf: [
{
resourceQuery: /^\?vue/,
use: 'pug-plain-loader'
},
{
use: ['raw-loader', 'pug-plain-loader']
}
]
use: [{ loader: 'raw-loader' }, { loader: 'pug-plain-loader' }]
},
{
test: /\.s?css$/,
@@ -72,9 +64,9 @@ module.exports = {
]
},
resolve: {
extensions: ['.css', '.js', '.scss'],
extensions: ['.js', '.css', '.scss'],
alias: {
vue: 'vue/dist/vue.common.js'
vue: 'vue/dist/vue.esm.js'
}
},
performance: {