Started to refactor dashboard.py with dashboard_new.py and trying really hard to figure out sqlalchemy lol

This commit is contained in:
Donald Zou
2024-01-09 00:25:47 -05:00
parent f671c992e1
commit 864f82ba11
12 changed files with 1310 additions and 66 deletions

View File

@@ -8,6 +8,6 @@
</head>
<body>
<div id="app" class="vw-100 vh-100"></div>
<!-- <script type="module" src="./src/main.js"></script> -->
<script type="module" src="./src/main.js"></script>
</body>
</html>

View File

@@ -0,0 +1,934 @@
body {
font-size: .875rem;
/*font-family: 'Poppins', sans-serif;*/
}
.codeFont{
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
.feather {
width: 16px;
height: 16px;
vertical-align: text-bottom;
}
.btn-primary {
font-weight: bold;
}
/*
* Sidebar
*/
/*.sidebar {*/
/* position: fixed;*/
/* top: 0;*/
/* bottom: 0;*/
/* left: 0;*/
/* z-index: 100;*/
/* !* Behind the navbar *!*/
/* padding: 48px 0 0;*/
/* !* Height of navbar *!*/
/* box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);*/
/*}*/
/*.sidebar-sticky {*/
/* position: relative;*/
/* top: 0;*/
/* height: calc(100vh - 48px);*/
/* padding-top: .5rem;*/
/* overflow-x: hidden;*/
/* overflow-y: auto;*/
/* !* Scrollable contents if viewport is shorter than content. *!*/
/*}*/
/*@supports ((position: -webkit-sticky) or (position: sticky)) {*/
/* .sidebar-sticky {*/
/* position: -webkit-sticky;*/
/* position: sticky;*/
/* }*/
/*}*/
.sidebar .nav-link, .bottomNavContainer .nav-link{
font-weight: 500;
color: #333;
transition: 0.2s cubic-bezier(0.82, -0.07, 0, 1.01);
}
.nav-link:hover {
padding-left: 30px;
background-color: #dfdfdf;
}
.sidebar .nav-link .feather {
margin-right: 4px;
color: #999;
}
.sidebar .nav-link.active, .bottomNavContainer .nav-link.active {
color: #007bff;
}
.sidebar .nav-link:hover .feather,
.sidebar .nav-link.active .feather {
color: inherit;
}
.sidebar-heading {
font-size: .75rem;
text-transform: uppercase;
}
/*
* Navbar
*/
.navbar-brand {
padding-top: .75rem;
padding-bottom: .75rem;
font-size: 1rem;
/*background-color: rgba(0, 0, 0, .25);*/
/*box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25);*/
}
.navbar .navbar-toggler {
top: .25rem;
right: 1rem;
}
.form-control {
transition: all 0.2s ease-in-out;
}
.form-control:disabled {
cursor: not-allowed;
}
.navbar .form-control {
padding: .75rem 1rem;
border-width: 0;
border-radius: 0;
}
.form-control-dark {
color: #fff;
background-color: rgba(255, 255, 255, .1);
border-color: rgba(255, 255, 255, .1);
}
.form-control-dark:focus {
border-color: transparent;
box-shadow: 0 0 0 3px rgba(255, 255, 255, .25);
}
.dot {
width: 10px;
height: 10px;
border-radius: 50px;
display: inline-block;
margin-left: auto !important;
}
.dot-running {
background-color: #28a745!important;
box-shadow: 0 0 0 0.2rem #28a74545;
}
.h6-dot-running {
margin-left: 0.3rem;
}
.dot-stopped {
background-color: #6c757d!important;
}
.card-running {
border-color: #28a745;
}
.info h6 {
line-break: anywhere;
transition: all 0.4s cubic-bezier(0.96, -0.07, 0.34, 1.01);
opacity: 1;
}
.info .row .col-sm {
display: flex;
flex-direction: column;
}
.info .row .col-sm small {
display: flex;
}
.info .row .col-sm small strong:last-child(1) {
margin-left: auto !important;
}
.btn-control {
border: none !important;
padding: 0;
margin: 0 1rem 0 0;
}
.btn-control:hover{
background-color: transparent !important;
}
.btn-control:active,
.btn-control:focus {
background-color: transparent !important;
border: none !important;
box-shadow: none;
}
.btn-qrcode-peer {
padding: 0 !important;
}
.btn-qrcode-peer:active,
.btn-qrcode-peer:hover {
transform: scale(0.9) rotate(180deg);
border: 0 !important;
}
.btn-download-peer:active,
.btn-download-peer:hover {
color: #17a2b8 !important;
transform: translateY(5px);
}
.share_peer_btn_group .btn-control {
margin: 0 0 0 1rem;
padding: 0 !important;
transition: all 0.4s cubic-bezier(1, -0.43, 0, 1.37);
}
.btn-control:hover {
background: white;
}
.btn-delete-peer:hover {
color: #dc3545;
}
.btn-lock-peer:hover {
color: #28a745;
}
.btn-lock-peer.lock{
color: #6c757d
}
.btn-lock-peer.lock:hover{
color: #6c757d
}
.btn-control.btn-outline-primary:hover{
color: #007bff
}
/* .btn-setting-peer:hover {
color: #007bff
} */
.btn-download-peer:hover {
color: #17a2b8;
}
.login-container {
padding: 2rem;
}
@media (max-width: 992px) {
.card-col {
margin-bottom: 1rem;
}
}
.switch {
font-size: 2rem;
}
.switch:hover {
text-decoration: none
}
.btn-group-label:hover {
color: #007bff;
border-color: #007bff;
background: white;
}
.peer_data_group {
text-align: right;
display: flex;
margin-bottom: 0.5rem
}
.peer_data_group p {
text-transform: uppercase;
margin-bottom: 0;
margin-right: 1rem
}
@media (max-width: 768px) {
.peer_data_group {
text-align: left;
}
}
.index-switch {
display: flex;
align-items: center;
justify-content: flex-end;
}
main {
margin-bottom: 3rem;
}
.peer_list {
margin-bottom: 7rem
}
@media (max-width: 768px) {
.add_btn {
bottom: 1.5rem !important;
}
.peer_list {
margin-bottom: 7rem !important;
}
}
.btn-manage-group {
z-index: 99;
position: fixed;
bottom: 3rem;
right: 2rem;
display: flex;
}
.btn-manage-group .setting_btn_menu {
position: absolute;
top: -124px;
background-color: white;
padding: 1rem 0;
right: 0;
box-shadow: 0 10px 20px rgb(0 0 0 / 19%), 0 6px 6px rgb(0 0 0 / 23%);
border-radius: 10px;
min-width: 250px;
display: none;
transform: translateY(-30px);
opacity: 0;
transition: all 0.3s cubic-bezier(0.58, 0.03, 0.05, 1.28);
}
.btn-manage-group .setting_btn_menu.show {
display: block;
}
.setting_btn_menu.showing {
transform: translateY(0px);
opacity: 1;
}
.setting_btn_menu a {
display: flex;
padding: 0.5rem 1rem;
transition: all 0.1s ease-in-out;
font-size: 1rem;
align-items: center;
cursor: pointer;
}
.setting_btn_menu a:hover {
background-color: #efefef;
text-decoration: none;
}
.setting_btn_menu a i {
margin-right: auto !important;
}
.add_btn {
height: 54px;
z-index: 99;
border-radius: 100px !important;
padding: 0 14px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
margin-right: 1rem;
font-size: 1.5rem;
}
.setting_btn {
height: 54px;
z-index: 99;
border-radius: 100px !important;
padding: 0 14px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
font-size: 1.5rem;
}
@-webkit-keyframes rotating
/* Safari and Chrome */
{
from {
-webkit-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes rotating {
from {
-ms-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-ms-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-webkit-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.rotating::before {
-webkit-animation: rotating 0.75s linear infinite;
-moz-animation: rotating 0.75s linear infinite;
-ms-animation: rotating 0.75s linear infinite;
-o-animation: rotating 0.75s linear infinite;
animation: rotating 0.75s linear infinite;
}
.peer_private_key_textbox_switch {
position: absolute;
right: 2rem;
transform: translateY(-28px);
font-size: 1.2rem;
cursor: pointer;
}
#peer_private_key_textbox,
#private_key,
#public_key,
#peer_preshared_key_textbox {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
.progress-bar {
transition: 0.3s ease-in-out;
}
.key {
transition: 0.2s ease-in-out;
cursor: pointer;
}
.key:hover {
color: #007bff;
}
.card {
border-radius: 10px;
}
.peer_list .card .button-group {
height: 22px;
}
.form-control {
border-radius: 10px;
}
.btn {
border-radius: 8px;
/*padding: 0.6rem 0.9em;*/
}
.login-box #username,
.login-box #password {
padding: 0.6rem calc( 0.9rem + 32px);
height: inherit;
}
.login-box label[for="username"],
.login-box label[for="password"] {
font-size: 1rem;
margin: 0 !important;
transform: translateY(2.1rem) translateX(1rem);
padding: 0;
}
/*label[for="password"]{*/
/* transform: translateY(32px) translateX(16px);*/
/*}*/
.modal-content {
border-radius: 10px;
}
.tooltip-inner {
font-size: 0.8rem;
}
@-webkit-keyframes loading {
0% {
background-color: #dfdfdf;
}
50% {
background-color: #adadad;
}
100% {
background-color: #dfdfdf;
}
}
@-moz-keyframes loading {
0% {
background-color: #dfdfdf;
}
50% {
background-color: #adadad;
}
100% {
background-color: #dfdfdf;
}
}
.conf_card {
transition: 0.2s ease-in-out;
}
.conf_card:hover {
border-color: #007bff;
cursor: pointer;
}
.info_loading {
/* animation: loading 2s infinite ease-in-out;
/* border-radius: 5px; */
height: 19.19px;
/* transition: 0.3s ease-in-out; */
/* transform: translateX(40px); */
opacity: 0 !important;
}
#conf_status_btn {
transition: 0.2s ease-in-out;
}
#conf_status_btn.info_loading {
height: 38px;
border-radius: 5px;
animation: loading 3s infinite ease-in-out;
}
#qrcode_img img {
width: 100%;
}
#selected_ip_list .badge,
#selected_peer_list .badge {
margin: 0.1rem
}
#add_modal.ip_modal_open {
transition: filter 0.2s ease-in-out;
filter: brightness(0.5);
}
#delete_bulk_modal .list-group a.active {
background-color: #dc3545;
border-color: #dc3545;
}
#selected_peer_list {
max-height: 80px;
overflow-y: scroll;
overflow-x: hidden;
}
.no-response {
width: 100%;
height: 100%;
position: fixed;
background: #000000ba;
z-index: 10000;
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
opacity: 0;
transition: all 1s ease-in-out;
}
.no-response.active {
display: flex;
}
.no-response.active.show {
opacity: 100;
}
.no-response .container>* {
text-align: center;
}
.no-responding {
transition: all 1s ease-in-out;
filter: blur(10px);
}
pre.index-alert {
margin-bottom: 0;
padding: 1rem;
background-color: #343a40;
border: 1px solid rgba(0, 0, 0, .125);
border-radius: .25rem;
margin-top: 1rem;
color: white;
}
.peerNameCol {
display: flex;
align-items: center;
margin-bottom: 0.2rem
}
.peerName {
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.peerLightContainer {
text-transform: uppercase;
margin: 0;
margin-left: auto !important;
}
.conf_card .dot,
.info .dot {
transform: translateX(10px);
}
#config_body {
transition: 0.3s ease-in-out;
}
#config_body.firstLoading {
opacity: 0.2;
}
.chartTitle {
display: flex;
}
.chartControl {
margin-bottom: 1rem;
display: flex;
align-items: center;
}
.chartTitle h6 {
margin-bottom: 0;
line-height: 1;
margin-right: 0.5rem;
}
.chartContainer.fullScreen {
position: fixed;
z-index: 9999;
background-color: white;
top: 0;
left: 0;
width: calc( 100% + 15px);
height: 100%;
padding: 32px;
}
.chartContainer.fullScreen .col-sm {
padding-right: 0;
height: 100%;
}
.chartContainer.fullScreen .chartCanvasContainer {
width: 100%;
height: calc( 100% - 47px) !important;
max-height: calc( 100% - 47px) !important;
}
#switch{
transition: all 200ms ease-in;
}
.toggle--switch{
display: none;
}
.toggleLabel{
width: 64px;
height: 32px;
background-color: #6c757d17;
display: flex;
position: relative;
border: 2px solid #6c757d8c;
border-radius: 100px;
transition: all 200ms ease-in;
cursor: pointer;
margin: 0;
}
.toggle--switch.waiting + .toggleLabel{
opacity: 0.5;
}
.toggleLabel::before{
background-color: #6c757d;
height: 26px;
width: 26px;
content: "";
border-radius: 100px;
margin: 1px;
position: absolute;
animation-name: off;
animation-duration: 350ms;
animation-fill-mode: forwards;
transition: all 200ms ease-in;
cursor: pointer;
}
.toggleLabel:hover::before{
filter: brightness(1.2);
}
.toggle--switch:checked + .toggleLabel{
background-color: #007bff17 !important;
border: 2px solid #007bff8c;
}
.toggle--switch:checked + .toggleLabel::before{
background-color: #007bff;
animation-name: on;
animation-duration: 350ms;
animation-fill-mode: forwards;
}
@keyframes on {
0%{
left: 0px;
}
60%{
left: 0px;
width: 40px;
}
100%{
left: 32px;
width: 26px;
}
}
@keyframes off {
0%{
left: 32px;
}
60%{
left: 18px;
width: 40px;
}
100%{
left: 0px;
width: 26px;
}
}
.toastContainer{
z-index: 99999 !important;
}
.toast{
min-width: 300px;
background-color: rgba(255,255,255,1);
z-index: 99999;
}
.toast-header{
background-color: rgba(255,255,255);
}
.toast-progressbar{
width: 100%;
height: 4px;
background-color: #007bff;
border-bottom-left-radius: .25rem;
}
.addConfigurationAvailableIPs{
margin-bottom: 0;
}
.input-feedback{
display: none;
}
#addConfigurationModal label{
display: flex;
width: 100%;
align-items: center;
}
#addConfigurationModal label a{
margin-left: auto !important;
}
#reGeneratePrivateKey{
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
.addConfigurationToggleStatus.waiting{
opacity: 0.5;
}
/*.conf_card .card-body .row .card-col{*/
/* margin-bottom: 0.5rem;*/
/*}*/
.peerDataUsageChartContainer{
min-height: 50vh;
width: 100%;
}
.peerDataUsageChartControl{
display: block !important;
margin: 0;
}
.peerDataUsageChartControl .switchUnit{
width: 33.3%;
}
.peerDataUsageChartControl .switchTimePeriod{
width: 25%;
}
@media (min-width: 1200px){
#peerDataUsage .modal-xl {
max-width: 95vw;
}
}
.bottom{
display: none;
}
@media (max-width: 768px){
.bottom{
display: block;
}
.btn-manage-group{
bottom: calc( 3rem + 40px + env(safe-area-inset-bottom, 5px));
}
main{
padding-bottom: calc( 3rem + 40px + env(safe-area-inset-bottom, 5px));
}
}
.bottomNavContainer{
display: flex;
color: #333;
padding-bottom: env(safe-area-inset-bottom, 5px);
box-shadow: inset 0 1px 0 rgb(0 0 0 / 10%);
}
.bottomNavButton{
width: 25vw;
display: flex;
flex-direction: column;
align-items: center;
margin: 0.7rem 0;
color: rgba(51, 51, 51, 0.5);
cursor: pointer;
transition: all ease-in 0.2s;
}
.bottomNavButton.active{
color: #333;
}
.bottomNavButton i{
font-size: 1.2rem;
}
.bottomNavButton .subNav{
width: 100vw;
position: absolute;
z-index: 10000;
bottom: 0;
left: 0;
background-color: #272b30;
display: none;
animation-duration: 400ms;
padding-bottom: env(safe-area-inset-bottom, 5px);
}
.bottomNavButton .subNav.active{
display: block;
}
.bottomNavButton .subNav .nav .nav-item .nav-link{
padding: 0.7rem 1rem;
}
.bottomNavWrapper{
height: 100%;
width: 100%;
background-color: #000000a1;
position: fixed;
z-index: 1030;
display: none;
left: 0;
}
.bottomNavWrapper.active{
display: block;
}
.sb-update-url .dot-running{
transform: translateX(10px);
}
.list-group-item{
transition: all 0.1s ease-in;
}
.theme-switch-btn{
width: 100%;
}

