frontend: add collapsable sidebar
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
f8dacef309
commit
48b9e595ff
3 changed files with 218 additions and 2 deletions
|
@ -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");
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
181
frontend/src/components/Sidebar.vue
Normal file
181
frontend/src/components/Sidebar.vue
Normal 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>
|
|
@ -13,4 +13,34 @@ const app = createApp(App).use(BootstrapIconsPlugin);
|
|||
_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');
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue