Reworked layout for mobile supoort

This commit is contained in:
adroslice 2023-03-12 20:15:38 +01:00
parent db147d842c
commit 9143d5a68f
2 changed files with 73 additions and 22 deletions

View file

@ -1,10 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { authenticate, logout, checkAuthentication, setup } from "./api";
// Icons
import IDashboard from '~icons/ri/dashboard-2-line'; import IDashboard from '~icons/ri/dashboard-2-line';
import IRule from '~icons/material-symbols/rule-folder-outline-sharp'; import IRule from '~icons/material-symbols/rule-folder-outline-sharp';
import IAddress from '~icons/eos-icons/ip'; import IAddress from '~icons/eos-icons/ip';
import { authenticate, logout, checkAuthentication, setup } from "./api";
enum NavState { Open, Reduced, Collapsed }; enum NavState { Open, Reduced, Collapsed };
const NavStateCount = 3; const NavStateCount = 3;
let navState = $ref(NavState.Open); let navState = $ref(NavState.Open);
@ -21,6 +22,23 @@ let loginDisabled = $ref(true);
let username = $ref(""); let username = $ref("");
let password = $ref(""); let password = $ref("");
const mobileMedia = window.matchMedia("only screen and (max-width: 768px)");
if (mobileMedia.matches) {
navState = NavState.Collapsed;
}
function collapseNavIfMobile() {
if (mobileMedia.matches && navState === NavState.Open) {
// Give new page time to find initial left before transitioning
setTimeout(() => navState = NavState.Collapsed, 0);
}
}
function toggleNavState() {
navState = (navState + 1) % NavStateCount;
if (mobileMedia.matches && navState === NavState.Reduced)
navState++;
}
async function tryLogin() { async function tryLogin() {
loginDisabled = true; loginDisabled = true;
@ -29,7 +47,8 @@ async function tryLogin() {
loginDisabled = false; loginDisabled = false;
if (res.error != null) { if (res.error != null) {
console.info("authentication error"); console.info("authentication error");
} else { }
else {
// TODO Check for MFA here // TODO Check for MFA here
authState = AuthState.Authenticated; authState = AuthState.Authenticated;
} }
@ -78,15 +97,16 @@ onMounted(async() => {
'nav-state-collapsed': navState === NavState.Collapsed, 'nav-state-collapsed': navState === NavState.Collapsed,
'nav-state-reduced': navState === NavState.Reduced, 'nav-state-reduced': navState === NavState.Reduced,
}"> }">
<button class="nav-head" @click="() => navState = (navState + 1) % NavStateCount"> <button class="nav-head" @click="toggleNavState">
nfSense <i-mdi-hamburger-menu/>
<h1>nfSense</h1>
</button> </button>
<Portal from="page-header" class="page-header pad gap"/> <Portal from="page-header" class="page-header pad gap"/>
<div class="nav-body"> <div class="nav-body">
<template v-for="(options, route) in navRoutes" :key="route"> <template v-for="(options, route) in navRoutes" :key="route">
<router-link :to="route" class="button"> <router-link :to="route" class="button" @click="collapseNavIfMobile">
<component :is="options.icon"/> <component :is="options.icon"/>
{{ options.caption }} {{ options.caption }}
</router-link> </router-link>
@ -134,36 +154,37 @@ onMounted(async() => {
.layout { .layout {
grid-template-rows: auto 1fr; grid-template-rows: auto 1fr;
grid-template-columns: auto 1fr; grid-template-columns: auto 1fr;
grid-template-areas:
"NH PH"
"NB PC";
} }
.login { place-items: center; } .login { place-items: center; }
.nav-head { grid-area: NH; }
.nav-body { grid-area: NB; }
.page-header { grid-area: PH; }
.page-content { grid-area: PC; }
/* Navigation */ /* Navigation */
.nav-head, .nav-body { background: var(--cl-bg-low); } .nav-head, .nav-body { background: var(--cl-bg-low); }
.nav-head {
font-size: 2rem; .nav-head { font-weight: bold; }
font-weight: bold; .nav-head > svg { display: none; }
} .nav-head > h1 { flex-grow: 1; }
.nav-body .button { justify-content: left; } .nav-body .button { justify-content: left; }
.nav-body .flex-row * { flex: 1; } .nav-body .flex-row * { flex: 1; }
/* Page */ /* Page */
.page-header { .page-header {
grid-row: 1;
grid-column: 2;
flex-flow: row nowrap; flex-flow: row nowrap;
align-items: center; align-items: center;
} }
.page-header button svg { .page-header button svg { margin: -0.25rem; }
margin: -0.25rem; .page-content { background: var(--cl-bg); }
}
.page-content {
grid-row: 2;
grid-column: 2;
background: var(--cl-bg);
}
/* Nav-Body-Collapsing */ /* Nav-Body-Collapsing */
.nav-body, .page-content { .nav-body, .page-header, .page-content {
position: relative; position: relative;
left: 0%; left: 0%;
width: 100%; width: 100%;
@ -184,4 +205,34 @@ onMounted(async() => {
flex-direction: column; flex-direction: column;
align-items: start; align-items: start;
} }
/* Mobile Layout */
@media only screen and (max-width: 768px) {
.layout {
grid-template-columns: auto 1fr;
grid-template-rows: auto auto 1fr;
grid-template-areas:
"NH NH"
"NB PH"
"NB PC";
}
.nav-head > svg {
display: initial;
}
.nav-state-collapsed .page-header {
left: calc(-100vw + 100%);
width: calc(0% + 100vw);
}
.nav-state-reduced .page-header {
left: calc(calc(-100vw + 100%) + var(--reduced-width));
width: calc(calc(0% + 100vw) - var(--reduced-width));
}
.nav-state-open .nav-body { width: calc(0% + 100vw); }
.nav-state-open .page-content,
.nav-state-open .page-header {
left: 100%;
}
}
</style> </style>

View file

@ -1,5 +1,5 @@
.fade-enter-active, .fade-leave-active { .fade-enter-active, .fade-leave-active {
transition: opacity 0.2s ease-out !important; transition: all 0.2s ease-out !important;
} }
.fade-enter-from, .fade-leave-to { .fade-enter-from, .fade-leave-to {
opacity: 0; opacity: 0;