frontend: add collapsable sidebar
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
j3d1 2024-03-24 06:44:38 +01:00
parent f8dacef309
commit 48b9e595ff
3 changed files with 218 additions and 2 deletions

View file

@ -1,5 +1,6 @@
<template>
<div class="wrapper">
<Sidebar/>
<div class="main">
<nav class="navbar navbar-expand navbar-light navbar-bg">
<a class="sidebar-toggle d-flex" @click="toggleSidebar">
@ -14,11 +15,13 @@
<script>
import Footer from "@/components/Footer.vue";
import Sidebar from "@/components/Sidebar.vue";
export default {
name: 'BaseLayout',
components: {
Footer
Footer,
Sidebar
},
props: {
hideSearch: {
@ -29,6 +32,8 @@ export default {
},
methods: {
toggleSidebar() {
closeAllDropdowns();
document.getElementById("sidebar").classList.toggle("collapsed");
},
},
}

View file

@ -0,0 +1,181 @@
<template>
<nav id="sidebar" class="sidebar">
<div class="sidebar-content">
<router-link to="/" class="sidebar-brand">
<img src="/src/assets/icons/toolshed-48x48.png" alt="Toolshed Logo" class="align-middle logo mr-2 h-75">
<span class="align-middle">Toolshed</span>
</router-link>
<ul class="sidebar-nav">
<li class="sidebar-header">
Tools & Components
</li>
</ul>
</div>
</nav>
</template>
<script>
import * as BIcons from "bootstrap-icons-vue";
export default {
name: "Sidebar",
components: {
...BIcons
},
}
</script>
<style scoped>
.sidebar {
min-width: 260px;
max-width: 260px;
direction: ltr;
}
.sidebar, .sidebar-content {
transition: margin-left .35s ease-in-out, left .35s ease-in-out, margin-right .35s ease-in-out, right .35s ease-in-out;
background: #222e3c;
}
.sidebar-content {
display: flex;
height: 100vh;
flex-direction: column;
}
.sidebar {
min-width: 260px;
max-width: 260px;
direction: ltr
}
.sidebar, .sidebar-content {
transition: margin-left .35s ease-in-out, left .35s ease-in-out, margin-right .35s ease-in-out, right .35s ease-in-out;
background: #222e3c
}
.sidebar-content {
display: flex;
height: 100vh;
flex-direction: column
}
.sidebar-nav {
padding-left: 0;
margin-bottom: 0;
list-style: none;
flex-grow: 1
}
.sidebar-link i, .sidebar-link svg, a.sidebar-link i, a.sidebar-link svg {
margin-right: .75rem;
color: rgba(233, 236, 239, .5)
}
.sidebar-item.active .sidebar-link:hover, .sidebar-item.active > .sidebar-link {
color: #e9ecef;
background: linear-gradient(90deg, rgba(59, 125, 221, .1), rgba(59, 125, 221, .0875) 50%, transparent);
border-left-color: #3b7ddd
}
.sidebar-item.active .sidebar-link:hover i, .sidebar-item.active .sidebar-link:hover svg, .sidebar-item.active > .sidebar-link i, .sidebar-item.active > .sidebar-link svg {
color: #e9ecef
}
.sidebar-dropdown .sidebar-link {
padding: .625rem 1.5rem .625rem 3.25rem;
font-weight: 400;
font-size: 90%;
border-left: 0;
color: #adb5bd;
background: transparent
}
.sidebar-dropdown .sidebar-link:before {
content: "→";
display: inline-block;
position: relative;
left: -14px;
transition: all .1s ease;
transform: translateX(0)
}
.sidebar-dropdown .sidebar-item .sidebar-link:hover {
font-weight: 400;
border-left: 0;
color: #e9ecef;
background: transparent
}
.sidebar-dropdown .sidebar-item .sidebar-link:hover:hover:before {
transform: translateX(4px)
}
.sidebar-dropdown .sidebar-item.active .sidebar-link {
font-weight: 400;
border-left: 0;
color: #518be1;
background: transparent
}
.sidebar [data-toggle=collapse] {
position: relative
}
.sidebar [data-toggle=collapse]:after {
content: " ";
border: solid;
border-width: 0 .075rem .075rem 0;
display: inline-block;
padding: 2px;
transform: rotate(45deg);
position: absolute;
top: 1.2rem;
right: 1.5rem;
transition: all .2s ease-out
}
.sidebar [aria-expanded=true]:after, .sidebar [data-toggle=collapse]:not(.collapsed):after {
transform: rotate(-135deg);
top: 1.4rem
}
.sidebar-brand {
font-weight: 600;
font-size: 1.15rem;
padding: 1.15rem 1.5rem;
display: block;
color: #f8f9fa
}
.sidebar-brand:hover {
text-decoration: none;
color: #f8f9fa
}
.sidebar-brand:focus {
outline: 0
}
.sidebar.collapsed {
margin-left: -260px
}
@media (min-width: 1px) and (max-width: 991.98px) {
.sidebar {
margin-left: -260px
}
.sidebar.collapsed {
margin-left: 0
}
}
.sidebar-header {
background: transparent;
padding: 1.5rem 1.5rem .375rem;
font-size: .75rem;
color: #ced4da
}
</style>

View file

@ -14,3 +14,33 @@ _nacl.instantiate((nacl) => {
window.nacl = nacl
app.use(router).mount('#app')
});
window.closeAllDropdowns = function () {
const dropdowns = document.getElementsByClassName("dropdown-menu");
let i;
for (i = 0; i < dropdowns.length; i++) {
const openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
window.onclick = function (event) {
if (!event.target.matches('.dropdown-toggle *')
&& !event.target.matches('.dropdown-toggle')
&& !event.target.matches('.dropdown-menu *')
&& !event.target.matches('.dropdown-menu')) {
closeAllDropdowns();
}
if (!event.target.matches('.sidebar-toggle *')
&& !event.target.matches('.sidebar-toggle')
&& !event.target.matches('.sidebar *')
&& !event.target.matches('.sidebar')) {
const sidebar = document.getElementById("sidebar");
const marginLeft = parseInt(getComputedStyle(sidebar).marginLeft);
if (sidebar.classList.contains('collapsed') && marginLeft === 0) {
sidebar.classList.remove('collapsed');
}
}
}