improved mobile navbar/sidebar (#574)

* improved mobile navbar/sidebar

Sidebar is hidden and all menu items moved to hamburger menu on mobile devices

* improvements to menu rendering

-removed redundant code
-fixed an issue with emitting data to App.vue

* Update Navigation.vue

fixed linting errors

* Add minor refactors to the mobile menu PR.

- Fix indentation and line lengths.
- Simplify prop definitions in the Navigation component.
- Remove redundant computed methods and use prop variables directly in
  the Navigation compontent.
- Simplify menu rendering logic by:
  removing isSidebar, showLogout and using simpler v-if / else
  in the parent instead of the Navigation component.

* Update App.vue

removed orphaned isSideBar Boolean

Co-authored-by: Kailash Nadh <kailash@nadh.in>
This commit is contained in:
SweetPPro 2021-11-09 19:56:34 +01:00 committed by GitHub
parent 125d51f7bf
commit 7b9ba2efbc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 170 additions and 108 deletions

42
frontend/fontello/config.json Normal file → Executable file
View file

@ -552,6 +552,20 @@
"speedometer"
]
},
{
"uid": "86efd4d8903ab613b84953efcef01406",
"css": "logout-variant",
"code": 984573,
"src": "custom_icons",
"selected": true,
"svg": {
"path": "M585.9 650.4L695.3 541H291V459H695.3L585.9 349.6 646.5 291 853.5 500 646.5 709ZM791 125Q826.2 125 850.6 149.4T875 209V402.3L791 320.3V209H209V791H791V679.7L875 597.7V791Q875 826.2 850.6 850.6T791 875H209Q173.8 875 149.4 850.6T125 791V209Q125 173.8 149.4 149.4T209 125H791Z",
"width": 1000
},
"search": [
"logout-variant"
]
},
{
"uid": "f4ad3f6d071a0bfb3a8452b514ed0892",
"css": "vector-square",
@ -21790,20 +21804,6 @@
"lock-plus"
]
},
{
"uid": "86efd4d8903ab613b84953efcef01406",
"css": "logout-variant",
"code": 984573,
"src": "custom_icons",
"selected": false,
"svg": {
"path": "M585.9 650.4L695.3 541H291V459H695.3L585.9 349.6 646.5 291 853.5 500 646.5 709ZM791 125Q826.2 125 850.6 149.4T875 209V402.3L791 320.3V209H209V791H791V679.7L875 597.7V791Q875 826.2 850.6 850.6T791 875H209Q173.8 875 149.4 850.6T125 791V209Q125 173.8 149.4 149.4T209 125H791Z",
"width": 1000
},
"search": [
"logout-variant"
]
},
{
"uid": "90e8ca4d57b7f017c8a63b1dc2917046",
"css": "music-note-bluetooth",
@ -74835,6 +74835,20 @@
"search": [
"set-split"
]
},
{
"uid": "b39a043bdb10d9d11ccecca6f17a07fe",
"css": "logout-variant",
"code": 64737,
"src": "custom_icons",
"selected": false,
"svg": {
"path": "M586.7 649.6L694.6 541.7H291.7V458.3H694.6L586.7 350.4 645.8 291.7 854.2 500 645.8 708.3 586.7 649.6M791.7 125C837.5 125 875 162.5 875 208.3V402.9L791.7 319.6V208.3H208.3V791.7H791.7V680.4L875 597.1V791.7C875 837.5 837.5 875 791.7 875H208.3C162.1 875 125 837.5 125 791.7V208.3C125 162.1 162.1 125 208.3 125H791.7Z",
"width": 1000
},
"search": [
"logout-variant"
]
}
]
}

View file

