mirror of
https://github.com/Lissy93/dashy.git
synced 2025-07-21 04:35:15 +02:00
✨ Basic multi-page support working (#584)
This commit is contained in:
parent
cf7587b4ee
commit
036bc008c5
@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="nav-outer" v-if="links && links.length > 0">
|
<div class="nav-outer" v-if="allLinks && allLinks.length > 0">
|
||||||
<IconBurger
|
<IconBurger
|
||||||
:class="`burger ${!navVisible ? 'visible' : ''}`"
|
:class="`burger ${!navVisible ? 'visible' : ''}`"
|
||||||
@click="navVisible = !navVisible"
|
@click="navVisible = !navVisible"
|
||||||
/>
|
/>
|
||||||
<nav id="nav" v-if="navVisible">
|
<nav id="nav" v-if="navVisible">
|
||||||
<!-- Render either router-link or anchor, depending if internal / external link -->
|
<!-- 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)"
|
<router-link v-if="!isUrl(link.path)"
|
||||||
:key="index"
|
:key="index"
|
||||||
:to="link.path"
|
:to="link.path"
|
||||||
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import IconBurger from '@/assets/interface-icons/burger-menu.svg';
|
import IconBurger from '@/assets/interface-icons/burger-menu.svg';
|
||||||
|
import { makePageSlug } from '@/utils/ConfigHelpers';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Nav',
|
name: 'Nav',
|
||||||
@ -41,6 +42,17 @@ export default {
|
|||||||
navVisible: true,
|
navVisible: true,
|
||||||
isMobile: false,
|
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() {
|
created() {
|
||||||
this.navVisible = !this.detectMobile();
|
this.navVisible = !this.detectMobile();
|
||||||
this.isMobile = this.detectMobile();
|
this.isMobile = this.detectMobile();
|
||||||
|
@ -3,10 +3,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Defaults, { localStorageKeys, iconCdns } from '@/utils/defaults';
|
import Defaults, { localStorageKeys, iconCdns } from '@/utils/defaults';
|
||||||
|
import Keys from '@/utils/StoreMutations';
|
||||||
import { searchTiles } from '@/utils/Search';
|
import { searchTiles } from '@/utils/Search';
|
||||||
|
|
||||||
const HomeMixin = {
|
const HomeMixin = {
|
||||||
props: {},
|
props: {
|
||||||
|
confPath: String,
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
sections() {
|
sections() {
|
||||||
return this.$store.getters.sections;
|
return this.$store.getters.sections;
|
||||||
@ -27,7 +30,22 @@ const HomeMixin = {
|
|||||||
data: () => ({
|
data: () => ({
|
||||||
searchValue: '',
|
searchValue: '',
|
||||||
}),
|
}),
|
||||||
|
async mounted() {
|
||||||
|
await this.getConfigForRoute();
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
async $route() {
|
||||||
|
await this.getConfigForRoute();
|
||||||
|
},
|
||||||
|
},
|
||||||
methods: {
|
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) {
|
updateModalVisibility(modalState) {
|
||||||
this.$store.commit('SET_MODAL_OPEN', modalState);
|
this.$store.commit('SET_MODAL_OPEN', modalState);
|
||||||
},
|
},
|
||||||
|
@ -11,10 +11,13 @@ import { Progress } from 'rsup-progress';
|
|||||||
|
|
||||||
// Import views, that are not lazy-loaded
|
// Import views, that are not lazy-loaded
|
||||||
import Home from '@/views/Home.vue';
|
import Home from '@/views/Home.vue';
|
||||||
|
// import Workspace from '@/views/Workspace.vue';
|
||||||
|
// import Minimal from '@/views/Minimal.vue';
|
||||||
import ConfigAccumulator from '@/utils/ConfigAccumalator';
|
import ConfigAccumulator from '@/utils/ConfigAccumalator';
|
||||||
|
|
||||||
// Import helper functions, config data and defaults
|
// Import helper functions, config data and defaults
|
||||||
import { isAuthEnabled, isLoggedIn, isGuestAccessEnabled } from '@/utils/Auth';
|
import { isAuthEnabled, isLoggedIn, isGuestAccessEnabled } from '@/utils/Auth';
|
||||||
|
import { makePageSlug } from '@/utils/ConfigHelpers';
|
||||||
import { metaTagData, startingView, routePaths } from '@/utils/defaults';
|
import { metaTagData, startingView, routePaths } from '@/utils/defaults';
|
||||||
import ErrorHandler from '@/utils/ErrorHandler';
|
import ErrorHandler from '@/utils/ErrorHandler';
|
||||||
|
|
||||||
@ -64,19 +67,33 @@ const makeMetaTags = (defaultTitle) => ({
|
|||||||
metaTags: metaTagData,
|
metaTags: metaTagData,
|
||||||
});
|
});
|
||||||
|
|
||||||
const makePageSlug = (pageName) => {
|
const makeSubConfigPath = (rawPath) => {
|
||||||
const formattedName = pageName.toLowerCase().replaceAll(' ', '-');
|
if (rawPath.startsWith('/') || rawPath.startsWith('http')) return rawPath;
|
||||||
return `/${formattedName}`;
|
else return `/${rawPath}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* For each additional config file, create routes for home, minimal and workspace views */
|
||||||
const makeMultiPageRoutes = (userPages) => {
|
const makeMultiPageRoutes = (userPages) => {
|
||||||
if (!userPages) return [];
|
if (!userPages) return [];
|
||||||
const multiPageRoutes = [];
|
const multiPageRoutes = [];
|
||||||
userPages.forEach((page) => {
|
userPages.forEach((page) => {
|
||||||
multiPageRoutes.push({
|
multiPageRoutes.push({
|
||||||
path: makePageSlug(page.name),
|
path: makePageSlug(page.name, 'home'),
|
||||||
name: page.name,
|
name: `${page.name}-home`,
|
||||||
component: 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;
|
return multiPageRoutes;
|
||||||
|
24
src/store.js
24
src/store.js
@ -8,13 +8,14 @@ import ConfigAccumulator from '@/utils/ConfigAccumalator';
|
|||||||
import { componentVisibility } from '@/utils/ConfigHelpers';
|
import { componentVisibility } from '@/utils/ConfigHelpers';
|
||||||
import { applyItemId } from '@/utils/SectionHelpers';
|
import { applyItemId } from '@/utils/SectionHelpers';
|
||||||
import filterUserSections from '@/utils/CheckSectionVisibility';
|
import filterUserSections from '@/utils/CheckSectionVisibility';
|
||||||
import { InfoHandler, InfoKeys } from '@/utils/ErrorHandler';
|
import ErrorHandler, { InfoHandler, InfoKeys } from '@/utils/ErrorHandler';
|
||||||
import { isUserAdmin } from '@/utils/Auth';
|
import { isUserAdmin } from '@/utils/Auth';
|
||||||
|
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
INITIALIZE_CONFIG,
|
INITIALIZE_CONFIG,
|
||||||
|
INITIALIZE_MULTI_PAGE_CONFIG,
|
||||||
SET_CONFIG,
|
SET_CONFIG,
|
||||||
SET_REMOTE_CONFIG,
|
SET_REMOTE_CONFIG,
|
||||||
SET_MODAL_OPEN,
|
SET_MODAL_OPEN,
|
||||||
@ -24,6 +25,7 @@ const {
|
|||||||
SET_THEME,
|
SET_THEME,
|
||||||
SET_CUSTOM_COLORS,
|
SET_CUSTOM_COLORS,
|
||||||
UPDATE_ITEM,
|
UPDATE_ITEM,
|
||||||
|
USE_MAIN_CONFIG,
|
||||||
SET_EDIT_MODE,
|
SET_EDIT_MODE,
|
||||||
SET_PAGE_INFO,
|
SET_PAGE_INFO,
|
||||||
SET_APP_CONFIG,
|
SET_APP_CONFIG,
|
||||||
@ -59,6 +61,9 @@ const store = new Vuex.Store({
|
|||||||
sections(state) {
|
sections(state) {
|
||||||
return filterUserSections(state.config.sections || []);
|
return filterUserSections(state.config.sections || []);
|
||||||
},
|
},
|
||||||
|
pages(state) {
|
||||||
|
return state.remoteConfig.pages || [];
|
||||||
|
},
|
||||||
theme(state) {
|
theme(state) {
|
||||||
return state.config.appConfig.theme;
|
return state.config.appConfig.theme;
|
||||||
},
|
},
|
||||||
@ -275,6 +280,13 @@ const store = new Vuex.Store({
|
|||||||
[CONF_MENU_INDEX](state, index) {
|
[CONF_MENU_INDEX](state, index) {
|
||||||
state.navigateConfToTab = index;
|
state.navigateConfToTab = index;
|
||||||
},
|
},
|
||||||
|
[USE_MAIN_CONFIG](state) {
|
||||||
|
if (state.remoteConfig) {
|
||||||
|
state.config = state.remoteConfig;
|
||||||
|
} else {
|
||||||
|
this.dispatch(Keys.INITIALIZE_CONFIG);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
/* Called when app first loaded. Reads config and sets state */
|
/* 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());
|
const config = deepCopy(new ConfigAccumulator().config());
|
||||||
commit(SET_CONFIG, 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: {},
|
modules: {},
|
||||||
});
|
});
|
||||||
|
@ -10,6 +10,12 @@ import {
|
|||||||
import ErrorHandler from '@/utils/ErrorHandler';
|
import ErrorHandler from '@/utils/ErrorHandler';
|
||||||
import ConfigSchema from '@/utils/ConfigSchema.json';
|
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
|
* Initiates the Accumulator class and generates a complete config object
|
||||||
* Self-executing function, returns the full user config as a JSON object
|
* Self-executing function, returns the full user config as a JSON object
|
||||||
|
@ -33,7 +33,7 @@ const setSwStatus = (swStateToSet) => {
|
|||||||
* Or disable if user specified to disable
|
* Or disable if user specified to disable
|
||||||
*/
|
*/
|
||||||
const shouldEnableServiceWorker = async () => {
|
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) {
|
if (conf && conf.appConfig && conf.appConfig.enableServiceWorker) {
|
||||||
setSwStatus({ disabledByUser: false });
|
setSwStatus({ disabledByUser: false });
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// A list of mutation names
|
// A list of mutation names
|
||||||
const KEY_NAMES = [
|
const KEY_NAMES = [
|
||||||
'INITIALIZE_CONFIG',
|
'INITIALIZE_CONFIG',
|
||||||
|
'INITIALIZE_MULTI_PAGE_CONFIG',
|
||||||
'SET_CONFIG',
|
'SET_CONFIG',
|
||||||
'SET_REMOTE_CONFIG',
|
'SET_REMOTE_CONFIG',
|
||||||
'SET_MODAL_OPEN',
|
'SET_MODAL_OPEN',
|
||||||
@ -10,6 +11,7 @@ const KEY_NAMES = [
|
|||||||
'SET_ITEM_SIZE',
|
'SET_ITEM_SIZE',
|
||||||
'SET_THEME',
|
'SET_THEME',
|
||||||
'SET_CUSTOM_COLORS',
|
'SET_CUSTOM_COLORS',
|
||||||
|
'USE_MAIN_CONFIG',
|
||||||
'UPDATE_ITEM',
|
'UPDATE_ITEM',
|
||||||
'SET_PAGE_INFO',
|
'SET_PAGE_INFO',
|
||||||
'SET_APP_CONFIG',
|
'SET_APP_CONFIG',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user