platypush/platypush/backend/http/webapp/src/components/Nav.vue

395 lines
8.5 KiB
Vue
Raw Normal View History

2020-11-30 20:57:00 +01:00
<template>
<nav :class="{collapsed: collapsed}">
<div class="toggler" @click="collapsed = !collapsed">
<i class="fas fa-bars" />
2020-12-14 02:13:55 +01:00
<span class="hostname" v-if="hostname" v-text="hostname" />
2020-11-30 20:57:00 +01:00
</div>
2023-08-06 18:49:03 +02:00
<ul class="plugins" v-if="selectedPanel === 'settings'">
<li class="entry" title="Home" @click="onItemClick('entities')">
<a href="/#">
<i class="fas fa-home" />
<span class="name" v-if="!collapsed">Home</span>
</a>
</li>
<li v-for="config, name in configSections" :key="name" class="entry"
:class="{selected: name === selectedConfigPanel}"
:title="config.name" @click="$emit('select-config', name)">
<a href="/#settings">
<span class="icon">
<i :class="config.icon['class']" v-if="config.icon?.['class']" />
<img :src="config.icon?.imgUrl" v-else-if="config.icon?.imgUrl" alt="name"/>
<i class="fas fa-puzzle-piece" v-else />
</span>
<span class="name" v-if="!collapsed" v-text="config.name" />
</a>
</li>
</ul>
<ul class="plugins" v-else>
2022-04-10 13:07:36 +02:00
<li v-for="name in panelNames" :key="name" class="entry" :class="{selected: name === selectedPanel}"
2020-12-26 15:03:12 +01:00
:title="name" @click="onItemClick(name)">
<a :href="`/#${name}`">
2020-11-30 20:57:00 +01:00
<span class="icon">
<i :class="icons[name].class" v-if="icons[name]?.class" />
2021-02-08 02:04:59 +01:00
<img :src="icons[name].imgUrl" v-else-if="icons[name]?.imgUrl" alt="name"/>
2020-11-30 20:57:00 +01:00
<i class="fas fa-puzzle-piece" v-else />
</span>
<span class="name" v-if="!collapsed" v-text="displayName(name)" />
2020-12-26 15:03:12 +01:00
</a>
</li>
</ul>
<ul class="footer">
<li :class="{selected: selectedPanel === 'extensions'}" title="Extensions" @click="onItemClick('extensions')">
<a href="/#extensions">
<span class="icon">
<i class="fa fa-puzzle-piece" />
</span>
<span class="name" v-if="!collapsed">Extensions</span>
</a>
</li>
<li :class="{selected: selectedPanel === 'settings'}" title="Settings" @click="onItemClick('settings')">
<a href="/#settings">
<span class="icon">
<i class="fa fa-cog" />
</span>
<span class="name" v-if="!collapsed">Settings</span>
</a>
</li>
<li title="Logout" @click="onItemClick('logout')">
<a href="/logout">
<span class="icon">
<i class="fas fa-sign-out-alt" />
</span>
<span class="name" v-if="!collapsed">Logout</span>
</a>
</li>
</ul>
2020-11-30 20:57:00 +01:00
</nav>
</template>
<script>
import icons from '@/assets/icons.json'
2020-12-14 02:13:55 +01:00
import Utils from "@/Utils";
2023-08-06 18:49:03 +02:00
import configSections from '@/components/panels/Settings/sections.json';
2020-11-30 20:57:00 +01:00
export default {
name: "Nav",
2023-08-06 18:49:03 +02:00
emits: ['select', 'select-config'],
2020-12-14 02:13:55 +01:00
mixins: [Utils],
2020-11-30 20:57:00 +01:00
props: {
panels: {
type: Object,
required: true,
},
selectedPanel: {
type: String,
},
2023-08-06 18:49:03 +02:00
selectedConfigPanel: {
type: String,
},
2020-11-30 20:57:00 +01:00
hostname: {
type: String,
},
},
2022-04-10 13:07:36 +02:00
computed: {
panelNames() {
const prepend = (names, name) => {
const idx = panelNames.indexOf(name)
if (idx >= 0)
names = [name].concat((names.slice(0, idx).concat(names.slice(idx+1))))
return names
}
let panelNames = Object.keys(this.panels).sort()
panelNames = prepend(panelNames, 'execute')
panelNames = prepend(panelNames, 'entities')
return panelNames
2022-04-10 13:07:36 +02:00
},
collapsedDefault() {
if (this.isMobile() || this.isTablet())
return true
return false
},
2022-04-10 13:07:36 +02:00
},
2020-12-03 00:59:35 +01:00
methods: {
2020-12-14 02:13:55 +01:00
onItemClick(name) {
this.$emit('select', name)
this.collapsed = this.isMobile() ? true : this.collapsedDefault
2020-12-14 02:13:55 +01:00
},
displayName(name) {
if (name === 'entities')
return 'Home'
if (name === 'execute')
return 'Execute'
return name
},
2020-12-03 00:59:35 +01:00
},
2020-11-30 20:57:00 +01:00
data() {
return {
2020-12-09 21:16:07 +01:00
collapsed: true,
2020-11-30 20:57:00 +01:00
icons: icons,
host: null,
2023-08-06 18:49:03 +02:00
configSections: configSections,
2020-11-30 20:57:00 +01:00
}
},
mounted() {
this.collapsed = this.collapsedDefault
},
2020-11-30 20:57:00 +01:00
}
</script>
<!--suppress SassScssResolvedByNameOnly -->
<style lang="scss" scoped>
$toggler-height: 2em;
$footer-collapsed-height: 7.5em;
$footer-expanded-height: 11em;
2020-11-30 20:57:00 +01:00
nav {
@media screen and (max-width: #{$tablet - 1px}) {
2020-12-14 02:13:55 +01:00
width: 100%;
height: 100vh;
background: $nav-bg;
color: $nav-fg;
box-shadow: $nav-box-shadow-main;
&.collapsed {
box-shadow: 1px 1px 1px 1px $default-shadow-color;
margin-bottom: 2px;
z-index: 1;
}
2020-12-14 02:13:55 +01:00
&:not(.collapsed) {
position: absolute;
top: 0;
left: 0;
z-index: 5;
2020-12-14 02:13:55 +01:00
}
}
@media screen and (min-width: $tablet) {
width: calc(16em - 2vw);
min-width: calc(16em - 2vw);
2020-12-14 02:13:55 +01:00
height: 100%;
overflow: auto;
background: $nav-bg;
color: $nav-fg;
box-shadow: $nav-box-shadow-main;
z-index: 1;
2020-12-14 02:13:55 +01:00
}
2020-11-30 20:57:00 +01:00
@media screen and (min-width: $desktop) {
width: 20em;
min-width: 20em;
}
2020-11-30 20:57:00 +01:00
li {
2023-03-19 22:23:37 +01:00
border-bottom: $nav-entry-border;
2020-11-30 20:57:00 +01:00
cursor: pointer;
2020-12-14 02:13:55 +01:00
list-style: none;
2020-11-30 20:57:00 +01:00
2020-12-03 00:59:35 +01:00
a {
display: block;
color: $nav-fg;
padding: 1em 0.5em;
text-decoration: none;
2020-12-03 00:59:35 +01:00
&:hover {
color: $nav-fg;
}
}
2020-11-30 20:57:00 +01:00
&.selected {
background: $nav-entry-selected-bg;
2023-03-19 22:23:37 +01:00
border: 1px solid rgba(0, 0, 0, 0);
}
&:hover {
background: $nav-entry-hover-bg;
border: 1px solid rgba(0, 0, 0, 0);
2020-11-30 20:57:00 +01:00
}
2021-02-14 21:08:29 +01:00
.name {
margin-left: 0.5em;
}
2020-11-30 20:57:00 +01:00
.icon {
margin-right: 0.5em;
}
}
.toggler {
width: 100%;
height: $toggler-height;
2021-02-19 22:55:31 +01:00
background: $nav-toggler-bg;
2023-03-19 22:23:37 +01:00
display: flex;
2020-11-30 20:57:00 +01:00
font-size: 1.5em;
cursor: pointer;
padding: 0.4em;
2020-12-14 02:13:55 +01:00
align-items: center;
2021-02-19 22:55:31 +01:00
box-shadow: $nav-toggler-shadow;
2020-12-14 02:13:55 +01:00
}
.hostname {
font-size: 0.7em;
margin-top: -0.2em;
2020-11-30 20:57:00 +01:00
2020-12-14 02:13:55 +01:00
@media screen and (min-width: $tablet) {
2020-11-30 20:57:00 +01:00
margin-left: 1em;
}
2020-12-14 02:13:55 +01:00
@media screen and (max-width: #{$tablet - 1px}) {
2020-12-14 02:13:55 +01:00
text-align: right;
margin-right: 0.25em;
flex-grow: 1;
}
2020-11-30 20:57:00 +01:00
}
.plugins {
height: calc(100% - #{$toggler-height} - #{$footer-expanded-height} - 1.5em);
overflow: auto;
}
.footer {
height: calc($footer-expanded-height + 0.4em);
2021-02-19 22:55:31 +01:00
background: $nav-footer-bg;
padding: 0;
margin: 0;
2023-03-19 22:23:37 +01:00
li:last-child {
border: 0;
}
}
ul {
li {
.icon {
margin-right: 0;
& img, i {
width: 1.5em;
height: 1.5em;
}
}
}
}
2020-11-30 20:57:00 +01:00
&.collapsed {
2020-12-26 15:03:12 +01:00
display: flex;
flex-direction: column;
2020-12-14 02:13:55 +01:00
@media screen and (min-width: $tablet) {
width: 2.5em;
min-width: 2.5em;
max-width: 2.5em;
2020-12-26 15:03:12 +01:00
background: $nav-collapsed-bg;
2020-12-14 02:13:55 +01:00
color: $nav-collapsed-fg;
box-shadow: $nav-box-shadow-collapsed;
.hostname {
display: none;
}
}
@media screen and (max-width: #{$tablet - 1px}) {
2020-12-14 02:13:55 +01:00
height: auto;
}
2020-11-30 20:57:00 +01:00
a {
color: $nav-collapsed-fg;
2020-12-03 00:59:35 +01:00
padding: 0.25em 0;
2020-11-30 20:57:00 +01:00
&:hover {
color: $nav-collapsed-fg;
}
}
.toggler {
height: $toggler-height;
2020-11-30 20:57:00 +01:00
text-align: center;
2021-02-19 22:55:31 +01:00
box-shadow: none;
background: $nav-toggler-collapsed-bg;
@media screen and (max-width: #{$tablet - 1px}) {
background: $nav-toggler-collapsed-mobile-bg;
color: $nav-toggler-collapsed-mobile-fg;
}
}
.footer {
height: $footer-collapsed-height;
2021-02-19 22:55:31 +01:00
background: none;
padding: 0;
margin-bottom: .5em;
2023-03-19 22:23:37 +01:00
box-shadow: none;
}
@media screen and (max-width: #{$tablet - 1px}) {
.footer {
display: none;
}
}
2020-12-26 15:03:12 +01:00
ul {
display: flex;
flex-direction: column;
justify-content: center;
2021-02-19 22:55:31 +01:00
height: calc(100% - #{$toggler-height} - #{$footer-collapsed-height});
overflow: hidden;
&.plugins {
@media screen and (min-width: $tablet) and (max-width: #{$desktop - 1px}) {
2021-02-19 22:55:31 +01:00
margin: 2em 0;
}
}
&:hover {
overflow: auto;
}
2020-11-30 20:57:00 +01:00
2020-12-26 15:03:12 +01:00
li {
2021-02-19 22:55:31 +01:00
border: none;
2020-12-26 15:03:12 +01:00
padding: 0;
text-align: center;
2020-11-30 20:57:00 +01:00
2020-12-26 15:03:12 +01:00
&.selected,
&:hover {
border-radius: 1em;
margin: 0 0.2em;
}
2020-11-30 20:57:00 +01:00
2020-12-26 15:03:12 +01:00
&.selected {
background: $nav-entry-collapsed-selected-bg;
}
2020-11-30 20:57:00 +01:00
2020-12-26 15:03:12 +01:00
&:hover {
background: $nav-entry-collapsed-hover-bg;
}
2020-12-14 02:13:55 +01:00
2020-12-26 15:03:12 +01:00
.icon {
margin-right: 0;
}
@media screen and (max-width: #{$tablet - 1px}) {
2020-12-26 15:03:12 +01:00
display: none;
}
2020-12-14 02:13:55 +01:00
}
2020-11-30 20:57:00 +01:00
}
}
}
</style>