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
+51 -153
View File
@@ -42,6 +42,7 @@ import ChartsTab from './views/tabs/Charts.vue';
// components // components
import SimpleSwitch from './components/settings/SimpleSwitch.vue'; import SimpleSwitch from './components/settings/SimpleSwitch.vue';
import GroupsSidebar from './components/sidebar/GroupsSidebar.vue'; import GroupsSidebar from './components/sidebar/GroupsSidebar.vue';
import PreviousInstanceInfo from './views/dialogs/PreviousInstanceInfo.vue';
// main app classes // main app classes
import _sharedFeed from './classes/sharedFeed.js'; import _sharedFeed from './classes/sharedFeed.js';
@@ -114,13 +115,6 @@ console.log(`isLinux: ${LINUX}`);
}); });
// #endregion // #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 // everything in this program is global stored in $app, I hate it, it is what it is
let $app = {}; let $app = {};
const API = new _apiInit($app); const API = new _apiInit($app);
@@ -184,12 +178,15 @@ console.log(`isLinux: ${LINUX}`);
// components // components
// - sidebar(friendsListSidebar) // - sidebar(friendsListSidebar)
GroupsSidebar GroupsSidebar,
// - dialogs
PreviousInstanceInfo
}, },
provide() { provide() {
return { return {
API, API,
showUserDialog: this.showUserDialog showUserDialog: this.showUserDialog,
adjustDialogZ: this.adjustDialogZ
}; };
}, },
el: '#x-app', el: '#x-app',
@@ -224,9 +221,6 @@ console.log(`isLinux: ${LINUX}`);
API.$on('SHOW_GROUP_DIALOG', (groupId) => API.$on('SHOW_GROUP_DIALOG', (groupId) =>
this.showGroupDialog(groupId) this.showGroupDialog(groupId)
); );
API.$on('SHOW_LAUNCH_DIALOG', (tag, shortName) =>
this.showLaunchDialog(tag, shortName)
);
this.updateLoop(); this.updateLoop();
this.getGameLogTable(); this.getGameLogTable();
this.refreshCustomCss(); this.refreshCustomCss();
@@ -338,7 +332,7 @@ console.log(`isLinux: ${LINUX}`);
// #endregion // #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({ Noty.overrideDefaults({
animation: { animation: {
@@ -365,6 +359,10 @@ console.log(`isLinux: ${LINUX}`);
Vue.use(DataTables); Vue.use(DataTables);
dayjs.extend(duration);
dayjs.extend(utc);
dayjs.extend(timezone);
// #endregion // #endregion
// #endregion // #endregion
@@ -485,23 +483,24 @@ console.log(`isLinux: ${LINUX}`);
} }
}; };
// FIXME: it may performance issue. review here
API.applyUserLanguage = function (ref) { API.applyUserLanguage = function (ref) {
if (!ref || !ref.tags || !$app.subsetOfLanguages) {
return;
}
ref.$languages = []; ref.$languages = [];
var { tags } = ref; const languagePrefix = 'language_';
for (var tag of tags) { const prefixLength = languagePrefix.length;
if (tag.startsWith('language_') === false) {
continue; 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) { $app.methods.selectMenu = function (index) {
// NOTE
// 툴팁이 쌓여서 느려지기 때문에 날려줌.
// 근데 이 방법이 안전한지는 모르겠음
document.querySelectorAll('[role="tooltip"]').forEach((node) => {
node.remove();
});
var item = this.$refs.menu.items[index]; var item = this.$refs.menu.items[index];
if (item) { if (item) {
item.$el.classList.remove('notify'); item.$el.classList.remove('notify');
@@ -3906,27 +3899,6 @@ console.log(`isLinux: ${LINUX}`);
} else if (index === 'friendsList') { } else if (index === 'friendsList') {
this.friendsListSearchChange(); 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; $app.data.twoFactorAuthDialogVisible = false;
@@ -4933,25 +4905,6 @@ console.log(`isLinux: ${LINUX}`);
return 0; 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) { var compareByMemberCount = function (a, b) {
if ( if (
typeof a.memberCount !== 'number' || typeof a.memberCount !== 'number' ||
@@ -6894,7 +6847,7 @@ console.log(`isLinux: ${LINUX}`);
avatarsArray.sort(compareByUpdatedAt); avatarsArray.sort(compareByUpdatedAt);
break; break;
case 'created': case 'created':
avatarsArray.sort(compareByCreatedAt); avatarsArray.sort($utils.compareByCreatedAt);
break; break;
case 'name': case 'name':
avatarsArray.sort(compareByName); avatarsArray.sort(compareByName);
@@ -8236,18 +8189,6 @@ console.log(`isLinux: ${LINUX}`);
'VRCX_sidePanelWidth', 'VRCX_sidePanelWidth',
300 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( $app.data.autoUpdateVRCX = await configRepository.getString(
'VRCX_autoUpdateVRCX', 'VRCX_autoUpdateVRCX',
'Auto Download' 'Auto Download'
@@ -11442,8 +11383,9 @@ console.log(`isLinux: ${LINUX}`);
D.treeData = $utils.buildTreeData(D.ref); D.treeData = $utils.buildTreeData(D.ref);
}; };
$app.methods.changeUserDialogAvatarSorting = function () { $app.methods.changeUserDialogAvatarSorting = function (sortOption) {
var D = this.userDialog; const D = this.userDialog;
D.avatarSorting = sortOption;
this.sortUserDialogAvatars(D.avatars); this.sortUserDialogAvatars(D.avatars);
}; };
@@ -15396,18 +15338,20 @@ console.log(`isLinux: ${LINUX}`);
// }; // };
$app.methods.friendsListSearchChange = function () { $app.methods.friendsListSearchChange = function () {
let query;
let cleanedQuery;
this.friendsListTable.data = []; this.friendsListTable.data = [];
var filters = [...this.friendsListSearchFilters]; let filters = [...this.friendsListSearchFilters];
if (filters.length === 0) { if (filters.length === 0) {
filters = ['Display Name', 'Rank', 'Status', 'Bio', 'Memo']; filters = ['Display Name', 'Rank', 'Status', 'Bio', 'Memo'];
} }
var results = []; const results = [];
if (this.friendsListSearch) { if (this.friendsListSearch) {
var query = this.friendsListSearch; query = this.friendsListSearch;
var cleanedQuery = removeWhitespace(query); cleanedQuery = removeWhitespace(query);
} }
for (var ctx of this.friends.values()) { for (const ctx of this.friends.values()) {
if (typeof ctx.ref === 'undefined') { if (typeof ctx.ref === 'undefined') {
continue; continue;
} }
@@ -15418,7 +15362,7 @@ console.log(`isLinux: ${LINUX}`);
continue; continue;
} }
if (query && filters) { if (query && filters) {
var match = false; let match = false;
if ( if (
!match && !match &&
filters.includes('Display Name') && filters.includes('Display Name') &&
@@ -15473,7 +15417,9 @@ console.log(`isLinux: ${LINUX}`);
results.push(ctx.ref); results.push(ctx.ref);
} }
this.getAllUserStats(); this.getAllUserStats();
this.friendsListTable.data = results; requestAnimationFrame(() => {
this.friendsListTable.data = results;
});
}; };
$app.methods.getAllUserStats = async function () { $app.methods.getAllUserStats = async function () {
@@ -19016,7 +18962,6 @@ console.log(`isLinux: ${LINUX}`);
}; };
$app.methods.setAsideWidth = async function () { $app.methods.setAsideWidth = async function () {
document.getElementById('aside').style.width = `${this.asideWidth}px`;
await configRepository.setInt('VRCX_sidePanelWidth', this.asideWidth); await configRepository.setInt('VRCX_sidePanelWidth', this.asideWidth);
}; };
@@ -19574,7 +19519,7 @@ console.log(`isLinux: ${LINUX}`);
} }
array.push(ref); array.push(ref);
} }
array.sort(compareByCreatedAt); array.sort($utils.compareByCreatedAt);
this.previousInstancesUserDialogTable.data = array; this.previousInstancesUserDialogTable.data = array;
D.loading = false; D.loading = false;
workerTimers.setTimeout(() => D.forceUpdate++, 150); workerTimers.setTimeout(() => D.forceUpdate++, 150);
@@ -19677,7 +19622,7 @@ console.log(`isLinux: ${LINUX}`);
} }
array.push(ref); array.push(ref);
} }
array.sort(compareByCreatedAt); array.sort($utils.compareByCreatedAt);
this.previousInstancesWorldDialogTable.data = array; this.previousInstancesWorldDialogTable.data = array;
D.loading = false; D.loading = false;
workerTimers.setTimeout(() => D.forceUpdate++, 150); workerTimers.setTimeout(() => D.forceUpdate++, 150);
@@ -19707,61 +19652,12 @@ console.log(`isLinux: ${LINUX}`);
// #endregion // #endregion
// #region | App: Previous Instance Info Dialog // #region | App: Previous Instance Info Dialog
$app.data.previousInstanceInfoDialogTable = { $app.data.previousInstanceInfoDialogVisible = false;
data: [], $app.data.previousInstanceInfoDialogInstanceId = '';
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.methods.showPreviousInstanceInfoDialog = function (instanceId) { $app.methods.showPreviousInstanceInfoDialog = function (instanceId) {
this.$nextTick(() => this.previousInstanceInfoDialogVisible = true;
$app.adjustDialogZ(this.$refs.previousInstanceInfoDialog.$el) this.previousInstanceInfoDialogInstanceId = instanceId;
);
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);
});
}; };
$app.data.dtHour12 = await configRepository.getBool('VRCX_dtHour12', false); $app.data.dtHour12 = await configRepository.getBool('VRCX_dtHour12', false);
@@ -22231,7 +22127,7 @@ console.log(`isLinux: ${LINUX}`);
$app.methods.updateLocalFavoriteFriends = function () { $app.methods.updateLocalFavoriteFriends = function () {
this.localFavoriteFriends.clear(); this.localFavoriteFriends.clear();
this.localFavoriteFriendsDivideByGroup.clear(); this.localFavoriteFriendsDivideByGroup.clear();
for (var ref of API.cachedFavorites.values()) { for (const ref of API.cachedFavorites.values()) {
if ( if (
!ref.$isDeleted && !ref.$isDeleted &&
ref.type === 'friend' && ref.type === 'friend' &&
@@ -23471,7 +23367,9 @@ console.log(`isLinux: ${LINUX}`);
} }
} }
} }
if (!locationTag) return; if (!locationTag) {
return;
}
if (!friendsList[locationTag]) { if (!friendsList[locationTag]) {
friendsList[locationTag] = []; friendsList[locationTag] = [];
+2 -6
View File
@@ -672,8 +672,8 @@ i.x-status-icon.red {
} }
.x-tag-age-verification { .x-tag-age-verification {
color: #5C70EC !important; color: #5c70ec !important;
border-color: #5C70EC !important; border-color: #5c70ec !important;
} }
.x-grey { .x-grey {
@@ -865,10 +865,6 @@ i.x-status-icon.red {
margin-right: 20px; margin-right: 20px;
} }
.el-tab-pane {
height: 100%;
}
.el-tabs { .el-tabs {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
-1
View File
@@ -108,7 +108,6 @@ export default class extends baseClass {
visible: false, visible: false,
loading: false, loading: false,
languageChoice: false, languageChoice: false,
languageValue: '',
languages: [] languages: []
} }
}; };
+9 -8
View File
@@ -12,9 +12,10 @@ export default class extends baseClass {
Vue.component('launch', { Vue.component('launch', {
template: 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: { props: {
location: String location: String,
hideTooltips: Boolean
}, },
methods: { methods: {
parse() { parse() {
@@ -25,7 +26,7 @@ export default class extends baseClass {
: 'none'; : 'none';
}, },
confirm() { confirm() {
API.$emit('SHOW_LAUNCH_DIALOG', this.location); this.$emit('show-launch-dialog', this.location);
} }
}, },
watch: { watch: {
@@ -279,8 +280,8 @@ export default class extends baseClass {
} }
}, },
showLaunchDialog() { showLaunchDialog() {
API.$emit( this.$emit(
'SHOW_LAUNCH_DIALOG', 'show-launch-dialog',
this.location, this.location,
this.shortName this.shortName
); );
@@ -308,12 +309,12 @@ export default class extends baseClass {
Vue.component('last-join', { Vue.component('last-join', {
template: template:
'<span>' + '<span v-if="lastJoin">' +
'<el-tooltip placement="top" style="margin-left:5px" v-if="lastJoin">' + '<el-tooltip placement="top" style="margin-left:5px" >' +
'<div slot="content">' + '<div slot="content">' +
'<span>{{ $t("dialog.user.info.last_join") }} <timer :epoch="lastJoin"></timer></span>' + '<span>{{ $t("dialog.user.info.last_join") }} <timer :epoch="lastJoin"></timer></span>' +
'</div>' + '</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>' + '</el-tooltip>' +
'</span>', '</span>',
props: { props: {
+20
View File
@@ -322,6 +322,26 @@ export default {
}); });
return node; 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 // lazy load echarts
loadEcharts() { loadEcharts() {
if (echarts) { if (echarts) {
+41 -42
View File
@@ -15,8 +15,8 @@
</div> </div>
<i <i
class="el-icon-info"
slot="reference" slot="reference"
class="el-icon-info"
style="margin-left: 5px; font-size: 12px; opacity: 0.7" style="margin-left: 5px; font-size: 12px; opacity: 0.7"
></i> ></i>
</el-popover> </el-popover>
@@ -103,7 +103,7 @@
</div> </div>
<transition name="el-fade-in-linear"> <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> <el-divider>·</el-divider>
</div> </div>
</transition> </transition>
@@ -255,19 +255,19 @@
}, },
async mounted() { async mounted() {
try { try {
this.getAllDateOfActivity();
const [echartsModule] = await Promise.all([ const [echartsModule] = await Promise.all([
// lazy load echarts // lazy load echarts
utils.loadEcharts().catch((error) => { utils.loadEcharts().catch((error) => {
console.error('lazy load echarts failed', error); console.error('lazy load echarts failed', error);
return null; return null;
}), }),
this.getActivityData(), this.getActivityData()
this.getAllDateOfActivity()
]); ]);
if (echartsModule) { if (echartsModule) {
this.echarts = echartsModule; this.echarts = echartsModule;
} }
if (this.activityData.length && this.echarts) { if (echartsModule) {
// activity data is ready, but world name data isn't ready // activity data is ready, but world name data isn't ready
// so init echarts with empty data, reduce the render time of init screen // so init echarts with empty data, reduce the render time of init screen
this.initEcharts(true); this.initEcharts(true);
@@ -284,10 +284,12 @@
this.isLoading = true; this.isLoading = true;
await this.getActivityData(); await this.getActivityData();
this.getWorldNameData(); this.getWorldNameData();
// possibility past 24:00
this.getAllDateOfActivity();
}, },
// echarts - start // echarts - start
initEcharts(isFirstTime = false) { initEcharts() {
const chartsHeight = this.activityData.length * (this.barWidth + 10) + 200; const chartsHeight = this.activityData.length * (this.barWidth + 10) + 200;
const chartDom = this.$refs.activityChartRef; const chartDom = this.$refs.activityChartRef;
if (!this.echartsInstance) { 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.echartsInstance.on('click', 'yAxis', handleClickYAxisLabel);
this.isLoading = false; this.isLoading = false;
}, },
getNewOption(isFirstTime) { getNewOption() {
const getTooltip = (params) => { const getTooltip = (params) => {
const activityData = this.activityData; const activityData = this.activityData;
const param = params[1]; const param = params[1];
@@ -412,17 +416,15 @@
color: 'transparent' color: 'transparent'
} }
}, },
data: isFirstTime data: this.activityData.map((item, idx) => {
? [] if (idx === 0) {
: this.activityData.map((item, idx) => { const midnight = dayjs.tz(this.selectedDate).startOf('day');
if (idx === 0) { if (midnight.isAfter(item.joinTime)) {
const midnight = dayjs.tz(this.selectedDate).startOf('day'); return 0;
if (midnight.isAfter(item.joinTime)) { }
return 0; }
} return item.joinTime - dayjs.tz(this.selectedDate).startOf('day');
} })
return item.joinTime - dayjs.tz(this.selectedDate).startOf('day');
})
}, },
{ {
name: 'Time', name: 'Time',
@@ -439,19 +441,17 @@
shadowOffsetX: 0.7, shadowOffsetX: 0.7,
shadowOffsetY: 0.5 shadowOffsetY: 0.5
}, },
data: isFirstTime data: this.activityData.map((item, idx) => {
? [] // If the joinTime of the first data is on the previous day,
: this.activityData.map((item, idx) => { // and the data traverses midnight, the duration starts at midnight
// If the joinTime of the first data is on the previous day, if (idx === 0) {
// and the data traverses midnight, the duration starts at midnight const midnight = dayjs.tz(this.selectedDate).startOf('day');
if (idx === 0) { if (midnight.isAfter(item.joinTime)) {
const midnight = dayjs.tz(this.selectedDate).startOf('day'); return item.leaveTime - dayjs.tz(midnight);
if (midnight.isAfter(item.joinTime)) { }
return item.leaveTime - dayjs.tz(midnight); }
} return item.time;
} })
return item.time;
})
} }
], ],
backgroundColor: 'transparent' backgroundColor: 'transparent'
@@ -545,7 +545,8 @@
} }
}) })
); );
if (this.worldNameArray && this.echartsInstance) {
if (this.worldNameArray) {
this.initEcharts(); this.initEcharts();
} }
}, },
@@ -599,9 +600,11 @@
this.API.currentUser.id this.API.currentUser.id
); );
this.$nextTick(() => { if (this.activityDetailData.length) {
this.handleIntersectionObserver(); this.$nextTick(() => {
}); this.handleIntersectionObserver();
});
}
}, },
handleSplitActivityDetailData(activityDetailData, currentUserId) { handleSplitActivityDetailData(activityDetailData, currentUserId) {
function countTargetIdOccurrences(innerArray, targetId) { function countTargetIdOccurrences(innerArray, targetId) {
@@ -685,11 +688,7 @@
// intersection observer - start // intersection observer - start
handleIntersectionObserver() { handleIntersectionObserver() {
if (!this.$refs.activityDetailChartRef) { this.$refs.activityDetailChartRef?.forEach((child, index) => {
console.error('handleIntersectionObserver failed');
return;
}
this.$refs.activityDetailChartRef.forEach((child, index) => {
const observer = new IntersectionObserver(this.handleIntersection.bind(this, index)); const observer = new IntersectionObserver(this.handleIntersection.bind(this, index));
observer.observe(child.$el); observer.observe(child.$el);
this.intersectionObservers[index] = observer; this.intersectionObservers[index] = observer;
@@ -771,7 +770,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin-top: 200px; margin-top: 100px;
color: #5c5c5c; color: #5c5c5c;
} }
.divider { .divider {
+1 -2
View File
@@ -109,8 +109,7 @@ html
:dt-hour12='dtHour12' :dt-hour12='dtHour12'
@open-previous-instance-info-dialog='showPreviousInstanceInfoDialog' @open-previous-instance-info-dialog='showPreviousInstanceInfoDialog'
:friends-map='friends' :friends-map='friends'
:local-favorite-friends='localFavoriteFriends' :local-favorite-friends='localFavoriteFriends')
)
//- settings //- settings
include ./mixins/tabs/settings.pug include ./mixins/tabs/settings.pug
+2 -2
View File
@@ -710,8 +710,8 @@
"avatars": { "avatars": {
"header": "Avatars", "header": "Avatars",
"total_count": "Total {count}", "total_count": "Total {count}",
"sort_by_name": "Sort by name", "sort_by_name": "Name",
"sort_by_update": "Sort by update", "sort_by_update": "Updated",
"all": "All", "all": "All",
"public": "Public", "public": "Public",
"private": "Private" "private": "Private"
+7 -4
View File
@@ -782,7 +782,8 @@
"instance_closed": "closed", "instance_closed": "closed",
"instance_hard_closed": "hard closed", "instance_hard_closed": "hard closed",
"close_instance": "Close Instance", "close_instance": "Close Instance",
"instance_age_gated": "age gated" "instance_age_gated": "age gated",
"open_previouse_instance": "Open Previous Instance"
}, },
"groups": { "groups": {
"header": "Groups", "header": "Groups",
@@ -824,11 +825,13 @@
"avatars": { "avatars": {
"header": "Avatars", "header": "Avatars",
"total_count": "Total {count}", "total_count": "Total {count}",
"sort_by_name": "Sort by name", "sort_by": "Sort by:",
"sort_by_update": "Sort by update", "sort_by_name": "Name",
"sort_by_update": "Updated",
"all": "All", "all": "All",
"public": "Public", "public": "Public",
"private": "Private" "private": "Private",
"group_by": "Group by:"
}, },
"json": { "json": {
"header": "JSON" "header": "JSON"
+1
View File
@@ -815,6 +815,7 @@
"avatars": { "avatars": {
"header": "アバター", "header": "アバター",
"total_count": "{count} 個のアバター", "total_count": "{count} 個のアバター",
"sort_by": "並べ替え:",
"sort_by_name": "名前順", "sort_by_name": "名前順",
"sort_by_update": "更新順", "sort_by_update": "更新順",
"all": "全て", "all": "全て",
+4 -2
View File
@@ -821,8 +821,10 @@
"avatars": { "avatars": {
"header": "创建的模型", "header": "创建的模型",
"total_count": "总共 {count} 个", "total_count": "总共 {count} 个",
"sort_by_name": "按名称排序", "sort_by": "排序方式:",
"sort_by_update": "按更新时间排序", "sort_by_name": "名称",
"sort_by_update": "更新时间",
"group_by": "分组方式:",
"all": "所有", "all": "所有",
"public": "公开", "public": "公开",
"private": "私人" "private": "私人"
+3 -2
View File
@@ -787,8 +787,9 @@
"avatars": { "avatars": {
"header": "角色", "header": "角色",
"total_count": "總共 {count}", "total_count": "總共 {count}",
"sort_by_name": "依名稱排序", "sort_by": "分類依據:",
"sort_by_update": "依更新排序", "sort_by_name": "名稱",
"sort_by_update": "更新",
"all": "所有", "all": "所有",
"public": "公開", "public": "公開",
"private": "私人" "private": "私人"
+15 -23
View File
@@ -52,10 +52,8 @@ mixin currentUser
:title='$t("dialog.language.header")' :title='$t("dialog.language.header")'
width='400px') width='400px')
div(v-loading='languageDialog.loading') 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( el-tag(
v-for='item in API.currentUser.$languages'
:key='item.key'
size='small' size='small'
type='info' type='info'
effect='plain' effect='plain'
@@ -63,26 +61,20 @@ mixin currentUser
@close='removeUserLanguage(item.key)' @close='removeUserLanguage(item.key)'
style='margin-right: 5px') style='margin-right: 5px')
span.flags(:class='languageClass(item.key)' style='display: inline-block; margin-right: 5px') span.flags(:class='languageClass(item.key)' style='display: inline-block; margin-right: 5px')
| {{ item.value }} ({{ item.key }}) | {{ item.value }} ({{ item.key.toUpperCase() }})
div(v-if='languageDialog.languageChoice === true') el-select(
el-select( value=''
v-model='languageDialog.languageValue' :disabled='languageDialog.loading || (API.currentUser.$languages && API.currentUser.$languages.length === 3)'
:placeholder='$t("dialog.language.select_language")' :placeholder='$t("dialog.language.select_language")'
size='mini') @change='addUserLanguage'
el-option( style='margin-top: 14px')
v-for='item in languageDialog.languages' el-option(
:key='item.key' v-for='item in languageDialog.languages'
:value='item.key' :key='item.key'
:label='item.value') :value='item.key'
span.flags(:class='languageClass(item.key)' style='display: inline-block; margin-right: 5px') :label='item.value')
| {{ item.value }} ({{ item.key }}) span.flags(:class='languageClass(item.key)' style='display: inline-block; margin-right: 5px')
el-button( | {{ item.value }} ({{ item.key.toUpperCase() }})
@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') }}
//- dialog: bio //- dialog: bio
el-dialog.x-dialog( el-dialog.x-dialog(
:before-close='beforeDialogClose' :before-close='beforeDialogClose'
+4 -4
View File
@@ -470,7 +470,7 @@ mixin groupDialog
span(:key='pIndex') {{ permission }} span(:key='pIndex') {{ permission }}
br br
span {{ role.name }}{{ rIndex < groupDialog.memberRoles.length - 1 ? ', ' : '' }} 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') template(v-if='groupDialog.visible')
span(style='margin-right: 10px') {{ $t('dialog.group.posts.posts_count') }} {{ groupDialog.posts.length }} span(style='margin-right: 10px') {{ $t('dialog.group.posts.posts_count') }} {{ groupDialog.posts.length }}
el-input( el-input(
@@ -544,7 +544,7 @@ mixin groupDialog
size='mini' size='mini'
style='margin-left: 5px' style='margin-left: 5px'
@click='confirmDeleteGroupPost(post)') @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') template(v-if='groupDialog.visible')
span( span(
v-if='hasGroupPermission(groupDialog.ref, "group-members-viewall")' v-if='hasGroupPermission(groupDialog.ref, "group-members-viewall")'
@@ -704,7 +704,7 @@ mixin groupDialog
@click='loadMoreGroupMembers') @click='loadMoreGroupMembers')
.detail(v-if='!isGroupMembersLoading') .detail(v-if='!isGroupMembersLoading')
span.name {{ $t('dialog.group.members.load_more') }} 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( el-button(
type='default' type='default'
size='mini' size='mini'
@@ -737,7 +737,7 @@ mixin groupDialog
v-lazy='image.imageUrl' v-lazy='image.imageUrl'
style='height: 700px' style='height: 700px'
@click='showFullscreenImageDialog(image.imageUrl)') @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( el-button(
type='default' type='default'
@click='refreshGroupDialogTreeData()' @click='refreshGroupDialogTreeData()'
+24 -57
View File
@@ -8,11 +8,12 @@ mixin previousInstances
:visible.sync='previousInstancesUserDialog.visible' :visible.sync='previousInstancesUserDialog.visible'
:title='$t("dialog.previous_instances.header")' :title='$t("dialog.previous_instances.header")'
width='1000px') width='1000px')
span(v-text='previousInstancesUserDialog.userRef.displayName' style='font-size: 14px') div(style='display: flex; align-items: center; justify-content: space-between')
el-input( span(v-text='previousInstancesUserDialog.userRef.displayName' style='font-size: 14px')
v-model='previousInstancesUserDialogTable.filters[0].value' el-input(
:placeholder='$t("dialog.previous_instances.search_placeholder")' v-model='previousInstancesUserDialogTable.filters[0].value'
style='display: block; width: 150px; margin-top: 15px') :placeholder='$t("dialog.previous_instances.search_placeholder")'
style='display: block; width: 150px')
data-tables( data-tables(
v-if='previousInstancesUserDialog.visible' v-if='previousInstancesUserDialog.visible'
v-bind='previousInstancesUserDialogTable' v-bind='previousInstancesUserDialogTable'
@@ -40,12 +41,12 @@ mixin previousInstances
template(#default='scope') template(#default='scope')
el-button( el-button(
type='text' type='text'
icon='el-icon-info' icon='el-icon-switch-button'
size='mini' size='mini'
@click='showLaunchDialog(scope.row.location)') @click='showLaunchDialog(scope.row.location)')
el-button( el-button(
type='text' type='text'
icon='el-icon-tickets' icon='el-icon-s-data'
size='mini' size='mini'
@click='showPreviousInstanceInfoDialog(scope.row.location)') @click='showPreviousInstanceInfoDialog(scope.row.location)')
el-button( el-button(
@@ -71,11 +72,12 @@ mixin previousInstances
:visible.sync='previousInstancesWorldDialog.visible' :visible.sync='previousInstancesWorldDialog.visible'
:title='$t("dialog.previous_instances.header")' :title='$t("dialog.previous_instances.header")'
width='1000px') width='1000px')
span(v-text='previousInstancesWorldDialog.worldRef.name' style='font-size: 14px') div(style='display: flex; align-items: center; justify-content: space-between')
el-input( span(v-text='previousInstancesWorldDialog.worldRef.name' style='font-size: 14px')
v-model='previousInstancesWorldDialogTable.filters[0].value' el-input(
:placeholder='$t("dialog.previous_instances.search_placeholder")' v-model='previousInstancesWorldDialogTable.filters[0].value'
style='display: block; width: 150px; margin-top: 15px') :placeholder='$t("dialog.previous_instances.search_placeholder")'
style='display: block; width: 150px')
data-tables( data-tables(
v-if='previousInstancesWorldDialog.visible' v-if='previousInstancesWorldDialog.visible'
v-bind='previousInstancesWorldDialogTable' v-bind='previousInstancesWorldDialogTable'
@@ -89,7 +91,8 @@ mixin previousInstances
location-world( location-world(
:locationobject='scope.row.$location' :locationobject='scope.row.$location'
:grouphint='scope.row.groupName' :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') el-table-column(:label='$t("table.previous_instances.instance_creator")' prop='location')
template(#default='scope') template(#default='scope')
display-name( display-name(
@@ -103,7 +106,7 @@ mixin previousInstances
template(#default='scope') template(#default='scope')
el-button( el-button(
type='text' type='text'
icon='el-icon-tickets' icon='el-icon-s-data'
size='mini' size='mini'
@click='showPreviousInstanceInfoDialog(scope.row.location)') @click='showPreviousInstanceInfoDialog(scope.row.location)')
el-button( el-button(
@@ -120,46 +123,10 @@ mixin previousInstances
size='mini' size='mini'
@click='deleteGameLogWorldInstancePrompt(scope.row)') @click='deleteGameLogWorldInstancePrompt(scope.row)')
//- dialog Table: Previous Instance Info previous-instance-info(
el-dialog.x-dialog( :visible.sync='previousInstanceInfoDialogVisible'
:before-close='beforeDialogClose' :instance-id='previousInstanceInfoDialogInstanceId'
@mousedown.native='dialogMouseDown' :game-log-is-friend='gameLogIsFriend'
@mouseup.native='dialogMouseUp' :game-log-is-favorite='gameLogIsFavorite'
ref='previousInstanceInfoDialog' :lookup-user='lookupUser'
:visible.sync='previousInstanceInfoDialog.visible' :is-dark-mode='isDarkMode')
: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')
+1 -1
View File
@@ -87,7 +87,7 @@ mixin screenshotMetadata
el-carousel( el-carousel(
ref='screenshotMetadataCarousel' ref='screenshotMetadataCarousel'
:interval='0' :interval='0'
initial-index='1' :initial-index='1'
indicator-position='none' indicator-position='none'
arrow='always' arrow='always'
height='600px' height='600px'
+77 -47
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') style='display: flex; flex-direction: column; margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid #e4e7ed14')
div(style='flex: none') div(style='flex: none')
template(v-if='isRealInstance(userDialog.$location.tag)') template(v-if='isRealInstance(userDialog.$location.tag)')
el-tooltip( launch(:location='userDialog.$location.tag' @show-launch-dialog='showLaunchDialog')
placement='top'
:content='$t("dialog.user.info.launch_invite_tooltip")'
:disabled='hideTooltips')
launch(:location='userDialog.$location.tag')
el-tooltip( el-tooltip(
placement='top' placement='top'
:content='$t("dialog.user.info.self_invite_tooltip")' :content='$t("dialog.user.info.self_invite_tooltip")'
@@ -509,17 +505,21 @@ mixin userDialog
:content='$t("dialog.user.info.accuracy_notice")') :content='$t("dialog.user.info.accuracy_notice")')
i.el-icon-warning i.el-icon-warning
span.extra {{ userDialog.lastSeen | formatDate('long') }} span.extra {{ userDialog.lastSeen | formatDate('long') }}
.x-friend-item(@click='showPreviousInstancesUserDialog(userDialog.ref)') el-tooltip(
.detail :disabled='hideTooltips'
span.name {{ $t('dialog.user.info.join_count') }} placement='top'
el-tooltip( :content='$t("dialog.user.info.open_previouse_instance")')
v-if='!hideTooltips' .x-friend-item(@click='showPreviousInstancesUserDialog(userDialog.ref)')
placement='top' .detail
style='margin-left: 5px' span.name {{ $t('dialog.user.info.join_count') }}
:content='$t("dialog.user.info.accuracy_notice")') el-tooltip(
i.el-icon-warning v-if='!hideTooltips'
span.extra(v-if='userDialog.joinCount === 0') - placement='top'
span.extra(v-else v-text='userDialog.joinCount') 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') .x-friend-item(style='cursor: default')
.detail .detail
span.name {{ $t('dialog.user.info.time_together') }} span.name {{ $t('dialog.user.info.time_together') }}
@@ -532,6 +532,10 @@ mixin userDialog
span.extra(v-if='userDialog.timeSpent === 0') - span.extra(v-if='userDialog.timeSpent === 0') -
span.extra(v-else) {{ timeToText(userDialog.timeSpent) }} span.extra(v-else) {{ timeToText(userDialog.timeSpent) }}
template(v-else) 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)') .x-friend-item(@click='showPreviousInstancesUserDialog(userDialog.ref)')
.detail .detail
span.name {{ $t('dialog.user.info.play_time') }} span.name {{ $t('dialog.user.info.play_time') }}
@@ -544,7 +548,7 @@ mixin userDialog
span.extra(v-if='userDialog.timeSpent === 0') - span.extra(v-if='userDialog.timeSpent === 0') -
span.extra(v-else) {{ timeToText(userDialog.timeSpent) }} span.extra(v-else) {{ timeToText(userDialog.timeSpent) }}
.x-friend-item(style='cursor: default') .x-friend-item(style='cursor: default')
el-tooltip(placement='top') el-tooltip(:placement='API.currentUser.id !== userDialog.id ? "bottom" : "top"')
template(#content) template(#content)
span {{ userOnlineForTimestamp(userDialog) | formatDate('short') }} span {{ userOnlineForTimestamp(userDialog) | formatDate('short') }}
.detail .detail
@@ -564,7 +568,7 @@ mixin userDialog
i.el-icon-warning i.el-icon-warning
span.extra {{ userOnlineFor(userDialog) }} span.extra {{ userOnlineFor(userDialog) }}
.x-friend-item(style='cursor: default') .x-friend-item(style='cursor: default')
el-tooltip(placement='top') el-tooltip(:placement='API.currentUser.id !== userDialog.id ? "bottom" : "top"')
template(#content) template(#content)
span {{ $t('dialog.user.info.last_login') }} {{ userDialog.ref.last_login | formatDate('short') }} span {{ $t('dialog.user.info.last_login') }} {{ userDialog.ref.last_login | formatDate('short') }}
.detail .detail
@@ -575,13 +579,11 @@ mixin userDialog
span.name {{ $t('dialog.user.info.date_joined') }} span.name {{ $t('dialog.user.info.date_joined') }}
span.extra(v-text='userDialog.ref.date_joined') span.extra(v-text='userDialog.ref.date_joined')
.x-friend-item(v-if='API.currentUser.id !== userDialog.id' style='cursor: default') .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(#content v-if='userDialog.dateFriendedInfo.length')
template(v-for='ref in userDialog.dateFriendedInfo') template(v-for='ref in userDialog.dateFriendedInfo')
span {{ ref.type }}: {{ ref.created_at | formatDate('long') }} span {{ ref.type }}: {{ ref.created_at | formatDate('long') }}
br br
template(#content v-else)
span -
.detail .detail
span.name(v-if='userDialog.unFriended') {{ $t('dialog.user.info.unfriended') }} span.name(v-if='userDialog.unFriended') {{ $t('dialog.user.info.unfriended') }}
el-tooltip( el-tooltip(
@@ -912,26 +914,30 @@ mixin userDialog
span.extra(v-if='world.occupants') ({{ world.occupants }}) span.extra(v-if='world.occupants') ({{ world.occupants }})
el-tab-pane(:label='$t("dialog.user.favorite_worlds.header")' lazy) el-tab-pane(:label='$t("dialog.user.favorite_worlds.header")' lazy)
el-button( el-button(
v-if='userFavoriteWorlds && userFavoriteWorlds.length > 0'
type='default' type='default'
:loading='userDialog.isFavoriteWorldsLoading' :loading='userDialog.isFavoriteWorldsLoading'
@click='getUserFavoriteWorlds(userDialog.id)' @click='getUserFavoriteWorlds(userDialog.id)'
size='mini' size='small'
icon='el-icon-refresh' icon='el-icon-refresh'
circle) circle
style='position: absolute; right: 15px; bottom: 15px; z-index: 99')
el-tabs.zero-margin-tabs( el-tabs.zero-margin-tabs(
type='card' type='card'
stretch
ref='favoriteWorlds' ref='favoriteWorlds'
v-loading='userDialog.isFavoriteWorldsLoading' v-loading='userDialog.isFavoriteWorldsLoading'
style='margin-top: 10px') style='margin-top: 10px; height: 50vh')
template(v-for='(list, index) in userFavoriteWorlds') template(v-if='userFavoriteWorlds && userFavoriteWorlds.length > 0')
el-tab-pane(:key='index' lazy) el-tab-pane(v-for='(list, index) in userFavoriteWorlds' :key='index' lazy)
span(slot='label') span(slot='label')
span(v-text='list[0]' style='font-weight: bold; font-size: 16px')
i.x-status-icon( i.x-status-icon(
style='margin-left: 5px' style='margin-right: 6px'
:class='userFavoriteWorldsStatus(list[1])') :class='userFavoriteWorldsStatus(list[1])')
span(style='color: #909399; font-size: 12px; margin-left: 5px') {{ list[2].length }}/{{ API.favoriteLimits.maxFavoritesPerGroup.world }} span(v-text='list[0]' style='font-weight: bold; font-size: 14px')
.x-friend-list(style='margin-top: 10px; margin-bottom: 15px; min-height: 60px') 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( .x-friend-item.x-friend-item-border(
v-for='world in list[2]' v-for='world in list[2]'
:key='world.favoriteId' :key='world.favoriteId'
@@ -941,6 +947,9 @@ mixin userDialog
.detail .detail
span.name(v-text='world.name') span.name(v-text='world.name')
span.extra(v-if='world.occupants') ({{ world.occupants }}) 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) 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; justify-content: space-between')
div(style='display: flex; align-items: center') div(style='display: flex; align-items: center')
@@ -962,22 +971,43 @@ mixin userDialog
circle) circle)
span(style='margin-left: 5px') {{ $t('dialog.user.avatars.total_count', { count: userDialogAvatars.length }) }} span(style='margin-left: 5px') {{ $t('dialog.user.avatars.total_count', { count: userDialogAvatars.length }) }}
div div
el-radio-group( template(v-if='userDialog.ref.id === API.currentUser.id')
v-if='userDialog.ref.id === API.currentUser.id' span(style='margin-right: 5px') {{ $t('dialog.user.avatars.sort_by') }}
v-model='userDialog.avatarSorting' el-dropdown(
size='mini' @click.native.stop
@change='changeUserDialogAvatarSorting') trigger='click'
el-radio(label='name') {{ $t('dialog.user.avatars.sort_by_name') }} size='small'
el-radio(label='update') {{ $t('dialog.user.avatars.sort_by_update') }} style='margin-right: 5px'
el-divider(direction='vertical') :disabled='userDialog.isWorldsLoading')
el-radio-group( el-button(size='mini')
v-if='userDialog.ref.id === API.currentUser.id' span {{ $t(`dialog.user.avatars.sort_by_${userDialog.avatarSorting}`) }} #[i.el-icon-arrow-down.el-icon--right]
v-model='userDialog.avatarReleaseStatus' el-dropdown-menu(#default='dropdown')
size='mini') el-dropdown-item(
el-radio(label='all') {{ $t('dialog.user.avatars.all') }} v-text='$t("dialog.user.avatars.sort_by_name")'
el-radio(label='public') {{ $t('dialog.user.avatars.public') }} @click.native='changeUserDialogAvatarSorting("name")')
el-radio(label='private') {{ $t('dialog.user.avatars.private') }} el-dropdown-item(
.x-friend-list(style='margin-top: 10px; min-height: 60px') 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( .x-friend-item.x-friend-item-border(
v-for='avatar in userDialogAvatars' v-for='avatar in userDialogAvatars'
:key='avatar.id' :key='avatar.id'
@@ -1009,7 +1039,7 @@ mixin userDialog
icon='el-icon-download' icon='el-icon-download'
circle circle
style='margin-left: 5px') 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') template(#default='scope')
span span
span(v-text='scope.data.key' style='font-weight: bold; margin-right: 5px') span(v-text='scope.data.key' style='font-weight: bold; margin-right: 5px')
+34 -13
View File
@@ -220,7 +220,12 @@ mixin worldDialog
location-world( location-world(
:locationobject='room.$location' :locationobject='room.$location'
:currentuserid='API.currentUser.id' :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( el-tooltip(
placement='top' placement='top'
:content='$t("dialog.world.instances.self_invite_tooltip")' :content='$t("dialog.world.instances.self_invite_tooltip")'
@@ -239,6 +244,18 @@ mixin worldDialog
icon='el-icon-refresh' icon='el-icon-refresh'
style='margin-left: 5px' style='margin-left: 5px'
circle) 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') last-join(:location='room.$location.tag' :currentlocation='lastLocation.location')
instance-info( instance-info(
:location='room.tag' :location='room.tag'
@@ -273,7 +290,7 @@ mixin worldDialog
timer(:epoch='user.$travelingToTime') timer(:epoch='user.$travelingToTime')
span.extra(v-else) span.extra(v-else)
timer(:epoch='user.$location_at') 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-list(style='max-height: none')
.x-friend-item(style='width: 100%; cursor: default') .x-friend-item(style='width: 100%; cursor: default')
.detail .detail
@@ -387,16 +404,20 @@ mixin worldDialog
:content='$t("dialog.world.info.accuracy_notice")') :content='$t("dialog.world.info.accuracy_notice")')
i.el-icon-warning i.el-icon-warning
span.extra {{ worldDialog.lastVisit | formatDate('long') }} span.extra {{ worldDialog.lastVisit | formatDate('long') }}
.x-friend-item(@click='showPreviousInstancesWorldDialog(worldDialog.ref)') el-tooltip(
.detail :disabled='hideTooltips'
span.name {{ $t('dialog.world.info.visit_count') }} placement='top'
el-tooltip( :content='$t("dialog.user.info.open_previouse_instance")')
v-if='!hideTooltips' .x-friend-item(@click='showPreviousInstancesWorldDialog(worldDialog.ref)')
placement='top' .detail
style='margin-left: 5px' span.name {{ $t('dialog.world.info.visit_count') }}
:content='$t("dialog.world.info.accuracy_notice")') el-tooltip(
i.el-icon-warning v-if='!hideTooltips'
span.extra(v-text='worldDialog.visitCount') 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') .x-friend-item(style='cursor: default')
.detail .detail
span.name {{ $t('dialog.world.info.time_spent') }} span.name {{ $t('dialog.world.info.time_spent') }}
@@ -408,7 +429,7 @@ mixin worldDialog
i.el-icon-warning i.el-icon-warning
span.extra(v-if='worldDialog.timeSpent === 0') - span.extra(v-if='worldDialog.timeSpent === 0') -
span.extra(v-else) {{ timeToText(worldDialog.timeSpent) }} 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( el-button(
type='default' type='default'
@click='refreshWorldDialogTreeData()' @click='refreshWorldDialogTreeData()'
+2 -1
View File
@@ -1,6 +1,7 @@
mixin friendsListSidebar mixin friendsListSidebar
#aside.x-aside-container( #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') div(style='display: flex; align-items: baseline')
el-select( el-select(
v-model='quickSearch' v-model='quickSearch'
+1 -1
View File
@@ -1,5 +1,5 @@
mixin friendsListTab 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') .options-container(style='margin-top: 0')
span.header {{ $t('view.friend_list.header') }} span.header {{ $t('view.friend_list.header') }}
div(style='float: right; font-size: 13px') div(style='float: right; font-size: 13px')
+5 -2
View File
@@ -103,10 +103,13 @@ mixin gameLogTab
icon='el-icon-delete' icon='el-icon-delete'
size='mini' size='mini'
@click='deleteGameLogEntryPrompt(scope.row)') @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( el-button(
v-if='scope.row.type === "Location"' v-if='scope.row.type === "Location"'
type='text' type='text'
icon='el-icon-tickets' icon='el-icon-s-data'
size='mini' size='mini'
@click='showPreviousInstanceInfoDialog(scope.row.location)') @click='showPreviousInstanceInfoDialog(scope.row.location)')
+2 -1
View File
@@ -84,7 +84,8 @@ mixin playerListTab
div(style='margin-top: 5px') div(style='margin-top: 5px')
location-world( location-world(
:locationobject='currentInstanceLocation' :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') span(v-if='lastLocation.playerList.size > 0' style='margin-left: 5px')
| {{ lastLocation.playerList.size }} | {{ lastLocation.playerList.size }}
| #[template(v-if='lastLocation.friendList.size > 0') ({{ lastLocation.friendList.size }})] | #[template(v-if='lastLocation.friendList.size > 0') ({{ lastLocation.friendList.size }})]
+6 -6
View File
@@ -1,5 +1,5 @@
mixin settingsTab 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') .options-container(style='margin-top: 0; padding: 5px')
span.header {{ $t('view.settings.header') }} span.header {{ $t('view.settings.header') }}
el-tabs(type='card' style='height: calc(100% - 51px)') 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') }} el-button(@click='ossDialog = true' size='small') {{ $t('view.settings.general.legal_notice.open_source_software_notice') }}
//- Appearance Tab //- Appearance Tab
el-tab-pane(:label='$t("view.settings.category.appearance")') el-tab-pane(lazy :label='$t("view.settings.category.appearance")')
//- Appearance | Appearance //- Appearance | Appearance
.options-container(style='margin-top: 0') .options-container(style='margin-top: 0')
span.header {{ $t('view.settings.appearance.appearance.header') }} span.header {{ $t('view.settings.appearance.appearance.header') }}
@@ -515,7 +515,7 @@ mixin settingsTab
span.color-picker.x-tag-troll(slot='trigger') Nuisance span.color-picker.x-tag-troll(slot='trigger') Nuisance
//- Notifications Tab //- Notifications Tab
el-tab-pane(:label='$t("view.settings.category.notifications")') el-tab-pane(lazy :label='$t("view.settings.category.notifications")')
//- Notifications | Notifications //- Notifications | Notifications
.options-container(style='margin-top: 0') .options-container(style='margin-top: 0')
span.header {{ $t('view.settings.notifications.notifications.header') }} 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') }} style='margin-left: 10px') {{ $t('view.settings.notifications.notifications.text_to_speech.play') }}
//- Wrist Overlay Tab //- 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 //- Wrist Overlay | SteamVR Wrist Overlay
.options-container(style='margin-top: 0') .options-container(style='margin-top: 0')
span.header {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.header') }} span.header {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.header') }}
@@ -735,7 +735,7 @@ mixin settingsTab
:disabled='!openVR || !overlayWrist') :disabled='!openVR || !overlayWrist')
//- Discord Presence Tab //- 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') .options-container(style='margin-top: 0')
span.header {{ $t('view.settings.discord_presence.discord_presence.header') }} span.header {{ $t('view.settings.discord_presence.discord_presence.header') }}
.options-container-item .options-container-item
@@ -767,7 +767,7 @@ mixin settingsTab
:disabled='!discordActive') :disabled='!discordActive')
//- "Advanced" Tab //- "Advanced" Tab
el-tab-pane(:label='$t("view.settings.category.advanced")') el-tab-pane(lazy :label='$t("view.settings.category.advanced")')
//- Advanced | Advanced //- Advanced | Advanced
.options-container(style='margin-top: 0') .options-container(style='margin-top: 0')
span.header {{ $t('view.settings.advanced.advanced.header') }} span.header {{ $t('view.settings.advanced.advanced.header') }}
+158
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>
+3 -11
View File
@@ -48,15 +48,7 @@ module.exports = {
}, },
{ {
test: /\.pug$/, test: /\.pug$/,
oneOf: [ use: [{ loader: 'raw-loader' }, { loader: 'pug-plain-loader' }]
{
resourceQuery: /^\?vue/,
use: 'pug-plain-loader'
},
{
use: ['raw-loader', 'pug-plain-loader']
}
]
}, },
{ {
test: /\.s?css$/, test: /\.s?css$/,
@@ -72,9 +64,9 @@ module.exports = {
] ]
}, },
resolve: { resolve: {
extensions: ['.css', '.js', '.scss'], extensions: ['.js', '.css', '.scss'],
alias: { alias: {
vue: 'vue/dist/vue.common.js' vue: 'vue/dist/vue.esm.js'
} }
}, },
performance: { performance: {