Merge branch 'master' into FEATURE/login-remember-me-always
This commit is contained in:
90
src/views/404.vue
Normal file
90
src/views/404.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<main class="not-found-page">
|
||||
<h1 class="not-found-title">404</h1>
|
||||
<h2 class="not-found-sad-face">:(</h2>
|
||||
<p class="not-found-subtitle">Page Not Found</p>
|
||||
<p class="not-found-message">
|
||||
Facing Issues?
|
||||
<a href="https://git.io/JzpL5">Get Support</a>.
|
||||
</p>
|
||||
<router-link to="/" class="go-home">Back Home</router-link>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'not-found',
|
||||
methods: {
|
||||
setTheme() {
|
||||
document.getElementsByTagName('html')[0].setAttribute('data-theme', 'dashy-docs');
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.setTheme();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '@/styles/media-queries.scss';
|
||||
@import '@/styles/style-helpers.scss';
|
||||
main.not-found-page {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
cursor: default;
|
||||
background: #202020;
|
||||
min-height: calc(99vh - var(--footer-height));
|
||||
background-color: #202020;
|
||||
h1.not-found-title, h2.not-found-sad-face {
|
||||
font-size: 20vh;
|
||||
font-family: Tahoma, monospace;
|
||||
cursor: default;
|
||||
color: #0c0c0c;
|
||||
text-shadow: 0px 4px 4px #090909, 0 0 0 #000, 0px 2px 2px #000000;
|
||||
margin: 1rem 0 0;
|
||||
}
|
||||
h2.not-found-sad-face {
|
||||
font-size: 4rem;
|
||||
margin: 0 0 1.5rem 0;
|
||||
}
|
||||
p {
|
||||
font-family: monospace;
|
||||
cursor: default;
|
||||
color: #0c0c0c;
|
||||
margin: 0.2rem 0;
|
||||
text-shadow: 0 1px 1px #090909, 0 0 0 #000, 0 1px 1px #000000;
|
||||
}
|
||||
p.not-found-subtitle {
|
||||
font-size: 2.8rem;
|
||||
}
|
||||
p.not-found-message {
|
||||
font-size: 1.4rem;
|
||||
font-weight: normal;
|
||||
a {
|
||||
color: #0c0c0c;
|
||||
font-family: monospace;
|
||||
}
|
||||
}
|
||||
a.go-home {
|
||||
padding: 0.3rem 1rem;
|
||||
border-radius: 3px;
|
||||
font-size: 1.7rem;
|
||||
cursor: pointer;
|
||||
font-family: Tahoma, monospace;
|
||||
color: #0c0c0c;
|
||||
margin: 2rem 0 0;
|
||||
text-decoration: none;
|
||||
background: #db78fc;
|
||||
box-shadow: 0 4px #b83ddd;
|
||||
&:hover { box-shadow: 0 2px #b83ddd; }
|
||||
}
|
||||
::selection { background-color: #db78fc; color: #121212; }
|
||||
}
|
||||
</style>
|
||||
@@ -7,18 +7,13 @@ import JsonToYaml from '@/utils/JsonToYaml';
|
||||
|
||||
export default {
|
||||
name: 'DownloadConfig',
|
||||
props: {
|
||||
sections: Array,
|
||||
appConfig: Object,
|
||||
pageInfo: Object,
|
||||
computed: {
|
||||
config() {
|
||||
return this.$store.state.config;
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
config: {
|
||||
appConfig: this.appConfig,
|
||||
pageInfo: this.pageInfo,
|
||||
sections: this.sections,
|
||||
},
|
||||
jsonParser: JsonToYaml,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -4,24 +4,33 @@
|
||||
<!-- Search bar, layout options and settings -->
|
||||
<SettingsContainer ref="filterComp"
|
||||
@user-is-searchin="searching"
|
||||
@change-display-layout="setLayoutOrientation"
|
||||
@change-icon-size="setItemSize"
|
||||
@change-modal-visibility="updateModalVisibility"
|
||||
:displayLayout="layout"
|
||||
:iconSize="itemSizeBound"
|
||||
:externalThemes="getExternalCSSLinks()"
|
||||
:sections="allSections"
|
||||
:appConfig="appConfig"
|
||||
:pageInfo="pageInfo"
|
||||
:modalOpen="modalOpen"
|
||||
class="settings-outer"
|
||||
/>
|
||||
<!-- Show back button, when on single-section view -->
|
||||
<div v-if="singleSectionView">
|
||||
<router-link to="/home" class="back-to-all-link">
|
||||
<BackIcon />
|
||||
<span>Back to All</span>
|
||||
</router-link>
|
||||
</div>
|
||||
<!-- Main content, section for each group of items -->
|
||||
<div v-if="checkTheresData(sections)"
|
||||
:class="`item-group-container orientation-${layout} item-size-${itemSizeBound}`">
|
||||
:class="`item-group-container `
|
||||
+ `orientation-${layout} `
|
||||
+ `item-size-${itemSizeBound} `
|
||||
+ (isEditMode ? 'edit-mode ' : '')
|
||||
+ (singleSectionView ? 'single-section-view ' : '')
|
||||
+ (this.colCount ? `col-count-${this.colCount} ` : '')"
|
||||
>
|
||||
<Section
|
||||
v-for="(section, index) in filteredTiles"
|
||||
:key="index"
|
||||
:index="index"
|
||||
:title="section.name"
|
||||
:icon="section.icon || undefined"
|
||||
:displayData="getDisplayData(section)"
|
||||
@@ -34,11 +43,17 @@
|
||||
:class="
|
||||
(searchValue && filterTiles(section.items, searchValue).length === 0) ? 'no-results' : ''"
|
||||
/>
|
||||
<!-- Show add new section button, in edit mode -->
|
||||
<AddNewSection v-if="isEditMode" />
|
||||
</div>
|
||||
<!-- Show message when there's no data to show -->
|
||||
<div v-if="checkIfResults()" class="no-data">
|
||||
{{searchValue ? $t('home.no-results') : $t('home.no-data')}}
|
||||
</div>
|
||||
<!-- Show banner at bottom of screen, for Saving config changes -->
|
||||
<EditModeSaveMenu v-if="isEditMode" />
|
||||
<!-- Modal for viewing and exporting configuration file -->
|
||||
<ExportConfigMenu />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -46,57 +61,80 @@
|
||||
|
||||
import SettingsContainer from '@/components/Settings/SettingsContainer.vue';
|
||||
import Section from '@/components/LinkItems/Section.vue';
|
||||
import EditModeSaveMenu from '@/components/InteractiveEditor/EditModeSaveMenu.vue';
|
||||
import ExportConfigMenu from '@/components/InteractiveEditor/ExportConfigMenu.vue';
|
||||
import AddNewSection from '@/components/InteractiveEditor/AddNewSectionLauncher.vue';
|
||||
import { searchTiles } from '@/utils/Search';
|
||||
import Defaults, { localStorageKeys, iconCdns } from '@/utils/defaults';
|
||||
import StoreKeys from '@/utils/StoreMutations';
|
||||
import Defaults, { localStorageKeys, iconCdns, modalNames } from '@/utils/defaults';
|
||||
import ErrorHandler from '@/utils/ErrorHandler';
|
||||
import BackIcon from '@/assets/interface-icons/back-arrow.svg';
|
||||
|
||||
export default {
|
||||
name: 'home',
|
||||
props: {
|
||||
sections: Array, // Main site content
|
||||
appConfig: Object, // Main site configuation (optional)
|
||||
pageInfo: Object, // Page metadata (optional)
|
||||
},
|
||||
components: {
|
||||
SettingsContainer,
|
||||
EditModeSaveMenu,
|
||||
ExportConfigMenu,
|
||||
AddNewSection,
|
||||
Section,
|
||||
BackIcon,
|
||||
},
|
||||
data: () => ({
|
||||
searchValue: '',
|
||||
layout: '',
|
||||
itemSizeBound: '',
|
||||
modalOpen: false, // When true, keybindings are disabled
|
||||
addNewSectionOpen: false,
|
||||
}),
|
||||
computed: {
|
||||
/* Combines sections from config file, with those in local storage */
|
||||
allSections() {
|
||||
// If the user has stored sections in local storage, return those
|
||||
const localSections = localStorage[localStorageKeys.CONF_SECTIONS];
|
||||
if (localSections) {
|
||||
const json = JSON.parse(localSections);
|
||||
if (json.length >= 1) return json;
|
||||
}
|
||||
// Otherwise, return the usuall data from conf.yml
|
||||
return this.sections;
|
||||
sections() {
|
||||
return this.$store.getters.sections;
|
||||
},
|
||||
appConfig() {
|
||||
return this.$store.getters.appConfig;
|
||||
},
|
||||
pageInfo() {
|
||||
return this.$store.getters.pageInfo;
|
||||
},
|
||||
modalOpen() {
|
||||
return this.$store.state.modalOpen;
|
||||
},
|
||||
singleSectionView() {
|
||||
return this.findSingleSection(this.$store.getters.sections, this.$route.params.section);
|
||||
},
|
||||
isEditMode() {
|
||||
return this.$store.state.editMode;
|
||||
},
|
||||
/* Get class for num columns, if specified by user */
|
||||
colCount() {
|
||||
let { colCount } = this.appConfig;
|
||||
if (!colCount) return null;
|
||||
if (colCount < 1) colCount = 1;
|
||||
if (colCount > 8) colCount = 8;
|
||||
return colCount;
|
||||
},
|
||||
/* Return all sections, that match users search term */
|
||||
filteredTiles() {
|
||||
const sections = this.allSections;
|
||||
const sections = this.singleSectionView || this.sections;
|
||||
return sections.filter((section) => this.filterTiles(section.items, this.searchValue));
|
||||
},
|
||||
/* Updates layout (when button clicked), and saves in local storage */
|
||||
layoutOrientation: {
|
||||
get() { return this.appConfig.layout || Defaults.layout; },
|
||||
set: function setLayout(layout) {
|
||||
localStorage.setItem(localStorageKeys.LAYOUT_ORIENTATION, layout);
|
||||
this.layout = layout;
|
||||
},
|
||||
layoutOrientation() {
|
||||
return this.$store.getters.layout;
|
||||
},
|
||||
/* Updates icon size (when button clicked), and saves in local storage */
|
||||
iconSize: {
|
||||
get() { return this.appConfig.iconSize || Defaults.iconSize; },
|
||||
set: function setIconSize(iconSize) {
|
||||
localStorage.setItem(localStorageKeys.ICON_SIZE, iconSize);
|
||||
this.itemSizeBound = iconSize;
|
||||
},
|
||||
iconSize() {
|
||||
return this.$store.getters.iconSize;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
layoutOrientation(layout) {
|
||||
localStorage.setItem(localStorageKeys.LAYOUT_ORIENTATION, layout);
|
||||
this.layout = layout;
|
||||
},
|
||||
iconSize(size) {
|
||||
localStorage.setItem(localStorageKeys.ICON_SIZE, size);
|
||||
this.itemSizeBound = size;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -121,17 +159,32 @@ export default {
|
||||
getDisplayData(section) {
|
||||
return !section.displayData ? {} : section.displayData;
|
||||
},
|
||||
/* Sets layout attribute, which is used by Section */
|
||||
setLayoutOrientation(layout) {
|
||||
this.layoutOrientation = layout;
|
||||
},
|
||||
/* Sets item size attribute, which is used by Section */
|
||||
setItemSize(itemSize) {
|
||||
this.iconSize = itemSize;
|
||||
},
|
||||
/* Update data when modal is open (so that key bindings can be disabled) */
|
||||
updateModalVisibility(modalState) {
|
||||
this.modalOpen = modalState;
|
||||
this.$store.commit('SET_MODAL_OPEN', modalState);
|
||||
},
|
||||
openAddNewSectionMenu() {
|
||||
this.addNewSectionOpen = true;
|
||||
this.$modal.show(modalNames.EDIT_SECTION);
|
||||
this.$store.commit(StoreKeys.SET_MODAL_OPEN, true);
|
||||
},
|
||||
closeEditSection() {
|
||||
this.addNewSectionOpen = false;
|
||||
this.$modal.hide(modalNames.EDIT_SECTION);
|
||||
this.$store.commit(StoreKeys.SET_MODAL_OPEN, false);
|
||||
},
|
||||
/* If on sub-route, and section exists, then return only that section */
|
||||
findSingleSection: (allSections, sectionTitle) => {
|
||||
if (!sectionTitle) return undefined;
|
||||
let sectionToReturn;
|
||||
const parse = (section) => section.replaceAll(' ', '-').toLowerCase().trim();
|
||||
allSections.forEach((section) => {
|
||||
if (parse(sectionTitle) === parse(section.name)) {
|
||||
sectionToReturn = [section];
|
||||
}
|
||||
});
|
||||
if (!sectionToReturn) ErrorHandler(`No section named '${sectionTitle}' was found`);
|
||||
return sectionToReturn;
|
||||
},
|
||||
/* Returns an array of links to external CSS from the Config */
|
||||
getExternalCSSLinks() {
|
||||
@@ -154,8 +207,8 @@ export default {
|
||||
/* Checks if any sections or items use icons from a given CDN */
|
||||
checkIfIconLibraryNeeded(prefix) {
|
||||
let isNeeded = false;
|
||||
if (!this.allSections) return false;
|
||||
this.allSections.forEach((section) => {
|
||||
if (!this.sections) return false;
|
||||
this.sections.forEach((section) => {
|
||||
if (section.icon && section.icon.includes(prefix)) isNeeded = true;
|
||||
section.items.forEach((item) => {
|
||||
if (item.icon && item.icon.includes(prefix)) isNeeded = true;
|
||||
@@ -194,10 +247,10 @@ export default {
|
||||
},
|
||||
/* Returns true if there is more than 1 sub-result visible during searching */
|
||||
checkIfResults() {
|
||||
if (!this.allSections) return false;
|
||||
if (!this.sections) return false;
|
||||
else {
|
||||
let itemsFound = true;
|
||||
this.allSections.forEach((section) => {
|
||||
this.sections.forEach((section) => {
|
||||
if (this.filterTiles(section.items, this.searchValue).length > 0) itemsFound = false;
|
||||
});
|
||||
return itemsFound;
|
||||
@@ -227,10 +280,19 @@ export default {
|
||||
.home {
|
||||
padding-bottom: 1px;
|
||||
background: var(--background);
|
||||
// min-height: calc(100vh - 126px);
|
||||
min-height: calc(99.9vh - var(--footer-height));
|
||||
}
|
||||
|
||||
.back-to-all-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.25rem;
|
||||
margin: 0.25rem;
|
||||
@extend .svg-button;
|
||||
svg { margin-right: 0.5rem; }
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Outside container wrapping the item groups*/
|
||||
.item-group-container {
|
||||
display: grid;
|
||||
@@ -255,29 +317,61 @@ export default {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
&.orientation-horizontal, &.orientation-vertical, &.single-section-view {
|
||||
@include phone { --content-max-width: 100%; }
|
||||
@include tablet { --content-max-width: 98%; }
|
||||
@include laptop { --content-max-width: 90%; }
|
||||
@include monitor { --content-max-width: 85%; }
|
||||
@include big-screen { --content-max-width: 80%; }
|
||||
@include big-screen-up { --content-max-width: 60%; }
|
||||
max-width: var(--content-max-width, 90%);
|
||||
}
|
||||
|
||||
/* Specify number of columns, based on screen size */
|
||||
@include phone {
|
||||
grid-template-columns: repeat(1, 1fr);
|
||||
}
|
||||
@include tablet {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
@include laptop {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
@include monitor {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
@include big-screen {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
@include big-screen-up {
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
/* Specify number of columns, based on screen size or user preference */
|
||||
@include phone { --col-count: 1; }
|
||||
@include tablet { --col-count: 2; }
|
||||
@include laptop { --col-count: 2; }
|
||||
@include monitor { --col-count: 3; }
|
||||
@include big-screen { --col-count: 4; }
|
||||
@include big-screen-up { --col-count: 5; }
|
||||
|
||||
@include tablet-up {
|
||||
&.col-count-1 { --col-count: 1; }
|
||||
&.col-count-2 { --col-count: 2; }
|
||||
&.col-count-3 { --col-count: 3; }
|
||||
&.col-count-4 { --col-count: 4; }
|
||||
&.col-count-5 { --col-count: 5; }
|
||||
&.col-count-6 { --col-count: 6; }
|
||||
&.col-count-7 { --col-count: 7; }
|
||||
&.col-count-8 { --col-count: 8; }
|
||||
}
|
||||
|
||||
grid-template-columns: repeat(var(--col-count, 2), minmax(0, 1fr));
|
||||
|
||||
/* Hide when search term returns nothing */
|
||||
.no-results { display: none; }
|
||||
|
||||
/* Additional spacing when in edit mode */
|
||||
&.edit-mode {
|
||||
margin-bottom: 12rem;
|
||||
}
|
||||
|
||||
/* When in single-section view mode */
|
||||
&.single-section-view {
|
||||
display: block;
|
||||
}
|
||||
.add-new-section {
|
||||
border: 2px dashed var(--primary);
|
||||
border-radius: var(--curve-factor);
|
||||
padding: var(--item-group-padding);
|
||||
background: var(--item-group-background);
|
||||
color: var(--primary);
|
||||
font-size: 1.2rem;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
height: fit-content;
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom styles only applied when there is no sections in config */
|
||||
|
||||
@@ -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, InfoKeys } from '@/utils/ErrorHandler';
|
||||
import {
|
||||
checkCredentials,
|
||||
login,
|
||||
@@ -91,9 +91,6 @@ export default {
|
||||
Button,
|
||||
Input,
|
||||
},
|
||||
props: {
|
||||
appConfig: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
username: '',
|
||||
@@ -104,6 +101,9 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
appConfig() {
|
||||
return this.$store.getters.appConfig;
|
||||
},
|
||||
/* Data for timeout dropdown menu, translated label + value in ms */
|
||||
dropDownMenu() {
|
||||
return [
|
||||
@@ -159,9 +159,9 @@ export default {
|
||||
if (response.correct) { // Yay, credentials were correct :)
|
||||
login(this.username, this.password, timeout); // Login, to set the cookie
|
||||
this.goHome();
|
||||
InfoHandler(`Succesfully signed in as ${this.username}`, 'Authentication');
|
||||
InfoHandler(`Succesfully signed in as ${this.username}`, InfoKeys.AUTH);
|
||||
} else {
|
||||
InfoHandler(`Unable to Sign In - ${this.message}`, 'Authentication');
|
||||
WarningInfoHandler('Unable to Sign In', InfoKeys.AUTH, this.message);
|
||||
}
|
||||
},
|
||||
/* Calls function to double-check guest access enabled, then log in as guest */
|
||||
@@ -169,9 +169,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', InfoKeys.AUTH);
|
||||
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', InfoKeys.AUTH);
|
||||
}
|
||||
},
|
||||
/* Calls logout, shows status message, and refreshed page */
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
<div class="minimal-home" :style="getBackgroundImage() + setColumnCount()">
|
||||
<!-- Buttons for config and home page -->
|
||||
<div class="minimal-buttons">
|
||||
<ConfigLauncher :sections="sections" :pageInfo="pageInfo" :appConfig="appConfig"
|
||||
@modalChanged="modalChanged" class="config-launcher" />
|
||||
<ConfigLauncher @modalChanged="modalChanged" class="config-launcher" />
|
||||
</div>
|
||||
<!-- Page title and search bar -->
|
||||
<div class="title-and-search">
|
||||
<router-link to="/">
|
||||
<h1>{{ pageInfo.title }}</h1>
|
||||
</router-link>
|
||||
<MinimalSearch @user-is-searchin="(s) => { this.searchValue = s; }" :active="!modalOpen" />
|
||||
<MinimalSearch
|
||||
@user-is-searchin="(s) => { this.searchValue = s; }"
|
||||
:active="!modalOpen" ref="filterComp" />
|
||||
</div>
|
||||
<div v-if="checkTheresData(sections)"
|
||||
:class="`item-group-container ${!tabbedView ? 'showing-all' : ''}`">
|
||||
@@ -60,11 +61,6 @@ import ConfigLauncher from '@/components/Settings/ConfigLauncher';
|
||||
|
||||
export default {
|
||||
name: 'home',
|
||||
props: {
|
||||
sections: Array, // Main site content
|
||||
appConfig: Object, // Main site configuation (optional)
|
||||
pageInfo: Object,
|
||||
},
|
||||
components: {
|
||||
MinimalSection,
|
||||
MinimalHeading,
|
||||
@@ -79,10 +75,21 @@ export default {
|
||||
tabbedView: true, // By default use tabs, when searching then show all instead
|
||||
theme: GetTheme(),
|
||||
}),
|
||||
computed: {
|
||||
sections() {
|
||||
return this.$store.getters.sections;
|
||||
},
|
||||
appConfig() {
|
||||
return this.$store.getters.appConfig;
|
||||
},
|
||||
pageInfo() {
|
||||
return this.$store.getters.pageInfo;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
/* When the theme changes, then call the update method */
|
||||
searchValue() {
|
||||
this.tabbedView = !(this.searchValue.length > 0);
|
||||
this.tabbedView = !this.searchValue || this.searchValue.length === 0;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -111,7 +118,7 @@ export default {
|
||||
},
|
||||
/* Clears input field, once a searched item is opened */
|
||||
finishedSearching() {
|
||||
this.$refs.filterComp.clearFilterInput();
|
||||
this.$refs.filterComp.clearMinFilterInput();
|
||||
},
|
||||
/* Extracts the site name from domain, used for the searching functionality */
|
||||
getDomainFromUrl(url) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="work-space">
|
||||
<SideBar :sections="sections" @launch-app="launchApp" />
|
||||
<SideBar :sections="sections" @launch-app="launchApp" :initUrl="getInitialUrl()" />
|
||||
<WebContent :url="url" v-if="!isMultiTaskingEnabled" />
|
||||
<MultiTaskingWebComtent :url="url" v-else />
|
||||
</div>
|
||||
@@ -16,17 +16,19 @@ import { GetTheme, ApplyLocalTheme, ApplyCustomVariables } from '@/utils/ThemeHe
|
||||
|
||||
export default {
|
||||
name: 'Workspace',
|
||||
props: {
|
||||
sections: Array,
|
||||
appConfig: Object,
|
||||
},
|
||||
data: () => ({
|
||||
url: '', // this.$route.query.url || '',
|
||||
url: '',
|
||||
GetTheme,
|
||||
ApplyLocalTheme,
|
||||
ApplyCustomVariables,
|
||||
}),
|
||||
computed: {
|
||||
sections() {
|
||||
return this.$store.getters.sections;
|
||||
},
|
||||
appConfig() {
|
||||
return this.$store.getters.appConfig;
|
||||
},
|
||||
isMultiTaskingEnabled() {
|
||||
return this.appConfig.enableMultiTasking || false;
|
||||
},
|
||||
@@ -37,8 +39,12 @@ export default {
|
||||
MultiTaskingWebComtent,
|
||||
},
|
||||
methods: {
|
||||
launchApp(url) {
|
||||
this.url = url;
|
||||
launchApp(options) {
|
||||
if (options.target === 'newtab') {
|
||||
window.open(options.url, '_blank');
|
||||
} else {
|
||||
this.url = options.url;
|
||||
}
|
||||
},
|
||||
setTheme() {
|
||||
const theme = this.GetTheme();
|
||||
@@ -51,16 +57,21 @@ export default {
|
||||
fontAwesomeScript.setAttribute('src', `https://kit.fontawesome.com/${faKey}.js`);
|
||||
document.head.appendChild(fontAwesomeScript);
|
||||
},
|
||||
repositionFooter() {
|
||||
document.getElementsByTagName('footer')[0].style.position = 'fixed';
|
||||
/* Returns a service URL, if set as a URL param, or if user has specified landing URL */
|
||||
getInitialUrl() {
|
||||
const route = this.$route;
|
||||
if (route.query && route.query.url) {
|
||||
return decodeURI(route.query.url);
|
||||
} else if (this.appConfig.workspaceLandingUrl) {
|
||||
return this.appConfig.workspaceLandingUrl;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const route = this.$route;
|
||||
if (route.query && route.query.url) this.url = decodeURI(route.query.url);
|
||||
this.setTheme();
|
||||
this.initiateFontAwesome();
|
||||
// this.repositionFooter();
|
||||
this.url = this.getInitialUrl();
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user