web/satellite/vuetify-poc: improve navigation drawer on small screens

This change improves the behaviour of the navigation drawer. It is now
able to automatically close on resize to smaller screen sizes and vice
versa, and also by close by clicking outside the drawer.

Issue: https://github.com/storj/storj/issues/6266

Change-Id: I1aee465a546abbf1369c48f6827b058523c5da21
This commit is contained in:
Wilfred Asomani 2023-09-15 14:51:35 +00:00
parent e4d6829971
commit 1a8913e7a0
6 changed files with 75 additions and 29 deletions

View File

@ -5,7 +5,7 @@
<v-app>
<session-wrapper>
<default-bar show-nav-drawer-button />
<account-nav v-if="appStore.state.isNavigationDrawerShown" />
<account-nav />
<default-view />
</session-wrapper>
</v-app>

View File

@ -2,11 +2,11 @@
// See LICENSE for copying information.
<template>
<v-navigation-drawer class="py-1">
<v-navigation-drawer v-model="model" class="py-1">
<v-sheet>
<v-list class="px-2" color="default" variant="flat">
<template v-if="pathBeforeAccountPage">
<v-list-item class="pa-4 rounded-lg" link router-link :to="pathBeforeAccountPage" @click="() => trackPageVisitEvent(pathBeforeAccountPage)">
<v-list-item class="pa-4 rounded-lg" link router-link :to="pathBeforeAccountPage" @click="() => registerLinkClick(pathBeforeAccountPage)">
<template #prepend>
<img src="@poc/assets/icon-back-tonal.svg" alt="Project">
<!-- <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -22,7 +22,7 @@
</template>
<!-- All Projects -->
<v-list-item class="pa-4 rounded-lg" link router-link to="/projects" @click="() => trackPageVisitEvent('/projects')">
<v-list-item class="pa-4 rounded-lg" link router-link to="/projects" @click="() => registerLinkClick('/projects')">
<template #prepend>
<!-- <img src="@poc/assets/icon-prosject.svg" alt="Project" class="mr-3"> -->
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -40,7 +40,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link router-link to="settings" class="my-1 py-3" rounded="lg" @click="() => trackPageVisitEvent('/settings')">
<v-list-item link router-link to="settings" class="my-1 py-3" rounded="lg" @click="() => registerLinkClick('/settings')">
<template #prepend>
<!-- <img src="@poc/assets/icon-settings.svg" alt="Account Settings" class="mr-3"> -->
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -52,7 +52,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link router-link to="billing" class="my-1" rounded="lg" @click="() => trackPageVisitEvent('/billing')">
<v-list-item link router-link to="billing" class="my-1" rounded="lg" @click="() => registerLinkClick('/billing')">
<template #prepend>
<!-- <img src="@poc/assets/icon-card.svg" alt="Billing" class="mr-3"> -->
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -71,7 +71,7 @@
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { computed, onBeforeMount } from 'vue';
import {
VNavigationDrawer,
VSheet,
@ -80,6 +80,7 @@ import {
VListItemTitle,
VDivider,
} from 'vuetify/components';
import { useDisplay } from 'vuetify';
import { useAppStore } from '@poc/store/appStore';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
@ -87,6 +88,13 @@ import { useAnalyticsStore } from '@/store/modules/analyticsStore';
const analyticsStore = useAnalyticsStore();
const appStore = useAppStore();
const { mdAndDown } = useDisplay();
const model = computed<boolean>({
get: () => appStore.state.isNavigationDrawerShown,
set: value => appStore.toggleNavigationDrawer(value),
});
/**
* Returns the path to the most recent non-account-related page.
*/
@ -96,10 +104,26 @@ const pathBeforeAccountPage = computed((): string | null => {
return path;
});
/**
* Conditionally closes the navigation drawer and tracks page visit.
*/
function registerLinkClick(page: string | null): void {
if (mdAndDown.value) {
model.value = false;
}
trackPageVisitEvent(page);
}
/**
* Sends "Page Visit" event to segment and opens link.
*/
function trackPageVisitEvent(page: string | null): void {
if (page) analyticsStore.pageVisit(page);
}
onBeforeMount(() => {
if (mdAndDown.value) {
model.value = false;
}
});
</script>

View File

@ -97,7 +97,7 @@
<v-divider class="my-2" />
<v-list-item link class="my-1 rounded-lg">
<v-list-item link class="my-1 rounded-lg" @click="closeSideNav">
<template #prepend>
<img src="@poc/assets/icon-upgrade.svg" alt="Upgrade">
</template>
@ -106,7 +106,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link class="my-1 rounded-lg" router-link to="/account/billing">
<v-list-item link class="my-1 rounded-lg" router-link to="/account/billing" @click="closeSideNav">
<template #prepend>
<img src="@poc/assets/icon-card.svg" alt="Billing">
</template>
@ -115,7 +115,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link class="my-1 rounded-lg" router-link to="/account/settings">
<v-list-item link class="my-1 rounded-lg" router-link to="/account/settings" @click="closeSideNav">
<template #prepend>
<img src="@poc/assets/icon-settings.svg" alt="Account Settings">
</template>
@ -222,6 +222,10 @@ watch(() => theme.global.current.value.dark, (newVal: boolean) => {
toggleTheme(localStorage.getItem('theme') || 'light');
activeTheme.value = theme.global.current.value.dark ? 1 : 0;
function closeSideNav(): void {
appStore.toggleNavigationDrawer(false);
}
/**
* Logs out user and navigates to login page.
*/

View File

@ -8,7 +8,7 @@
</div>
<session-wrapper v-else>
<default-bar show-nav-drawer-button />
<ProjectNav v-if="appStore.state.isNavigationDrawerShown" />
<ProjectNav />
<default-view />
</session-wrapper>
</v-app>
@ -86,10 +86,6 @@ watch(() => route.params.projectId, async newId => {
* Pre-fetches user`s and project information.
*/
onBeforeMount(async () => {
if (document.body.clientWidth < 1280) {
appStore.toggleNavigationDrawer(false);
}
isLoading.value = true;
try {

View File

@ -2,7 +2,7 @@
// See LICENSE for copying information.
<template>
<v-navigation-drawer class="py-1">
<v-navigation-drawer v-model="model" class="py-1">
<v-sheet>
<v-list class="px-2" color="default" variant="flat">
<!-- Project -->
@ -11,7 +11,7 @@
<!-- Project Menu -->
<v-list class="pa-2">
<!-- My Projects -->
<v-list-item rounded="lg" link router-link to="/projects" @click="() => trackPageVisitEvent('/projects')">
<v-list-item rounded="lg" link router-link to="/projects" @click="() => registerLinkClick('/projects')">
<template #prepend>
<!-- <img src="@poc/assets/icon-project.svg" alt="Projects"> -->
<IconProject />
@ -36,7 +36,7 @@
<v-divider class="my-2" />
<!-- Shared With Me -->
<v-list-item rounded="lg" link router-link to="/projects" @click="() => trackPageVisitEvent('/projects')">
<v-list-item rounded="lg" link router-link to="/projects" @click="() => registerLinkClick('/projects')">
<template #prepend>
<IconProject />
</template>
@ -69,7 +69,7 @@
<!-- <v-divider class="my-2"></v-divider> -->
<!-- View All Projects -->
<v-list-item link rounded="lg" router-link to="/projects" @click="() => trackPageVisitEvent('/projects')">
<v-list-item link rounded="lg" router-link to="/projects" @click="() => registerLinkClick('/projects')">
<template #prepend>
<IconAllProjects />
</template>
@ -117,7 +117,7 @@
<v-divider class="my-2" />
<v-list-item link router-link :to="`/projects/${selectedProject.id}/dashboard`" class="my-1 py-3" rounded="lg" @click="() => trackPageVisitEvent('/dashboard')">
<v-list-item link router-link :to="`/projects/${selectedProject.id}/dashboard`" class="my-1 py-3" rounded="lg" @click="() => registerLinkClick('/dashboard')">
<template #prepend>
<IconDashboard />
</template>
@ -126,7 +126,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link router-link :to="`/projects/${selectedProject.id}/buckets`" class="my-1" rounded="lg" @click="() => trackPageVisitEvent('/buckets')">
<v-list-item link router-link :to="`/projects/${selectedProject.id}/buckets`" class="my-1" rounded="lg" @click="() => registerLinkClick('/buckets')">
<template #prepend>
<IconBucket />
</template>
@ -135,7 +135,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link router-link :to="`/projects/${selectedProject.id}/bucket`" class="my-1" rounded="lg" @click="() => trackPageVisitEvent('/bucket')">
<v-list-item link router-link :to="`/projects/${selectedProject.id}/bucket`" class="my-1" rounded="lg" @click="() => registerLinkClick('/bucket')">
<template #prepend>
<IconBrowse />
</template>
@ -144,7 +144,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link router-link :to="`/projects/${selectedProject.id}/access`" class="my-1" rounded="lg" @click="() => trackPageVisitEvent('/access')">
<v-list-item link router-link :to="`/projects/${selectedProject.id}/access`" class="my-1" rounded="lg" @click="() => registerLinkClick('/access')">
<template #prepend>
<IconAccess />
</template>
@ -153,7 +153,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link router-link :to="`/projects/${selectedProject.id}/team`" class="my-1" rounded="lg" @click="() => trackPageVisitEvent('/team')">
<v-list-item link router-link :to="`/projects/${selectedProject.id}/team`" class="my-1" rounded="lg" @click="() => registerLinkClick('/team')">
<template #prepend>
<IconTeam />
</template>
@ -236,7 +236,7 @@
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import { computed, onBeforeMount, ref } from 'vue';
import {
VNavigationDrawer,
VSheet,
@ -248,10 +248,12 @@ import {
VChip,
VDivider,
} from 'vuetify/components';
import { useDisplay } from 'vuetify';
import { Project } from '@/types/projects';
import { useProjectsStore } from '@/store/modules/projectsStore';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
import { useAppStore } from '@poc/store/appStore';
import IconProject from '@poc/components/icons/IconProject.vue';
import IconSettings from '@poc/components/icons/IconSettings.vue';
@ -271,6 +273,14 @@ import CreateProjectDialog from '@poc/components/dialogs/CreateProjectDialog.vue
const analyticsStore = useAnalyticsStore();
const projectsStore = useProjectsStore();
const appStore = useAppStore();
const { mdAndDown } = useDisplay();
const model = computed<boolean>({
get: () => appStore.state.isNavigationDrawerShown,
set: value => appStore.toggleNavigationDrawer(value),
});
const isCreateProjectDialogShown = ref<boolean>(false);
@ -281,10 +291,26 @@ const selectedProject = computed((): Project => {
return projectsStore.state.selectedProject;
});
/**
* Conditionally closes the navigation drawer and tracks page visit.
*/
function registerLinkClick(page: string): void {
if (mdAndDown.value) {
model.value = false;
}
trackPageVisitEvent(page);
}
/**
* Sends "Page Visit" event to segment and opens link.
*/
function trackPageVisitEvent(page: string): void {
analyticsStore.pageVisit(page);
}
onBeforeMount(() => {
if (mdAndDown.value) {
model.value = false;
}
});
</script>

View File

@ -20,10 +20,6 @@ html {
--v-theme-overlay-multiplier: 0.75;
}
.v-navigation-drawer {
// box-shadow: 0 3px 4px rgba(var(--v-theme-on-surface), 0.05) !important;
transform: translateX(0) !important;
}
.v-app-bar.v-toolbar {
border-bottom: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
// box-shadow: 0 1px 3px rgba(var(--v-theme-on-surface), 0.05) !important;