195 lines
4.0 KiB
Vue
195 lines
4.0 KiB
Vue
<script setup>
|
|
|
|
import { ref, useTemplateRef, onMounted } from 'vue';
|
|
import { onSwipe } from '@cloudron/pankow/gestures.js';
|
|
import SideBarItem from './SideBarItem.vue';
|
|
|
|
defineProps({
|
|
cloudronAvatarUrl: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
cloudronName: {
|
|
type: String,
|
|
default: 'Cloudron',
|
|
},
|
|
items: {
|
|
type: Array
|
|
}
|
|
});
|
|
|
|
const sideBar = useTemplateRef('sideBar');
|
|
const isVisible = ref(false);
|
|
const isCollapsed = ref(!!window.localStorage['sideBarCollapsed']);
|
|
|
|
function open() {
|
|
isVisible.value = true;
|
|
}
|
|
|
|
function close() {
|
|
isVisible.value = false;
|
|
}
|
|
|
|
function onToggleCollapse() {
|
|
isCollapsed.value = !isCollapsed.value;
|
|
if (isCollapsed.value) window.localStorage['sideBarCollapsed'] = 'true';
|
|
else window.localStorage.removeItem('sideBarCollapsed');
|
|
}
|
|
|
|
onMounted(() => {
|
|
onSwipe(sideBar.value, (direction) => {
|
|
if (direction === 'left') close();
|
|
});
|
|
});
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<div class="sidebar" ref="sideBar" :class="{ 'sidebar-closed': !isVisible, 'sidebar-collapsed': isCollapsed }">
|
|
<Transition name="pankow-scale">
|
|
<div class="sidebar-close-action" v-if="isVisible" @click="close()"><i class="fa-solid fa-xmark"></i></div>
|
|
<div class="sidebar-open-action" v-else @click="open()"><i class="fa-solid fa-bars"></i></div>
|
|
</Transition>
|
|
<div class="sidebar-inner">
|
|
<a href="#/" class="sidebar-logo" @click="close()">
|
|
<img :src="cloudronAvatarUrl" :alt="cloudronName + ' icon'"/> {{ cloudronName }}
|
|
</a>
|
|
<div class="sidebar-list">
|
|
<SideBarItem v-for="item in items" :key="item"
|
|
:label="item.label"
|
|
:icon="item.icon"
|
|
:route="item.route"
|
|
:visible="item.visible"
|
|
:active="item.active"
|
|
:separator="item.separator"
|
|
:child-items="item.childItems"
|
|
:collapsed="isCollapsed"
|
|
@close="close"
|
|
/>
|
|
</div>
|
|
<div style="flex-grow: 1"></div>
|
|
<div class="sidebar-collapse-action pankow-no-mobile" @click="onToggleCollapse()"><i class="fa-solid" :class="{ 'fa-arrow-left': !isCollapsed, 'fa-arrow-right': isCollapsed }"></i> <span v-if="!isCollapsed">Collapse sidebar</span></div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
|
|
.sidebar {
|
|
display: block;
|
|
height: 100%;
|
|
overflow: auto;
|
|
background-color: var(--navbar-background);
|
|
padding: 22px 10px 10px 10px;
|
|
margin-right: 20px;
|
|
}
|
|
|
|
.sidebar-collapsed {
|
|
min-width: unset !important;
|
|
width: 70px;
|
|
}
|
|
|
|
.sidebar-collapse-action {
|
|
display: block;
|
|
color: gray;
|
|
border-radius: 3px;
|
|
padding: 5px 15px;
|
|
white-space: nowrap;
|
|
cursor: pointer;
|
|
transition: all 180ms ease-out;
|
|
}
|
|
|
|
.sidebar-collapse-action i {
|
|
opacity: 0.5;
|
|
margin-right: 10px;
|
|
}
|
|
|
|
|
|
.sidebar-inner {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
}
|
|
|
|
.sidebar-open-action {
|
|
display: none;
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
font-size: 24px;
|
|
padding: 8px 14px;
|
|
cursor: pointer;
|
|
color: var(--pankow-color-dark);
|
|
}
|
|
|
|
.sidebar-close-action {
|
|
display: none;
|
|
position: fixed;
|
|
top: 0;
|
|
right: 0;
|
|
font-size: 32px;
|
|
padding: 8px 20px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.sidebar-logo img {
|
|
margin-right: 10px;
|
|
height: 40px;
|
|
width: 40px;
|
|
border-radius: var(--pankow-border-radius);
|
|
}
|
|
|
|
.sidebar-logo,
|
|
.sidebar-logo:hover {
|
|
display: flex;
|
|
align-items: center;
|
|
color: var(--pankow-text-color);
|
|
text-decoration: none;
|
|
padding-left: 5px;
|
|
max-width: 300px;
|
|
overflow: hidden;
|
|
min-height: 55px;
|
|
}
|
|
|
|
.sidebar-list {
|
|
overflow: auto;
|
|
padding-top: 25px;
|
|
scrollbar-color: transparent transparent;
|
|
scrollbar-width: thin;
|
|
}
|
|
|
|
.sidebar-list:hover {
|
|
scrollbar-color: var(--color-neutral-border) transparent;
|
|
}
|
|
|
|
@media (max-width: 576px) {
|
|
.sidebar {
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: 2000;
|
|
transition: left 250ms ease-in-out;
|
|
}
|
|
|
|
.sidebar-closed {
|
|
position: fixed;
|
|
left: -600px; /* depends on media query */
|
|
}
|
|
|
|
.sidebar-open-action {
|
|
display: block;
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
z-index: 2000;
|
|
}
|
|
|
|
.sidebar-close-action {
|
|
display: block;
|
|
}
|
|
}
|
|
|
|
</style>
|