View File

@@ -1,9 +1,10 @@
<script setup>
import { RouterView } from 'vue-router'
</script>
<template>
<nav class="navbar bg-dark fixed-top" data-bs-theme="dark">
<nav class="navbar bg-dark sticky-top" data-bs-theme="dark">
<div class="container-fluid">
<span class="navbar-brand mb-0 h1">WGDashboard</span>
</div>

View File

@@ -0,0 +1,43 @@
<script>
export default {
name: "navbar"
}
</script>
<template>
<nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-light sidebar border border-right p-0">
<div class="sidebar-sticky pt-3">
<ul class="nav flex-column">
<li class="nav-item">
<RouterLink class="nav-link" to="/">Home</RouterLink></li>
<li class="nav-item">
<RouterLink class="nav-link" to="/settings">Settings</RouterLink></li>
</ul>
<hr>
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Configurations</span>
</h6>
<ul class="nav flex-column">
</ul>
<hr>
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Tools</span>
</h6>
<ul class="nav flex-column">
<ul class="nav flex-column">
<li class="nav-item"><a class="nav-link" data-toggle="modal" data-target="#ping_modal" href="#">Ping</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="modal" data-target="#traceroute_modal" href="#">Traceroute</a></li>
</ul>
</ul>
<hr>
<ul class="nav flex-column">
<li class="nav-item"><a href="https://github.com/donaldzou/WGDashboard/releases/tag/"><small class="nav-link text-muted"></small></a></li>
</ul>
</div>
</nav>
</template>
<style scoped>
</style>

