-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathApp.vue
More file actions
193 lines (185 loc) · 6.74 KB
/
App.vue
File metadata and controls
193 lines (185 loc) · 6.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
<template>
<div id="dashy" :style="topLevelStyleModifications" :class="subPageClassName">
<EditModeTopBanner v-if="isEditMode" />
<LoadingScreen :isLoading="isLoading" v-if="shouldShowSplash" />
<Header :pageInfo="pageInfo" />
<router-view v-if="!isFetching" />
<CriticalError v-if="hasCriticalError" />
<Footer :text="footerText" v-if="visibleComponents.footer && !isFetching" />
</div>
</template>
<script>
import Header from '@/components/PageStrcture/Header.vue';
import Footer from '@/components/PageStrcture/Footer.vue';
import EditModeTopBanner from '@/components/InteractiveEditor/EditModeTopBanner.vue';
import CriticalError from '@/components/PageStrcture/CriticalError.vue';
import LoadingScreen from '@/components/PageStrcture/LoadingScreen.vue';
import { welcomeMsg } from '@/utils/CoolConsole';
import ErrorHandler from '@/utils/ErrorHandler';
import Keys from '@/utils/StoreMutations';
import {
localStorageKeys,
splashScreenTime,
language as defaultLanguage,
} from '@/utils/defaults';
export default {
name: 'app',
components: {
Header,
Footer,
LoadingScreen,
EditModeTopBanner,
CriticalError,
},
data() {
return {
isLoading: true, // Set to false after mount complete
isFetching: true, // Set to false after the conf has been fetched
};
},
watch: {
isEditMode(isEditMode) {
// When in edit mode, show confirmation dialog on page exit
window.onbeforeunload = isEditMode ? this.confirmExit : null;
},
config() {
this.isFetching = false;
},
},
computed: {
/* If the user has specified custom text for footer - get it */
footerText() {
return this.pageInfo && this.pageInfo.footerText ? this.pageInfo.footerText : '';
},
/* Determine if splash screen should be shown */
shouldShowSplash() {
return (this.appConfig.showSplashScreen);
},
config() {
return this.$store.state.config;
},
appConfig() {
return this.$store.getters.appConfig;
},
pageInfo() {
return this.$store.getters.pageInfo;
},
sections() {
return this.$store.getters.sections;
},
visibleComponents() {
return this.$store.getters.visibleComponents;
},
isEditMode() {
return this.$store.state.editMode;
},
hasCriticalError() {
return this.$store.state.criticalError;
},
subPageClassName() {
const currentSubPage = this.$store.state.currentConfigInfo;
return (currentSubPage && currentSubPage.pageId) ? currentSubPage.pageId : '';
},
topLevelStyleModifications() {
const vc = this.visibleComponents;
if (!vc.footer && !vc.pageTitle) {
return '--footer-height: 1rem;';
} else if (!vc.footer) {
return '--footer-height: 5rem;';
} else if (!vc.pageTitle) {
return '--footer-height: 4rem;';
}
return '';
},
},
methods: {
/* Injects the users custom CSS as a style tag */
injectCustomStyles(usersCss) {
const style = document.createElement('style');
style.textContent = usersCss;
document.head.append(style);
},
/* Hide splash screen, either after 2 seconds, or immediately based on user preference */
hideSplash() {
if (this.shouldShowSplash) {
setTimeout(() => { this.isLoading = false; }, splashScreenTime || 1000);
} else {
this.isLoading = false;
}
},
/* Auto-detects users language from browser/ os, when not specified */
autoDetectLanguage(availibleLocales) {
const isLangSupported = (languageList, userLang) => languageList
.map(lang => lang.toLowerCase()).find((lang) => lang === userLang.toLowerCase());
const usersBorwserLang1 = window.navigator.language || ''; // e.g. en-GB or or ''
const usersBorwserLang2 = usersBorwserLang1.split('-')[0]; // e.g. en or undefined
const usersSpairLangs = window.navigator.languages; // e.g [en, en-GB, en-US]
return isLangSupported(availibleLocales, usersBorwserLang1)
|| isLangSupported(availibleLocales, usersBorwserLang2)
|| usersSpairLangs.find((spair) => isLangSupported(availibleLocales, spair))
|| defaultLanguage;
},
/* Get users language, if not available then call auto-detect */
getLanguage() {
const availibleLocales = this.$i18n.availableLocales; // All available locales
const usersLang = localStorage[localStorageKeys.LANGUAGE] || this.appConfig.language;
if (usersLang) {
if (availibleLocales.includes(usersLang)) {
return usersLang;
} else {
ErrorHandler(`Unsupported Language: '${usersLang}'`);
}
}
return this.autoDetectLanguage(availibleLocales);
},
/* Fetch or detect users language, then apply it */
applyLanguage() {
const language = this.getLanguage();
this.$store.commit(Keys.SET_LANGUAGE, language);
this.$i18n.locale = language;
document.getElementsByTagName('html')[0].setAttribute('lang', language);
},
/* If placeholder element still visible, hide it */
hideLoader() {
const loader = document.getElementById('loader');
if (loader) loader.style.display = 'none';
},
/* Called when in edit mode and navigating away from page */
confirmExit(e) {
e.preventDefault();
return 'You may have unsaved edits. Are you sure you want to exit the page?';
},
/* Detect and apply theme based on OS preference */
applyThemeBasedOnOSPreference() {
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
const osTheme = prefersDark ? this.appConfig.nightTheme : this.appConfig.dayTheme;
if (osTheme) {
this.$store.commit(Keys.SET_THEME, osTheme);
this.updateTheme(osTheme);
}
},
},
/* Basic initialization tasks on app load */
async mounted() {
await this.$store.dispatch(Keys.INITIALIZE_CONFIG); // Initialize config before moving on
this.applyLanguage(); // Apply users local language
this.applyThemeBasedOnOSPreference(); // Apply theme based on OS preference
this.hideSplash(); // Hide the splash screen, if visible
if (this.appConfig.customCss) { // Inject users custom CSS, if present
const cleanedCss = this.appConfig.customCss.replace(/<\/?[^>]+(>|$)/g, '');
this.injectCustomStyles(cleanedCss);
}
this.hideLoader(); // If initial placeholder still visible, hide it
welcomeMsg(); // Show message in console
},
};
</script>
<style lang="scss">
/* Import styles used globally throughout the app */
@import '@/styles/global-styles.scss';
@import '@/styles/color-palette.scss';
@import '@/styles/dimensions.scss';
@import '@/styles/color-themes.scss';
@import '@/styles/typography.scss';
@import '@/styles/user-defined-themes.scss';
</style>