Basic multi-page support working (#584)

This commit is contained in:
Alicia Sykes 2022-04-19 21:16:27 +01:00
parent cf7587b4ee
commit 036bc008c5
7 changed files with 87 additions and 10 deletions

View File

@ -1,12 +1,12 @@
<template>
<div class="nav-outer" v-if="links && links.length > 0">
<div class="nav-outer" v-if="allLinks && allLinks.length > 0">
<IconBurger
:class="`burger ${!navVisible ? 'visible' : ''}`"
@click="navVisible = !navVisible"
/>
<nav id="nav" v-if="navVisible">
<!-- Render either router-link or anchor, depending if internal / external link -->
<template v-for="(link, index) in links">
<template v-for="(link, index) in allLinks">
<router-link v-if="!isUrl(link.path)"
:key="index"
:to="link.path"
@ -28,6 +28,7 @@
<script>
import IconBurger from '@/assets/interface-icons/burger-menu.svg';
import { makePageSlug } from '@/utils/ConfigHelpers';
export default {
name: 'Nav',
@ -41,6 +42,17 @@ export default {
navVisible: true,
isMobile: false,
}),
computed: {
/* Get links to sub-pages, and combine with nav-links */
allLinks() {
const subPages = this.$store.getters.pages.map((subPage) => ({
path: makePageSlug(subPage.path, 'home'),
title: subPage.name,
}));
const navLinks = this.links || [];
return [...navLinks, ...subPages];
},
},
created() {
this.navVisible = !this.detectMobile();
this.isMobile = this.detectMobile();

View File

@ -3,10 +3,13 @@
*/
import Defaults, { localStorageKeys, iconCdns } from '@/utils/defaults';
import Keys from '@/utils/StoreMutations';
import { searchTiles } from '@/utils/Search';
const HomeMixin = {
props: {},
props: {
confPath: String,
},
computed: {
sections() {
return this.$store.getters.sections;
@ -27,7 +30,22 @@ const HomeMixin = {
data: () => ({
searchValue: '',
}),
async mounted() {
await this.getConfigForRoute();
},
watch: {
async $route() {
await this.getConfigForRoute();
},
},
methods: {
async getConfigForRoute() {
if (this.confPath) { // Get config for sub-page
await this.$store.dispatch(Keys.INITIALIZE_MULTI_PAGE_CONFIG, this.confPath);
} else { // Otherwise, use main config
this.$store.commit(Keys.USE_MAIN_CONFIG);
}
},
updateModalVisibility(modalState) {
this.$store.commit('SET_MODAL_OPEN', modalState);
},

View File

@ -11,10 +11,13 @@ import { Progress } from 'rsup-progress';
// Import views, that are not lazy-loaded
import Home from '@/views/Home.vue';
// import Workspace from '@/views/Workspace.vue';
// import Minimal from '@/views/Minimal.vue';
import ConfigAccumulator from '@/utils/ConfigAccumalator';
// Import helper functions, config data and defaults
import { isAuthEnabled, isLoggedIn, isGuestAccessEnabled } from '@/utils/Auth';
import { makePageSlug } from '@/utils/ConfigHelpers';
import { metaTagData, startingView, routePaths } from '@/utils/defaults';
import ErrorHandler from '@/utils/ErrorHandler';
@ -64,19 +67,33 @@ const makeMetaTags = (defaultTitle) => ({
metaTags: metaTagData,
});
const makePageSlug = (pageName) => {
const formattedName = pageName.toLowerCase().replaceAll(' ', '-');
return `/${formattedName}`;
const makeSubConfigPath = (rawPath) => {
if (rawPath.startsWith('/') || rawPath.startsWith('http')) return rawPath;
else return `/${rawPath}`;
};
/* For each additional config file, create routes for home, minimal and workspace views */
const makeMultiPageRoutes = (userPages) => {
if (!userPages) return [];
const multiPageRoutes = [];
userPages.forEach((page) => {
multiPageRoutes.push({
path: makePageSlug(page.name),
name: page.name,
path: makePageSlug(page.name, 'home'),
name: `${page.name}-home`,
component: Home,
props: { confPath: makeSubConfigPath(page.path) },
});
multiPageRoutes.push({
path: makePageSlug(page.name, 'workspace'),
name: `${page.name}-workspace`,
component: () => import('./views/Workspace.vue'),
props: { confPath: makeSubConfigPath(page.path) },
});
multiPageRoutes.push({
path: makePageSlug(page.name, 'minimal'),
name: `${page.name}-minimal`,
component: () => import('./views/Minimal.vue'),
props: { confPath: makeSubConfigPath(page.path) },
});
});
return multiPageRoutes;

View File

@ -8,13 +8,14 @@ import ConfigAccumulator from '@/utils/ConfigAccumalator';
import { componentVisibility } from '@/utils/ConfigHelpers';
import { applyItemId } from '@/utils/SectionHelpers';
import filterUserSections from '@/utils/CheckSectionVisibility';
import { InfoHandler, InfoKeys } from '@/utils/ErrorHandler';
import ErrorHandler, { InfoHandler, InfoKeys } from '@/utils/ErrorHandler';
import { isUserAdmin } from '@/utils/Auth';
Vue.use(Vuex);
const {
INITIALIZE_CONFIG,
INITIALIZE_MULTI_PAGE_CONFIG,
SET_CONFIG,
SET_REMOTE_CONFIG,
SET_MODAL_OPEN,
@ -24,6 +25,7 @@ const {
SET_THEME,
SET_CUSTOM_COLORS,
UPDATE_ITEM,
USE_MAIN_CONFIG,
SET_EDIT_MODE,
SET_PAGE_INFO,
SET_APP_CONFIG,
@ -59,6 +61,9 @@ const store = new Vuex.Store({
sections(state) {
return filterUserSections(state.config.sections || []);
},
pages(state) {
return state.remoteConfig.pages || [];
},
theme(state) {
return state.config.appConfig.theme;
},
@ -275,6 +280,13 @@ const store = new Vuex.Store({
[CONF_MENU_INDEX](state, index) {
state.navigateConfToTab = index;
},
[USE_MAIN_CONFIG](state) {
if (state.remoteConfig) {
state.config = state.remoteConfig;
} else {
this.dispatch(Keys.INITIALIZE_CONFIG);
}
},
},
actions: {
/* Called when app first loaded. Reads config and sets state */
@ -285,6 +297,16 @@ const store = new Vuex.Store({
const config = deepCopy(new ConfigAccumulator().config());
commit(SET_CONFIG, config);
},
/* Fetch config for a sub-page (sections and pageInfo only) */
async [INITIALIZE_MULTI_PAGE_CONFIG]({ commit, state }, configPath) {
axios.get(configPath).then((response) => {
const subConfig = yaml.load(response.data);
subConfig.appConfig = state.config.appConfig; // Always use parent appConfig
commit(SET_CONFIG, subConfig);
}).catch((err) => {
ErrorHandler(`Unable to load config from '${configPath}'`, err);
});
},
},
modules: {},
});

View File

@ -10,6 +10,12 @@ import {
import ErrorHandler from '@/utils/ErrorHandler';
import ConfigSchema from '@/utils/ConfigSchema.json';
/* For a given sub-page, and page type, return the URL */
export const makePageSlug = (pageName, pageType) => {
const formattedName = pageName.toLowerCase().replaceAll(' ', '-').replaceAll('.yml', '');
return `/${pageType}/${formattedName}`;
};
/**
* Initiates the Accumulator class and generates a complete config object
* Self-executing function, returns the full user config as a JSON object

View File

@ -33,7 +33,7 @@ const setSwStatus = (swStateToSet) => {
* Or disable if user specified to disable
*/
const shouldEnableServiceWorker = async () => {
const conf = yaml.load((await axios.get('conf.yml')).data);
const conf = yaml.load((await axios.get('/conf.yml')).data);
if (conf && conf.appConfig && conf.appConfig.enableServiceWorker) {
setSwStatus({ disabledByUser: false });
return true;

View File

@ -1,6 +1,7 @@
// A list of mutation names
const KEY_NAMES = [
'INITIALIZE_CONFIG',
'INITIALIZE_MULTI_PAGE_CONFIG',
'SET_CONFIG',
'SET_REMOTE_CONFIG',
'SET_MODAL_OPEN',
@ -10,6 +11,7 @@ const KEY_NAMES = [
'SET_ITEM_SIZE',
'SET_THEME',
'SET_CUSTOM_COLORS',
'USE_MAIN_CONFIG',
'UPDATE_ITEM',
'SET_PAGE_INFO',
'SET_APP_CONFIG',