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:
parent
125d51f7bf
commit
7b9ba2efbc
5 changed files with 170 additions and 108 deletions
42
frontend/fontello/config.json
Normal file → Executable file
42
frontend/fontello/config.json
Normal file → Executable 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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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>
|
||||
|
|
1
frontend/src/assets/icons/fontello.css
vendored
1
frontend/src/assets/icons/fontello.css
vendored
|
@ -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
BIN
frontend/src/assets/icons/fontello.woff2
Normal file → Executable file
Binary file not shown.
117
frontend/src/components/Navigation.vue
Normal file
117
frontend/src/components/Navigation.vue
Normal 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>
|
Loading…
Reference in a new issue