mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-17 13:53:52 +02:00
improve: UI (#1152)
* improve: UI (#1033) * fix: instance activity chart not displaying properly * fix
This commit is contained in:
204
src/app.js
204
src/app.js
@@ -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] = [];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -108,7 +108,6 @@ export default class extends baseClass {
|
||||
visible: false,
|
||||
loading: false,
|
||||
languageChoice: false,
|
||||
languageValue: '',
|
||||
languages: []
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -815,6 +815,7 @@
|
||||
"avatars": {
|
||||
"header": "アバター",
|
||||
"total_count": "{count} 個のアバター",
|
||||
"sort_by": "並べ替え:",
|
||||
"sort_by_name": "名前順",
|
||||
"sort_by_update": "更新順",
|
||||
"all": "全て",
|
||||
|
||||
@@ -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": "私人"
|
||||
|
||||
@@ -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": "私人"
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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()'
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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()'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)')
|
||||
|
||||
@@ -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 }})]
|
||||
|
||||
@@ -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') }}
|
||||
|
||||
158
src/views/dialogs/PreviousInstanceInfo.vue
Normal file
158
src/views/dialogs/PreviousInstanceInfo.vue
Normal 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>
|
||||
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user