@ -10,9 +10,11 @@
</div>
</template>
<template slot="end">
<b-navbar-item tag="div">
<a href="#" @click.prevent="doLogout">{{ $t('users.logout') }}</a>
</b-navbar-item>
<navigation v-if="isMobile" :isMobile="isMobile"
:activeItem="activeItem" :activeGroup="activeGroup" @toggleGroup="toggleGroup" />
<b-navbar-item v-else tag="div">
<a href="#" @click.prevent="doLogout">{{ $t('users.logout') }}</a>
</b-navbar-item>
</template>
</b-navbar>
@ -20,88 +22,15 @@
<section class="sidebar">
<b-sidebar
position="static"
mobile="reduce"
mobile="hide"
:fullheight="true"
:open="true"
:can-cancel="false"
>
<div>
<b-menu :accordion="false">
<b-menu-list>
<b-menu-item :to="{name: 'dashboard'}" tag="router-link"
:active="activeItem.dashboard"
icon="view-dashboard-variant-outline" :label="$t('menu.dashboard')">
</b-menu-item><!-- dashboard -->
<b-menu-item :expanded="activeGroup.lists"
:active="activeGroup.lists" data-cy="lists"
v-on:update:active="(state) => toggleGroup('lists', state)"
icon="format-list-bulleted-square" :label="$t('globals.terms.lists')">
<b-menu-item :to="{name: 'lists'}" tag="router-link"
:active="activeItem.lists" data-cy="all-lists"
icon="format-list-bulleted-square" :label="$t('menu.allLists')"></b-menu-item>
<b-menu-item :to="{name: 'forms'}" tag="router-link"
:active="activeItem.forms" class="forms"
icon="newspaper-variant-outline" :label="$t('menu.forms')"></b-menu-item>
</b-menu-item><!-- lists -->
<b-menu-item :expanded="activeGroup.subscribers"
:active="activeGroup.subscribers" data-cy="subscribers"
v-on:update:active="(state) => toggleGroup('subscribers', state)"
icon="account-multiple" :label="$t('globals.terms.subscribers')">
<b-menu-item :to="{name: 'subscribers'}" tag="router-link"
:active="activeItem.subscribers" data-cy="all-subscribers"
icon="account-multiple" :label="$t('menu.allSubscribers')"></b-menu-item>
<b-menu-item :to="{name: 'import'}" tag="router-link"
:active="activeItem.import" data-cy="import"
icon="file-upload-outline" :label="$t('menu.import')"></b-menu-item>
<b-menu-item :to="{name: 'bounces'}" tag="router-link"
:active="activeItem.bounces" data-cy="bounces"
icon="email-bounce" :label="$t('globals.terms.bounces')"></b-menu-item>
</b-menu-item><!-- subscribers -->
<b-menu-item :expanded="activeGroup.campaigns"
:active="activeGroup.campaigns" data-cy="campaigns"
v-on:update:active="(state) => toggleGroup('campaigns', state)"
icon="rocket-launch-outline" :label="$t('globals.terms.campaigns')">
<b-menu-item :to="{name: 'campaigns'}" tag="router-link"
:active="activeItem.campaigns" data-cy="all-campaigns"
icon="rocket-launch-outline" :label="$t('menu.allCampaigns')"></b-menu-item>
<b-menu-item :to="{name: 'campaign', params: {id: 'new'}}" tag="router-link"
:active="activeItem.campaign" data-cy="new-campaign"
icon="plus" :label="$t('menu.newCampaign')"></b-menu-item>
<b-menu-item :to="{name: 'media'}" tag="router-link"
:active="activeItem.media" data-cy="media"
icon="image-outline" :label="$t('menu.media')"></b-menu-item>
<b-menu-item :to="{name: 'templates'}" tag="router-link"
:active="activeItem.templates" data-cy="templates"
icon="file-image-outline" :label="$t('globals.terms.templates')"></b-menu-item>
<b-menu-item :to="{name: 'campaignAnalytics'}" tag="router-link"
:active="activeItem.campaignAnalytics" data-cy="analytics"
icon="chart-bar" :label="$t('globals.terms.analytics')"></b-menu-item>
</b-menu-item><!-- campaigns -->
<b-menu-item :expanded="activeGroup.settings"
:active="activeGroup.settings" data-cy="settings"
v-on:update:active="(state) => toggleGroup('settings', state)"
icon="cog-outline" :label="$t('menu.settings')">
<b-menu-item :to="{name: 'settings'}" tag="router-link"
:active="activeItem.settings" data-cy="all-settings"
icon="cog-outline" :label="$t('menu.settings')"></b-menu-item>
<b-menu-item :to="{name: 'logs'}" tag="router-link"
:active="activeItem.logs" data-cy="logs"
icon="newspaper-variant-outline" :label="$t('menu.logs')"></b-menu-item>
</b-menu-item><!-- settings -->
</b-menu-list>
<navigation v-if="!isMobile" :isMobile="isMobile"
:activeItem="activeItem" :activeGroup="activeGroup" @toggleGroup="toggleGroup" />
</b-menu>
</div>
</b-sidebar>
@ -136,15 +65,22 @@
<script>
import Vue from 'vue';
import { mapState } from 'vuex';
import { uris } from './constants';
import Navigation from './components/Navigation.vue';
export default Vue.extend({
name: 'App',
components: {
Navigation,
},
data() {
return {
activeItem: {},
activeGroup: {},
showLogout: Boolean,
windowWidth: window.innerWidth,
};
},
@ -168,20 +104,6 @@ export default Vue.extend({
this.activeGroup = state ? { [group]: true } : {};
},
doLogout() {
const http = new XMLHttpRequest();
const u = uris.root.substr(-1) === '/' ? uris.root : `${uris.root}/`;
http.open('get', `${u}api/logout`, false, 'logout_non_user', 'logout_non_user');
http.onload = () => {
document.location.href = uris.root;
};
http.onerror = () => {
document.location.href = uris.root;
};
http.send();
},
reloadApp() {
this.$api.reloadApp().then(() => {
this.$utils.toast('Reloading app ...');
@ -204,12 +126,20 @@ export default Vue.extend({
version() {
return process.env.VUE_APP_VERSION;
},
isMobile() {
return this.windowWidth <= 768;
},
},
mounted() {
// Lists is required across different views. On app load, fetch the lists
// and have them in the store.
this.$api.getLists({ minimal: true });
window.addEventListener('resize', () => {
this.windowWidth = window.innerWidth;
});
},
});
</script>

View file

@ -79,3 +79,4 @@
.mdi-chart-bar:before { content: '\e824'; } /* '' */
.mdi-email-bounce:before { content: '\e825'; } /* '' */
.mdi-speedometer:before { content: '\e826'; } /* '' */
.mdi-logout-variant:before { content: '󰗽'; } /* '\f05fd' */

BIN
frontend/src/assets/icons/fontello.woff2 Normal file → Executable file

Binary file not shown.

View file

@ -0,0 +1,117 @@
<template>
<b-menu-list>
<b-menu-item :to="{name: 'dashboard'}" tag="router-link" :active="activeItem.dashboard"
icon="view-dashboard-variant-outline" :label="$t('menu.dashboard')">
</b-menu-item><!-- dashboard -->
<b-menu-item :expanded="activeGroup.lists" :active="activeGroup.lists" data-cy="lists"
v-on:update:active="(state) => toggleGroup('lists', state)" icon="format-list-bulleted-square"
:label="$t('globals.terms.lists')">
<b-menu-item :to="{name: 'lists'}" tag="router-link" :active="activeItem.lists"
data-cy="all-lists" icon="format-list-bulleted-square" :label="$t('menu.allLists')">
</b-menu-item>
<b-menu-item :to="{name: 'forms'}" tag="router-link" :active="activeItem.forms"
class="forms" icon="newspaper-variant-outline" :label="$t('menu.forms')">
</b-menu-item>
</b-menu-item><!-- lists -->
<b-menu-item :expanded="activeGroup.subscribers" :active="activeGroup.subscribers"
data-cy="subscribers" v-on:update:active="(state) => toggleGroup('subscribers', state)"
icon="account-multiple" :label="$t('globals.terms.subscribers')">
<b-menu-item :to="{name: 'subscribers'}" tag="router-link"
:active="activeItem.subscribers" data-cy="all-subscribers" icon="account-multiple"
:label="$t('menu.allSubscribers')">
</b-menu-item>
<b-menu-item :to="{name: 'import'}" tag="router-link" :active="activeItem.import"
data-cy="import" icon="file-upload-outline" :label="$t('menu.import')">
</b-menu-item>
<b-menu-item :to="{name: 'bounces'}" tag="router-link" :active="activeItem.bounces"
data-cy="bounces" icon="email-bounce" :label="$t('globals.terms.bounces')">
</b-menu-item>
</b-menu-item><!-- subscribers -->
<b-menu-item :expanded="activeGroup.campaigns" :active="activeGroup.campaigns"
data-cy="campaigns" v-on:update:active="(state) => toggleGroup('campaigns', state)"
icon="rocket-launch-outline" :label="$t('globals.terms.campaigns')">
<b-menu-item :to="{name: 'campaigns'}" tag="router-link" :active="activeItem.campaigns"
data-cy="all-campaigns" icon="rocket-launch-outline" :label="$t('menu.allCampaigns')">
</b-menu-item>
<b-menu-item :to="{name: 'campaign', params: {id: 'new'}}" tag="router-link"
:active="activeItem.campaign" data-cy="new-campaign" icon="plus"
:label="$t('menu.newCampaign')">
</b-menu-item>
<b-menu-item :to="{name: 'media'}" tag="router-link" :active="activeItem.media"
data-cy="media" icon="image-outline" :label="$t('menu.media')">
</b-menu-item>
<b-menu-item :to="{name: 'templates'}" tag="router-link" :active="activeItem.templates"
data-cy="templates" icon="file-image-outline" :label="$t('globals.terms.templates')">
</b-menu-item>
<b-menu-item :to="{name: 'campaignAnalytics'}" tag="router-link"
:active="activeItem.campaignAnalytics" data-cy="analytics" icon="chart-bar"
:label="$t('globals.terms.analytics')">
</b-menu-item>
</b-menu-item><!-- campaigns -->
<b-menu-item :expanded="activeGroup.settings" :active="activeGroup.settings"
data-cy="settings" v-on:update:active="(state) => toggleGroup('settings', state)"
icon="cog-outline" :label="$t('menu.settings')">
<b-menu-item :to="{name: 'settings'}" tag="router-link" :active="activeItem.settings"
data-cy="all-settings" icon="cog-outline" :label="$t('menu.settings')">
</b-menu-item>
<b-menu-item :to="{name: 'logs'}" tag="router-link" :active="activeItem.logs"
data-cy="logs" icon="newspaper-variant-outline" :label="$t('menu.logs')">
</b-menu-item>
</b-menu-item><!-- settings -->
<b-menu-item v-if="isMobile" icon="logout-variant" :label="$t('users.logout')"
@click.prevent="doLogout">
</b-menu-item>
</b-menu-list>
</template>
<script>
import { uris } from '../constants';
export default {
name: 'navigation',
props: {
activeItem: Object,
activeGroup: Object,
isMobile: Boolean,
},
methods: {
toggleGroup(group, state) {
this.$emit('toggleGroup', group, state);
},
doLogout() {
const http = new XMLHttpRequest();
const u = uris.root.substr(-1) === '/' ? uris.root : `${uris.root}/`;
http.open('get', `${u}api/logout`, false, 'logout_non_user', 'logout_non_user');
http.onload = () => {
document.location.href = uris.root;
};
http.onerror = () => {
document.location.href = uris.root;
};
http.send();
},
},
};
</script>