Use pankow SideBar component

This commit is contained in:
Johannes Zellner
2025-03-23 14:29:42 +01:00
parent 93d47bb0c2
commit c4205c1c11
2 changed files with 136 additions and 200 deletions

View File

@@ -1,197 +0,0 @@
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
const props = defineProps(['config', 'profile']);
const active = ref('');
const isOpen = ref(false); // only applies to mobile for now
function onToggle() {
isOpen.value = !isOpen.value;
}
function onClose() {
isOpen.value = false;
}
const activeGroup = ref('');
function onToggleGroup(group) {
activeGroup.value = activeGroup.value === group ? '' : group;
}
function onHashChange() {
active.value = window.location.hash.slice(2);
if (active.value.indexOf('email') === 0) activeGroup.value = 'email';
else activeGroup.value = '';
}
onMounted(() => {
window.addEventListener('hashchange', onHashChange);
onHashChange();
});
onUnmounted(() => {
window.removeEventListener('hashchange', onHashChange);
});
</script>
<template>
<div>
<div @click="onToggle()" class="sidebar-toggle-button"><i class="fa-solid fa-bars"></i></div>
<div class="sidebar" :class="{ 'open': isOpen }">
<a href="#/" class="sidebar-logo" @click="onClose()">
<img :src="`https://${config.adminFqdn}/api/v1/cloudron/avatar`" width="40" height="40"/> {{ config.cloudronName || 'Cloudron' }}
</a>
<div class="sidebar-list">
<a class="sidebar-item" :class="{ active: active === 'apps' }" href="#/apps" @click="onClose()"><i class="fa fa-grip fa-fw"></i> {{ $t('apps.title') }}</a>
<a class="sidebar-item" :class="{ active: active === 'appstore' }" v-show="profile.isAtLeastAdmin" href="#/appstore" @click="onClose()"><i class="fa fa-cloud-download-alt fa-fw"></i> {{ $t('appstore.title') }}</a>
<a class="sidebar-item" :class="{ active: active === 'users' }" v-show="profile.isAtLeastUserManager" href="#/users" @click="onClose()"><i class="fa fa-users fa-fw"></i> {{ $t('main.navbar.users') }}</a>
<a class="sidebar-item" :class="{ active: active === 'backups' }" v-show="profile.isAtLeastAdmin" href="#/backups" @click="onClose()"><i class="fa fa-archive fa-fw"></i> {{ $t('backups.title') }}</a>
<a class="sidebar-item" :class="{ active: active === 'branding' }" v-show="profile.isAtLeastAdmin" href="#/branding" @click="onClose()"><i class="fa fa-passport fa-fw"></i> {{ $t('branding.title') }}</a>
<a class="sidebar-item" :class="{ active: active === 'domains' }" v-show="profile.isAtLeastAdmin" href="#/domains" @click="onClose()"><i class="fa fa-globe fa-fw"></i> {{ $t('domains.title') }}</a>
<div class="sidebar-item actionable" v-show="profile.isAtLeastMailManager" @click="onToggleGroup('email')"><i class="fa fa-envelope fa-fw"></i> {{ $t('emails.title') }}</div>
<Transition name="sidebar-item-group-animation">
<div class="sidebar-item-group" v-if="activeGroup === 'email'">
<a class="sidebar-item" :class="{ active: active === 'emails-mailboxes' }" href="#/emails-mailboxes" @click="onClose()"><i class="fa fa-inbox fa-fw"></i> {{ $t('email.incoming.mailboxes.title') }}</a>
<a class="sidebar-item" :class="{ active: active === 'emails-mailinglists' }" href="#/emails-mailinglists" @click="onClose()"><i class="fa-solid fa-envelopes-bulk fa-fw"></i> {{ $t('email.incoming.mailinglists.title') }}</a>
<a class="sidebar-item" :class="{ active: active === 'email' }" href="#/email" @click="onClose()"><i class="fa fa-cog fa-fw"></i> {{ $t('emails.title') }} {{ $t('settings.title') }}</a>
</div>
</Transition>
<a class="sidebar-item" :class="{ active: active === 'eventlog' }" v-show="profile.isAtLeastAdmin" href="#/eventlog" @click="onClose()"><i class="fa fa-list-alt fa-fw"></i> {{ $t('eventlog.title') }}</a>
<a class="sidebar-item" :class="{ active: active === 'network' }" v-show="profile.isAtLeastAdmin" href="#/network" @click="onClose()"><i class="fas fa-network-wired fa-fw"></i> {{ $t('network.title') }}</a>
<a class="sidebar-item" :class="{ active: active === 'services' }" v-show="profile.isAtLeastAdmin" href="#/services" @click="onClose()"><i class="fa fa-cogs fa-fw"></i> {{ $t('services.title') }}</a>
<a class="sidebar-item" :class="{ active: active === 'settings' }" v-show="profile.isAtLeastAdmin" href="#/settings" @click="onClose()"><i class="fa fa-wrench fa-fw"></i> {{ $t('settings.title') }}</a>
<a class="sidebar-item" :class="{ active: active === 'user-directory' }" v-show="profile.isAtLeastAdmin" href="#/user-directory" @click="onClose()"><i class="fa fa-users-gear fa-fw"></i> {{ $t('users.title') }}</a>
<a class="sidebar-item" :class="{ active: active === 'volumes' }" v-show="profile.isAtLeastAdmin" href="#/volumes" @click="onClose()"><i class="fa fa-hdd fa-fw"></i> {{ $t('volumes.title') }}</a>
<a class="sidebar-item" :class="{ active: active === 'system' }" v-show="profile.isAtLeastAdmin" href="#/system" @click="onClose()"><i class="fa fa-chart-area fa-fw"></i> {{ $t('system.title') }}</a>
</div>
</div>
</div>
</template>
<style scoped>
.sidebar-toggle-button {
position: absolute;
left: 10px;
top: 10px;
}
.sidebar {
position: relative;
z-index: 1000;
transition: all 250ms ease;
min-width: 280px;
height: 100%;
white-space: nowrap !important;
overflow: hidden;
display: flex;
flex-direction: column;
background-color: var(--navbar-background);
border-right: 1px solid var(--pankow-color-background-hover);
padding: 22px 10px 10px 10px;
margin-right: 20px;
}
@media(max-width:767px) {
.sidebar {
margin-right: 0;
position: fixed;
top: 0;
left: 0;
width: 0;
min-width: 0;
padding: 22px 0 10px 0;
border-right: 0;
}
.sidebar.open {
width: 100%;
padding: 22px 10px 10px 10px;
}
}
.sidebar-logo img {
margin-right: 10px;
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: 10px;
}
.sidebar-list {
overflow: auto;
padding-top: 20px;
scrollbar-color: transparent transparent;
scrollbar-width: thin;
}
.sidebar-list:hover {
scrollbar-color: var(--color-neutral-border) transparent;
}
.sidebar-item {
display: block;
color: var(--pankow-text-color);
border-radius: 3px;
padding: 10px 15px;
}
.sidebar-item i {
opacity: 0.5;
margin-right: 10px;
}
.sidebar-item.active {
color: var(--pankow-color-primary);
text-decoration: none;
font-weight: bold;
}
.sidebar-item:hover {
background-color: #e9ecef;
text-decoration: none;
}
@media (prefers-color-scheme: dark) {
.sidebar-item:hover {
background-color: var(--card-background);
}
}
.sidebar-item.active i ,
.sidebar-item:hover i {
opacity: 1;
}
.sidebar-item-group {
padding-left: 20px;
height: auto;
overflow: hidden;
/* we need height to auto so we animate max-height. needs to be bigger than we need */
max-height: 300px;
}
.sidebar-item-group-animation-enter-active,
.sidebar-item-group-animation-leave-active {
transition: all 0.2s linear;
}
.sidebar-item-group-animation-leave-to,
.sidebar-item-group-animation-enter-from {
transform: translateX(-100px);
opacity: 0;
max-height: 0;
}
</style>