View File

@@ -2,6 +2,7 @@ import { createRouter, createWebHashHistory } from 'vue-router'
import {cookie} from "../utilities/cookie.js";
import Index from "@/views/index.vue"
import Signin from "@/views/signin.vue";
import ConfigurationList from "@/views/configurationList.vue";
const router = createRouter({
history: createWebHashHistory(),
@@ -11,7 +12,13 @@ const router = createRouter({
component: Index,
meta: {
requiresAuth: true
}
},
children: [
{
path: '',
component: ConfigurationList
}
]
},
{
path: '/signin', component: Signin
@@ -21,7 +28,7 @@ const router = createRouter({
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth){
if (cookie.getCookie("auth")){
if (cookie.getCookie("authToken")){
next()
}else{
next("/signin")
@@ -30,5 +37,4 @@ router.beforeEach((to, from, next) => {
next();
}
});
export default router

View File

@@ -0,0 +1,13 @@
<script>
export default {
name: "configurationList"
}
</script>
<template>
</template>
<style scoped>
</style>

View File

@@ -1,11 +1,21 @@
<script>
import Navbar from "@/components/navbar.vue";
export default {
name: "index"
name: "index",
components: {Navbar}
}
</script>
<template>
<div class="container-fluid flex-grow-1">
<div class="row h-100">
<Navbar></Navbar>
<main class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mb-4">
<RouterView></RouterView>
</main>
</div>
</div>
</template>
<style scoped>

View File

@@ -6,17 +6,29 @@ export default {
data(){
return {
username: "",
password: ""
password: "",
loginError: false,
loginErrorMessage: ""
}
},
methods: {
async auth(){
if (this.username && this.password){
await fetchPost("/auth", {
await fetchPost("/api/authenticate", {
username: this.username,
password: this.password
}, (response) => {
console.log(response)
if (response.status){
this.loginError = false;
this.$router.push('/')
}else{
this.loginError = true;
this.loginErrorMessage = response.message;
document.querySelectorAll("input[required]").forEach(x => {
x.classList.remove("is-valid")
x.classList.add("is-invalid")
});
}
})
}else{
document.querySelectorAll("input[required]").forEach(x => {
@@ -27,7 +39,7 @@ export default {
x.classList.remove("is-invalid")
x.classList.add("is-valid")
}
})
});
}
}
}
@@ -37,19 +49,24 @@ export default {
<template>
<div class="container-fluid login-container-fluid h-100 d-flex">
<div class="login-box m-auto" style="width: 500px;">
<h1 class="text-center">Sign in</h1>
<h5 class="text-center">to WGDashboard</h5>
<h5 class="text-center">Welcome to</h5>
<h1 class="text-center">WGDashboard</h1>
<div class="m-auto">
<div class="alert alert-danger d-none" role="alert" style="margin-top: 1rem; margin-bottom: 0rem;"></div>
<div class="form-group">
<label for="username" class="text-left" style="font-size: 1rem"><i class="bi bi-person-circle"></i></label>
<input type="text" v-model="username" class="form-control" id="username" name="username" placeholder="Username" required>
<div class="alert alert-danger mt-2 mb-0" role="alert" v-if="loginError">
{{this.loginErrorMessage}}
</div>
<div class="form-group">
<label for="password" class="text-left" style="font-size: 1rem"><i class="bi bi-key-fill"></i></label>
<input type="password" v-model="password" class="form-control" id="password" name="password" placeholder="Password" required>
</div>
<button class="btn btn-dark w-100 mt-4" @click="this.auth()">Sign In</button>
<form @submit="(e) => {e.preventDefault(); this.auth();}">
<div class="form-group">
<label for="username" class="text-left" style="font-size: 1rem"><i class="bi bi-person-circle"></i></label>
<input type="text" v-model="username" class="form-control" id="username" name="username" placeholder="Username" required>
</div>
<div class="form-group">
<label for="password" class="text-left" style="font-size: 1rem"><i class="bi bi-key-fill"></i></label>
<input type="password" v-model="password" class="form-control" id="password" name="password" placeholder="Password" required>
</div>
<button class="btn btn-dark ms-auto mt-4 w-100 d-flex">
Sign In<i class="ms-auto bi bi-chevron-right"></i></button>
</form>
</div>
</div>
</div>

View File

@@ -15,7 +15,7 @@ export default defineConfig({
},
server:{
proxy: {
'/': 'http://178.128.231.4:10086/'
'/api': 'http://178.128.231.4:10086/'
}
}
})

View File

@@ -1,8 +1,10 @@
body {
font-size: .875rem;
/*font-family: 'Poppins', sans-serif;*/
#app{
display: flex;
flex-direction: column;
}
.codeFont{
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
@@ -21,34 +23,34 @@ body {
* Sidebar
*/
.sidebar {
position: fixed;
top: 0;
bottom: 0;
left: 0;
z-index: 100;
/* Behind the navbar */
padding: 48px 0 0;
/* Height of navbar */
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
}
/*.sidebar {*/
/* position: fixed;*/
/* top: 0;*/
/* bottom: 0;*/
/* left: 0;*/
/* z-index: 100;*/
/* !* Behind the navbar *!*/
/* padding: 48px 0 0;*/
/* !* Height of navbar *!*/
/* box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);*/
/*}*/
.sidebar-sticky {
position: relative;
top: 0;
height: calc(100vh - 48px);
padding-top: .5rem;
overflow-x: hidden;
overflow-y: auto;
/* Scrollable contents if viewport is shorter than content. */
}
/*.sidebar-sticky {*/
/* position: relative;*/
/* top: 0;*/
/* height: calc(100vh - 48px);*/
/* padding-top: .5rem;*/
/* overflow-x: hidden;*/
/* overflow-y: auto;*/
/* !* Scrollable contents if viewport is shorter than content. *!*/
/*}*/
@supports ((position: -webkit-sticky) or (position: sticky)) {
.sidebar-sticky {
position: -webkit-sticky;
position: sticky;
}
}
/*@supports ((position: -webkit-sticky) or (position: sticky)) {*/
/* .sidebar-sticky {*/
/* position: -webkit-sticky;*/
/* position: sticky;*/
/* }*/
/*}*/
.sidebar .nav-link, .bottomNavContainer .nav-link{
font-weight: 500;