LiveAtlas/src/App.vue

247 lines
7.3 KiB
Vue
Raw Normal View History

2020-12-16 16:54:41 +00:00
<!--
2021-07-25 14:12:40 +00:00
- Copyright 2021 James Lyne
2020-12-16 16:54:41 +00:00
-
2021-07-25 14:12:40 +00:00
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
2020-12-16 16:54:41 +00:00
-
2021-07-25 14:12:40 +00:00
- http://www.apache.org/licenses/LICENSE-2.0
2020-12-16 16:54:41 +00:00
-
2021-07-25 14:12:40 +00:00
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
2020-12-16 16:54:41 +00:00
-->
2020-11-20 18:43:30 +00:00
<template>
2020-12-01 23:20:38 +00:00
<Map></Map>
2021-01-06 16:02:36 +00:00
<ChatBox v-if="chatBoxEnabled" v-show="chatBoxEnabled && chatVisible"></ChatBox>
<LoginModal v-if="loginEnabled" v-show="loginModalVisible" :required="loginRequired"></LoginModal>
<Sidebar></Sidebar>
2021-05-26 23:01:09 +00:00
<notifications position="bottom center" :speed="250" :max="3" :ignoreDuplicates="true" classes="notification" />
2020-11-20 18:43:30 +00:00
</template>
2020-11-20 21:47:56 +00:00
<script lang="ts">
2020-12-31 13:05:54 +00:00
import {computed, defineComponent, onBeforeUnmount, onMounted, onUnmounted, ref, watch} from 'vue';
2020-12-01 23:20:38 +00:00
import Map from './components/Map.vue';
2020-11-23 12:13:28 +00:00
import Sidebar from './components/Sidebar.vue';
2021-01-06 16:02:36 +00:00
import ChatBox from './components/ChatBox.vue';
2021-05-15 19:25:03 +00:00
import {useStore} from "@/store";
2020-11-23 16:16:26 +00:00
import {ActionTypes} from "@/store/action-types";
2021-05-27 00:41:58 +00:00
import {parseUrl} from '@/util';
import {hideSplash, showSplash, showSplashError} from '@/util/splash';
import {MutationTypes} from "@/store/mutation-types";
import {LiveAtlasServerDefinition, LiveAtlasUIElement} from "@/index";
2021-08-30 21:27:41 +00:00
import LoginModal from "@/components/login/LoginModal.vue";
import {notify} from "@kyvg/vue3-notification";
2020-11-23 12:13:28 +00:00
export default defineComponent({
name: 'App',
2020-11-23 12:13:28 +00:00
components: {
2020-12-01 23:20:38 +00:00
Map,
2020-11-23 12:13:28 +00:00
Sidebar,
2021-08-30 21:27:41 +00:00
ChatBox,
LoginModal
2020-11-23 12:13:28 +00:00
},
setup() {
let loadingTimeout = 0;
const store = useStore(),
2021-08-12 13:27:39 +00:00
title = computed(() => store.getters.pageTitle),
currentUrl = computed(() => store.getters.url),
2021-05-17 02:39:25 +00:00
currentServer = computed(() => store.state.currentServer),
2021-05-17 23:19:51 +00:00
configurationHash = computed(() => store.state.configurationHash),
2021-01-06 16:02:36 +00:00
chatBoxEnabled = computed(() => store.state.components.chatBox),
2020-12-31 13:05:54 +00:00
chatVisible = computed(() => store.state.ui.visibleElements.has('chat')),
loginEnabled = computed(() => store.state.components.login), //Whether logging in is enabled for the current server
loggedIn = computed(() => store.state.loggedIn), //Whether the user is currently logged in
loginRequired = ref(false), //Whether logging is required to view the current server
//Hide the login modal if we are logged out on a login-required server, but the server list is open
//Allows switching servers without the modal overlapping
loginModalVisible = computed(() => store.state.ui.visibleModal === 'login'
&& (!loginRequired.value || !store.state.ui.visibleElements.has('maps'))),
loading = ref(false),
loadingAttempts = ref(0),
loadConfiguration = async () => {
try {
clearTimeout(loadingTimeout);
showSplash(!loadingAttempts.value);
loading.value = true;
await store.dispatch(ActionTypes.STOP_UPDATES, undefined);
store.commit(MutationTypes.RESET, undefined);
await store.dispatch(ActionTypes.LOAD_CONFIGURATION, undefined);
await store.dispatch(ActionTypes.START_UPDATES, undefined);
loginRequired.value = false;
2021-05-26 23:01:09 +00:00
requestAnimationFrame(() => {
2021-05-26 23:50:34 +00:00
hideSplash();
2021-05-26 23:01:09 +00:00
const map = document.getElementById('#app');
if(map) {
(map as HTMLElement).focus();
}
});
} catch(e: any) {
//Request was aborted, probably because another server was selected before the request finished. Don't retry
if(e instanceof DOMException && e.name === 'AbortError') {
return;
}
//Logging in is required, show login modal
2021-08-30 21:27:41 +00:00
if(e.message === 'login-required') {
loginRequired.value = true;
2021-08-30 21:27:41 +00:00
return;
}
//Any other errors
2021-05-20 14:30:55 +00:00
const error = `Failed to load server configuration for '${store.state.currentServer!.id}'`;
console.error(`${error}:`, e);
showSplashError(`${error}\n${e}`, false, ++loadingAttempts.value);
clearTimeout(loadingTimeout);
loadingTimeout = setTimeout(() => loadConfiguration(), 1000);
} finally {
loading.value = false;
}
},
2021-01-26 20:37:29 +00:00
handleUrl = () => {
const parsedUrl = parseUrl();
if(parsedUrl) {
2020-12-21 18:46:01 +00:00
//Remove legacy url if one was parsed
if(parsedUrl.legacy) {
const url = new URL(window.location.href);
2021-09-07 22:08:44 +00:00
url.searchParams.delete('worldname'); //Dynmap
url.searchParams.delete('world'); //Pl3xmap
2020-12-21 18:46:01 +00:00
url.searchParams.delete('mapname');
url.searchParams.delete('x');
url.searchParams.delete('y');
url.searchParams.delete('z');
url.searchParams.delete('zoom');
history.replaceState({}, '', url.toString());
}
store.commit(MutationTypes.SET_PARSED_URL, parsedUrl);
}
2020-12-31 13:05:54 +00:00
},
onResize = () => {
store.commit(MutationTypes.SET_SMALL_SCREEN, window.innerWidth < 480 || window.innerHeight < 500);
},
onKeydown = (e: KeyboardEvent) => {
if(!e.ctrlKey || !e.shiftKey) {
return;
}
let element: LiveAtlasUIElement;
//Disable shortcuts if modal is open - except login required to allow server list toggling
if(store.state.ui.visibleModal && !loginRequired.value) {
return;
}
switch(e.key) {
case 'M':
element = 'maps';
break;
case 'C':
element = 'chat';
break;
case 'P':
element = 'players';
break;
case 'L':
element = 'layers';
break;
default:
return;
}
e.preventDefault();
store.commit(MutationTypes.TOGGLE_UI_ELEMENT_VISIBILITY, element);
},
onUrlChange = () => {
const parsedUrl = parseUrl();
if(parsedUrl) {
store.commit(MutationTypes.SET_PARSED_URL, parsedUrl);
}
};
2020-11-23 12:13:28 +00:00
watch(title, (title) => document.title = title);
watch(currentUrl, (url) => window.history.replaceState({}, '', url));
2021-05-20 14:30:55 +00:00
watch(currentServer, (newServer?: LiveAtlasServerDefinition) => {
if(!newServer) {
return;
}
loadingAttempts.value = 0;
window.history.replaceState({}, '', newServer.id);
2021-05-17 02:39:25 +00:00
loadConfiguration();
}, {deep: true});
watch(configurationHash, async (newHash, oldHash) => {
2021-05-17 23:19:51 +00:00
if(newHash && oldHash) {
await loadConfiguration();
2021-05-17 23:19:51 +00:00
}
});
2021-08-30 21:27:41 +00:00
watch(loggedIn, async () => {
if(!loading.value) {
console.log('Login state changed. Reloading configuration');
await loadConfiguration();
}
});
watch(loginRequired, (newValue) => {
if(newValue) {
store.commit(MutationTypes.SET_UI_ELEMENT_VISIBILITY, {
element: 'maps',
state: false,
});
store.commit(MutationTypes.SHOW_UI_MODAL, 'login');
notify('Login required');
showSplashError('Login required', true, 1);
}
2021-08-30 21:27:41 +00:00
})
2020-11-23 12:13:28 +00:00
onMounted(() => loadConfiguration());
onBeforeUnmount(() => {
store.dispatch(ActionTypes.STOP_UPDATES, undefined);
clearTimeout(loadingTimeout);
});
2021-01-26 20:37:29 +00:00
handleUrl();
2020-12-31 13:05:54 +00:00
onResize();
onMounted(() => {
window.addEventListener('resize', onResize);
window.addEventListener('keydown', onKeydown);
window.addEventListener('hashchange', onUrlChange);
});
onUnmounted(() => {
window.addEventListener('resize', onResize);
window.addEventListener('keydown', onKeydown);
window.addEventListener('hashchange', onUrlChange);
});
2020-12-17 14:50:12 +00:00
return {
2021-01-06 16:02:36 +00:00
chatBoxEnabled,
2020-12-31 13:05:54 +00:00
chatVisible,
2021-08-30 21:27:41 +00:00
loginEnabled,
loginRequired,
loginModalVisible
2020-12-17 14:50:12 +00:00
}
},
2020-11-23 12:13:28 +00:00
});
2020-11-20 18:43:30 +00:00
</script>