mirror of https://github.com/Lissy93/dashy.git
🔀 Merge pull request #238 from Lissy93/FEATURE/improved-loading
[FEATURE] Improved Loading
This commit is contained in:
commit
e0d93659d7
|
@ -1,5 +1,10 @@
|
|||
# Changelog
|
||||
|
||||
## ⚡️ 1.8.3 - Improved UX for Initial Load [PR #238](https://github.com/Lissy93/dashy/pull/238)
|
||||
- Removes the old splash screen
|
||||
- Adds placeholder in the HTML index, which will usually be visible on initial load
|
||||
- Show progress bar on route switcher
|
||||
|
||||
## ✨ 1.8.2 - Serverless Functions for Netlify Instances [PR #235](https://github.com/Lissy93/dashy/pull/235)
|
||||
- Previously when Dashy was deployed as a static site to Netlify, it was not possible to use several features, which required server-side code
|
||||
- This PR adds serverless cloud functions to provide most of this functionality
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "Dashy",
|
||||
"version": "1.8.2",
|
||||
"version": "1.8.3",
|
||||
"license": "MIT",
|
||||
"main": "server",
|
||||
"scripts": {
|
||||
|
|
|
@ -1,27 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Do not modify this file directly -->
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<!-- Encoding and Viewport -->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<!-- Favicon + App Icon -->
|
||||
<link rel="icon" type="image/png" sizes="64x64" href="<%= BASE_URL %>/web-icons/favicon-64x64.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="web-icons/favicon-32x32.png">
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/png" href="<%= BASE_URL %>favicon.ico" />
|
||||
<!-- Default Page Title -->
|
||||
<title>Dashy</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- built files will be auto injected -->
|
||||
<div id="app">
|
||||
<!-- Loading screen, will be replaced when app loaded -->
|
||||
<div class="loading-placeholder" id="loader"><h1>Dashy</h1><p>Loading...</p></div>
|
||||
</div>
|
||||
<!-- Devices without JS enabled -->
|
||||
<noscript>
|
||||
<strong>Sorry, JavaScript is required to run this app 😥</strong>
|
||||
<strong>Sorry, JavaScript needs to be enabled to run Dashy 😥</strong>
|
||||
</noscript>
|
||||
|
||||
<!-- built files will be auto injected -->
|
||||
<div id="app"></div>
|
||||
<!-- Styles for loading screen -->
|
||||
<style type="text/css">
|
||||
body { margin: 0; }
|
||||
#app .loading-placeholder {
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: progress;
|
||||
background: #121212;
|
||||
}
|
||||
#app .loading-placeholder h1 {
|
||||
font-size: 20vh;
|
||||
font-family: Tahoma, monospace;
|
||||
cursor: progress;
|
||||
color: #0c0c0c;
|
||||
text-shadow: 0px 4px 4px #090909, 0 0 0 #000, 0px 2px 2px #000000;
|
||||
}
|
||||
#app .loading-placeholder p {
|
||||
font-size: 2rem;
|
||||
font-family: monospace;
|
||||
cursor: progress;
|
||||
color: #0c0c0c;
|
||||
text-shadow: 0 1px 1px #090909, 0 0 0 #000, 0 1px 1px #000000;
|
||||
}
|
||||
::selection { background-color: #db78fc; color: #121212; }
|
||||
</style>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -53,8 +53,7 @@ export default {
|
|||
},
|
||||
/* Determine if splash screen should be shown */
|
||||
shouldShowSplash() {
|
||||
return (this.visibleComponents || defaultVisibleComponents).splashScreen
|
||||
|| !localStorage[localStorageKeys.HIDE_WELCOME_BANNER];
|
||||
return (this.visibleComponents || defaultVisibleComponents).splashScreen;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
@ -107,6 +106,10 @@ export default {
|
|||
this.$i18n.locale = language;
|
||||
document.getElementsByTagName('html')[0].setAttribute('lang', language);
|
||||
},
|
||||
hideLoader() {
|
||||
const loader = document.getElementById('loader');
|
||||
if (loader) loader.style.display = 'none';
|
||||
},
|
||||
},
|
||||
/* When component mounted, hide splash and initiate the injection of custom styles */
|
||||
mounted() {
|
||||
|
@ -115,6 +118,7 @@ export default {
|
|||
if (this.appConfig.customCss) {
|
||||
const cleanedCss = this.appConfig.customCss.replace(/<\/?[^>]+(>|$)/g, '');
|
||||
this.injectCustomStyles(cleanedCss);
|
||||
this.hideLoader();
|
||||
}
|
||||
welcomeMsg();
|
||||
},
|
||||
|
|
|
@ -66,7 +66,7 @@ import IconBackup from '@/assets/interface-icons/config-backup.svg';
|
|||
import IconRestore from '@/assets/interface-icons/config-restore.svg';
|
||||
import { backup, update, restore } from '@/utils/CloudBackup';
|
||||
import { localStorageKeys } from '@/utils/defaults';
|
||||
import ErrorHandler, { InfoHandler } from '@/utils/ErrorHandler';
|
||||
import { InfoHandler, WarningInfoHandler } from '@/utils/ErrorHandler';
|
||||
|
||||
export default {
|
||||
name: 'CloudBackupRestore',
|
||||
|
@ -161,7 +161,7 @@ export default {
|
|||
this.backupPassword = '';
|
||||
},
|
||||
showErrorMsg(errorMsg) {
|
||||
ErrorHandler(errorMsg);
|
||||
WarningInfoHandler(errorMsg, 'Cloud Backup');
|
||||
this.$toasted.show(errorMsg, { className: 'toast-error' });
|
||||
},
|
||||
showSuccessMsg(msg) {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
// Import Vue.js and vue router
|
||||
import Vue from 'vue';
|
||||
import Router from 'vue-router';
|
||||
import ProgressBar from 'rsup-progress';
|
||||
|
||||
// Import views
|
||||
import Home from '@/views/Home.vue';
|
||||
|
@ -21,6 +22,7 @@ import { config } from '@/utils/ConfigHelpers';
|
|||
import { metaTagData, startingView, routePaths } from '@/utils/defaults';
|
||||
|
||||
Vue.use(Router);
|
||||
const progress = new ProgressBar({ color: 'var(--progress-bar)' });
|
||||
|
||||
/* Returns true if user is already authenticated, or if auth is not enabled */
|
||||
const isAuthenticated = () => {
|
||||
|
@ -119,12 +121,14 @@ const router = new Router({
|
|||
* If not logged in, prevent all access and redirect them to login page
|
||||
* */
|
||||
router.beforeEach((to, from, next) => {
|
||||
progress.start();
|
||||
if (to.name !== 'login' && !isAuthenticated()) next({ name: 'login' });
|
||||
else next();
|
||||
});
|
||||
|
||||
/* If title is missing, then apply default page title */
|
||||
router.afterEach((to) => {
|
||||
progress.end();
|
||||
Vue.nextTick(() => {
|
||||
document.title = to.meta.title || 'Dashy';
|
||||
});
|
||||
|
|
|
@ -28,7 +28,7 @@ export const statusMsg = (title, msg) => {
|
|||
/* Prints status message, with a stack trace */
|
||||
export const statusErrorMsg = (title, msg, errorLog) => {
|
||||
console.log(
|
||||
`%c${title || ''}\n%c${msg} \n%c${errorLog}`,
|
||||
`%c${title || ''}\n%c${msg} \n%c${errorLog || ''}`,
|
||||
'font-weight: bold; color: #0dd8d8; text-decoration: underline;',
|
||||
'color: #ff025a',
|
||||
'color: #ff025a80;',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as Sentry from '@sentry/vue';
|
||||
import { warningMsg, statusMsg } from '@/utils/CoolConsole';
|
||||
import { warningMsg, statusMsg, statusErrorMsg } from '@/utils/CoolConsole';
|
||||
import { sessionStorageKeys } from '@/utils/defaults';
|
||||
|
||||
/* Makes the current time, like hh:mm:ss */
|
||||
|
@ -33,4 +33,9 @@ export const InfoHandler = (msg, title) => {
|
|||
statusMsg(title || 'Info', msg);
|
||||
};
|
||||
|
||||
/* Outputs warnings caused by the user, such as missing field */
|
||||
export const WarningInfoHandler = (msg, title, log) => {
|
||||
statusErrorMsg(title || 'Warning', msg, log);
|
||||
};
|
||||
|
||||
export default ErrorHandler;
|
||||
|
|
|
@ -71,8 +71,9 @@ module.exports = {
|
|||
],
|
||||
/* Which structural components should be visible by default */
|
||||
visibleComponents: {
|
||||
pageTitle: true,
|
||||
splashScreen: false,
|
||||
navigation: true,
|
||||
pageTitle: true,
|
||||
searchBar: true,
|
||||
settings: true,
|
||||
footer: true,
|
||||
|
|
|
@ -76,7 +76,7 @@ import router from '@/router';
|
|||
import Button from '@/components/FormElements/Button';
|
||||
import Input from '@/components/FormElements/Input';
|
||||
import Defaults, { localStorageKeys } from '@/utils/defaults';
|
||||
import { InfoHandler } from '@/utils/ErrorHandler';
|
||||
import { InfoHandler, WarningInfoHandler } from '@/utils/ErrorHandler';
|
||||
import {
|
||||
checkCredentials,
|
||||
login,
|
||||
|
@ -160,7 +160,7 @@ export default {
|
|||
this.goHome();
|
||||
InfoHandler(`Succesfully signed in as ${this.username}`, 'Authentication');
|
||||
} else {
|
||||
InfoHandler(`Unable to Sign In - ${this.message}`, 'Authentication');
|
||||
WarningInfoHandler('Unable to Sign In', 'Authentication', this.message);
|
||||
}
|
||||
},
|
||||
/* Calls function to double-check guest access enabled, then log in as guest */
|
||||
|
@ -168,9 +168,11 @@ export default {
|
|||
const isAllowed = this.isGuestAccessEnabled;
|
||||
if (isAllowed) {
|
||||
this.$toasted.show('Logged in as Guest, Redirecting...', { className: 'toast-success' });
|
||||
InfoHandler('Logged in as Guest', 'Authentication');
|
||||
this.goHome();
|
||||
} else {
|
||||
this.$toasted.show('Guest access not allowed', { className: 'toast-error' });
|
||||
this.$toasted.show('Guest Access Not Allowed', { className: 'toast-error' });
|
||||
WarningInfoHandler('Guest Access Not Allowed', 'Authentication');
|
||||
}
|
||||
},
|
||||
/* Calls logout, shows status message, and refreshed page */
|
||||
|
|
Loading…
Reference in New Issue