mirror of
https://github.com/Lissy93/dashy.git
synced 2025-07-23 21:55:30 +02:00
Implemented a workspace feature
This commit is contained in:
parent
f5ecdb4459
commit
3a22283f3c
@ -68,6 +68,7 @@ export default {
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '@/styles/global-styles.scss';
|
@import '@/styles/global-styles.scss';
|
||||||
@import '@/styles/color-palette.scss';
|
@import '@/styles/color-palette.scss';
|
||||||
|
@import '@/styles/dimensions.scss';
|
||||||
@import '@/styles/color-themes.scss';
|
@import '@/styles/color-themes.scss';
|
||||||
@import '@/styles/typography.scss';
|
@import '@/styles/typography.scss';
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="item-icon">
|
||||||
<i v-if="iconType === 'font-awesome'" :class="`${icon} ${size}`" ></i>
|
<i v-if="iconType === 'font-awesome'" :class="`${icon} ${size}`" ></i>
|
||||||
<img v-else-if="icon" :src="iconPath" @error="imageNotFound"
|
<img v-else-if="icon" :src="iconPath" @error="imageNotFound"
|
||||||
:class="`tile-icon ${size} ${broken ? 'broken' : ''}`"
|
:class="`tile-icon ${size} ${broken ? 'broken' : ''}`"
|
||||||
@ -98,9 +98,16 @@ export default {
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.tile-icon {
|
.tile-icon {
|
||||||
width: 60px;
|
width: 2rem;
|
||||||
// filter: var(--item-icon-transform);
|
// filter: var(--item-icon-transform);
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
&.broken { display: none; }
|
&.broken { display: none; }
|
||||||
|
&.small {
|
||||||
|
width: 1.5rem;
|
||||||
|
}
|
||||||
|
&.large {
|
||||||
|
width: 3rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i.fas, i.fab, i.far, i.fal, i.fad {
|
i.fas, i.fab, i.far, i.fal, i.fad {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
|
@ -54,6 +54,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
/* Sets the theme, by updating data-theme attribute on the html tag */
|
||||||
setLocalTheme(newTheme) {
|
setLocalTheme(newTheme) {
|
||||||
const htmlTag = document.getElementsByTagName('html')[0];
|
const htmlTag = document.getElementsByTagName('html')[0];
|
||||||
if (htmlTag.hasAttribute('data-theme')) htmlTag.removeAttribute('data-theme');
|
if (htmlTag.hasAttribute('data-theme')) htmlTag.removeAttribute('data-theme');
|
||||||
|
@ -1,7 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<nav class="side-bar">
|
<nav class="side-bar">
|
||||||
<div v-for="(section, index) in sections" :key="index">
|
<div v-for="(section, index) in sections" :key="index">
|
||||||
<SideBarItem class="item" :icon="section.icon" :title="section.title" />
|
<div @click="openSection(index)" class="side-bar-item-container">
|
||||||
|
<SideBarItem
|
||||||
|
class="item"
|
||||||
|
:icon="section.icon"
|
||||||
|
:title="section.name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<transition name="slide">
|
||||||
|
<SideBarSection
|
||||||
|
v-if="isOpen[index]"
|
||||||
|
:items="section.items"
|
||||||
|
@launch-app="launchApp"
|
||||||
|
/>
|
||||||
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
@ -9,6 +22,7 @@
|
|||||||
<script>
|
<script>
|
||||||
|
|
||||||
import SideBarItem from '@/components/Workspace/SideBarItem.vue';
|
import SideBarItem from '@/components/Workspace/SideBarItem.vue';
|
||||||
|
import SideBarSection from '@/components/Workspace/SideBarSection.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SideBar',
|
name: 'SideBar',
|
||||||
@ -16,13 +30,29 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
sections: Array,
|
sections: Array,
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isOpen: new Array(this.sections.length).fill(false),
|
||||||
|
};
|
||||||
|
},
|
||||||
components: {
|
components: {
|
||||||
SideBarItem,
|
SideBarItem,
|
||||||
|
SideBarSection,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/* Toggles the section clicked, and closes all other sections */
|
||||||
|
openSection(index) {
|
||||||
|
this.isOpen = this.isOpen.map((val, ind) => (ind !== index ? false : !val));
|
||||||
|
},
|
||||||
|
launchApp(url) {
|
||||||
|
this.$emit('launch-app', url);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
@import '@/styles/media-queries.scss';
|
@import '@/styles/media-queries.scss';
|
||||||
@import '@/styles/style-helpers.scss';
|
@import '@/styles/style-helpers.scss';
|
||||||
|
|
||||||
@ -33,11 +63,28 @@ nav.side-bar {
|
|||||||
background: var(--side-bar-background);
|
background: var(--side-bar-background);
|
||||||
color: var(--side-bar-color);
|
color: var(--side-bar-color);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 3rem;
|
width: var(--side-bar-width);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
overflow: auto;
|
||||||
|
@extend .scroll-bar;
|
||||||
|
.side-bar-item-container {
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
.item:not(:last-child) {
|
.item:not(:last-child) {
|
||||||
border-bottom: 1px dashed var(--side-bar-color);
|
border-bottom: 1px dashed var(--side-bar-color);
|
||||||
|
z-index: 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.slide-leave-active,
|
||||||
|
.slide-enter-active {
|
||||||
|
transition: all 0.1s ease-in-out;
|
||||||
|
}
|
||||||
|
.slide-enter {
|
||||||
|
transform: translate(0, -80%);
|
||||||
|
}
|
||||||
|
.slide-leave-to {
|
||||||
|
transform: translate(0, -80%);
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="side-bar-item">
|
<div @click="itemClicked()"
|
||||||
<Icon v-if="icon" :icon="icon" size="small" />
|
:class="`side-bar-item ${icon ? 'w-icon' : 'text-only'}`" v-tooltip="tooltip">
|
||||||
<p v-else>{{ title }}</p>
|
<Icon v-if="icon" :icon="icon" size="small" :url="url" />
|
||||||
|
<p class="small-title" v-else>{{ title }}</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import Icon from '@/components/LinkItems/ItemIcon.vue';
|
import Icon from '@/components/LinkItems/ItemIcon.vue';
|
||||||
import Defaults from '@/utils/defaults';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SideBarItem',
|
name: 'SideBarItem',
|
||||||
@ -16,21 +16,30 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
icon: String,
|
icon: String,
|
||||||
title: String,
|
title: String,
|
||||||
},
|
url: String,
|
||||||
mounted() {
|
click: Function,
|
||||||
this.initiateFontAwesome();
|
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Icon,
|
Icon,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initiateFontAwesome() {
|
itemClicked() {
|
||||||
const fontAwesomeScript = document.createElement('script');
|
if (this.url) this.$emit('launch-app', this.url);
|
||||||
const faKey = this.config.appConfig.fontAwesomeKey || Defaults.fontAwesomeKey;
|
|
||||||
fontAwesomeScript.setAttribute('src', `https://kit.fontawesome.com/${faKey}.js`);
|
|
||||||
document.head.appendChild(fontAwesomeScript);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tooltip: {
|
||||||
|
disabled: !this.title,
|
||||||
|
content: this.title,
|
||||||
|
trigger: 'hover focus',
|
||||||
|
hideOnTargetClick: true,
|
||||||
|
html: false,
|
||||||
|
placement: 'right-start',
|
||||||
|
delay: { show: 800, hide: 1000 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -42,6 +51,14 @@ div.side-bar-item {
|
|||||||
color: var(--side-bar-color);
|
color: var(--side-bar-color);
|
||||||
background: var(--side-bar-background);
|
background: var(--side-bar-background);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
&.text-only {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
p.small-title {
|
||||||
|
margin: 0.1rem auto;
|
||||||
|
font-size: 0.6rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
54
src/components/Workspace/SideBarSection.vue
Normal file
54
src/components/Workspace/SideBarSection.vue
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<div class="sub-side-bar">
|
||||||
|
<div v-for="(item, index) in items" :key="index">
|
||||||
|
<SideBarItem
|
||||||
|
class="item"
|
||||||
|
:icon="item.icon"
|
||||||
|
:title="item.title"
|
||||||
|
:url="item.url"
|
||||||
|
@launch-app="launchApp"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import SideBarItem from '@/components/Workspace/SideBarItem.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SideBarSection',
|
||||||
|
inject: ['config'],
|
||||||
|
props: {
|
||||||
|
items: Array,
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
SideBarItem,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
launchApp(url) {
|
||||||
|
this.$emit('launch-app', url);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '@/styles/media-queries.scss';
|
||||||
|
@import '@/styles/style-helpers.scss';
|
||||||
|
|
||||||
|
div.sub-side-bar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: var(--side-bar-background-lighter);
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
margin: 0.2rem;
|
||||||
|
color: var(--side-bar-color);
|
||||||
|
text-align: center;
|
||||||
|
z-index: 3;
|
||||||
|
.item:not(:last-child) {
|
||||||
|
border-bottom: 1px dashed var(--side-bar-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -20,9 +20,9 @@ export default {
|
|||||||
|
|
||||||
iframe {
|
iframe {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 3rem;
|
left: var(--side-bar-width);
|
||||||
height: calc(100% - 6.3rem);
|
height: calc(100% - var(--header-height));
|
||||||
width: calc(100% - 3rem);
|
width: calc(100% - var(--side-bar-width));
|
||||||
border: none;
|
border: none;
|
||||||
background: white;
|
background: white;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="work-space">
|
<div class="work-space">
|
||||||
<SideBar :sections="sections" />
|
<SideBar :sections="sections" @launch-app="launchApp" />
|
||||||
<WebContent :url="url" />
|
<WebContent :url="url" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -9,11 +9,13 @@
|
|||||||
|
|
||||||
import SideBar from '@/components/Workspace/SideBar';
|
import SideBar from '@/components/Workspace/SideBar';
|
||||||
import WebContent from '@/components/Workspace/WebContent';
|
import WebContent from '@/components/Workspace/WebContent';
|
||||||
|
import Defaults, { localStorageKeys } from '@/utils/defaults';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Workspace',
|
name: 'Workspace',
|
||||||
props: {
|
props: {
|
||||||
sections: Array,
|
sections: Array,
|
||||||
|
appConfig: Object,
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
url: '',
|
url: '',
|
||||||
@ -22,6 +24,27 @@ export default {
|
|||||||
SideBar,
|
SideBar,
|
||||||
WebContent,
|
WebContent,
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
launchApp(url) {
|
||||||
|
this.url = url;
|
||||||
|
},
|
||||||
|
setTheme() {
|
||||||
|
const theme = localStorage[localStorageKeys.THEME] || this.confTheme || Defaults.theme;
|
||||||
|
const htmlTag = document.getElementsByTagName('html')[0];
|
||||||
|
if (htmlTag.hasAttribute('data-theme')) htmlTag.removeAttribute('data-theme');
|
||||||
|
htmlTag.setAttribute('data-theme', theme);
|
||||||
|
},
|
||||||
|
initiateFontAwesome() {
|
||||||
|
const fontAwesomeScript = document.createElement('script');
|
||||||
|
const faKey = this.appConfig.fontAwesomeKey || Defaults.fontAwesomeKey;
|
||||||
|
fontAwesomeScript.setAttribute('src', `https://kit.fontawesome.com/${faKey}.js`);
|
||||||
|
document.head.appendChild(fontAwesomeScript);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.setTheme();
|
||||||
|
this.initiateFontAwesome();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user