Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to toggle sidebar and always show the toggle #989

Merged
merged 1 commit into from
Apr 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
],
"dependencies": {
"@nextcloud/axios": "^1.1.0",
"@nextcloud/event-bus": "^1.1.4",
"@nextcloud/l10n": "^1.1.0",
"@nextcloud/router": "^1.0.0",
"core-js": "^3.4.4",
Expand Down
64 changes: 29 additions & 35 deletions src/components/AppContent/AppContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
- @copyright Copyright (c) 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
-
- @author Christoph Wurst <christoph@winzerhof-wurst.at>
- @author Marco Ambrosini <marcoambrosini@pm.me>
- @author John Molakvoæ <skjnldsv@protonmail.com>
-
- @license GNU AGPL version 3 or any later version
-
Expand All @@ -21,78 +23,70 @@
-->

<template>
<main id="app-content" class="no-snapper" :style="opened ? 'transform: translateX(300px)' : ''">
<AppNavigationToggle :aria-expanded="opened"
aria-controls="app-navigation"
@click="toggleNavigation" />
<main id="app-content" class="no-snapper">
<!-- @slot Provide content to the app content -->
<slot />
</main>
</template>

<script>
import Hammer from 'hammerjs'
import AppNavigationToggle from '../AppNavigationToggle'
import { emit } from '@nextcloud/event-bus'

/**
* App content container to be used for the main content of your app
*
*/
export default {
name: 'AppContent',
components: {
AppNavigationToggle,
},
data() {
return {
// closed by default on mobile mode
opened: false,
}

props: {
// Allows to disable the control by swipe of the app navigation open state
allowSwipeNavigation: {
type: Boolean,
default: true,
},
},

mounted() {
this.mc = new Hammer(this.$el, { cssProps: { userSelect: 'text' } })
this.mc.on('swipeleft swiperight', e => {
this.handleSwipe(e)
})
if (this.allowSwipeNavigation) {
this.mc = new Hammer(this.$el, { cssProps: { userSelect: 'text' } })
this.mc.on('swipeleft swiperight', this.handleSwipe)
}
},
unmounted() {
this.mc.off('swipeleft swiperight')
this.mc.destroy()
beforeDestroy() {
this.mc.off('swipeleft swiperight', this.handleSwipe)
},
methods: {
/**
* Toggle the navigation
*
* @param {Boolean} [state] set the state instead of inverting the current one
*/
toggleNavigation(state) {
this.opened = state || !this.opened
this.opened
? document.body.classList.add('nav-open')
: document.body.classList.remove('nav-open')
},
// handle the swipe event
handleSwipe(e) {
const minSwipeX = 70
const touchzone = 40
const startX = e.srcEvent.pageX - e.deltaX
const hasEnoughDistance = Math.abs(e.deltaX) > minSwipeX
if (hasEnoughDistance && startX < touchzone) {
this.toggleNavigation(true)
} else if (this.opened && hasEnoughDistance && startX < touchzone + 300) {
this.toggleNavigation(false)
emit('toggle-navigation', {
open: true,
})
} else if (hasEnoughDistance && startX < touchzone + 300) {
emit('toggle-navigation', {
open: false,
})
}
},
},
}
</script>
<style lang="scss" scoped>

#app-content {
z-index: 1000;
background-color: var(--color-main-background);
position: relative;
flex-basis: 100vw;
min-height: 100%;
transition: transform var(--animation-quick);
// Overriding server styles TODO: cleanup!
margin: 0 !important;
}

</style>
142 changes: 116 additions & 26 deletions src/components/AppNavigation/AppNavigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
-
- @author Christoph Wurst <christoph@winzerhof-wurst.at>
- @author John Molakvoæ <skjnldsv@protonmail.com>
- @author Marco Ambrosini <marcoambrosini@pm.me>
-
- @license GNU AGPL version 3 or any later version
Expand All @@ -20,34 +21,118 @@
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-->
<docs>
The navigation bar can be open and closed from anywhere in the app using the
nextcloud event bus.

### Install the event bus package

```bash
npm i -S @nextcloud/event-bus
```

### Usage

#### Open the navigation

```js static
import { emit } from '@nextcloud/event-bus'
emit('toggle-navigation', {
open: true,
})
```

#### Close the navigation

```js static
import { emit } from '@nextcloud/event-bus'
emit('toggle-navigation', {
open: false,
})
```

</docs>

<template>
<div id="app-navigation" class="vue">
<div
class="app-navigation"
:class="{'app-navigation--close':!open }">
<AppNavigationToggle :open.sync="open" />
<slot />
</div>
</template>

<script>
import { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'
import AppNavigationToggle from '../AppNavigationToggle/AppNavigationToggle'
import isMobile from '../../mixins/isMobile'

export default {
name: 'AppNavigation',

components: {
AppNavigationToggle,
},

mixins: [isMobile],

data() {
return {
open: true,
}
},

watch: {
isMobile() {
this.open = !this.isMobile
},
},

mounted() {
subscribe('toggle-navigation', this.toggleNavigationByEventBus)
// Emit an event with the initial state of the navigation
emit('navigation-toggled', {
open: this.open,
})
},
unmounted() {
this.mc.off('swipeleft swiperight')
this.mc.destroy()
unsubscribe('toggle-navigation', this.toggleNavigationByEventBus)
},

methods: {
/**
* Toggle the navigation
*
* @param {Boolean} [state] set the state instead of inverting the current one
*/
toggleNavigation(state) {
this.open = state || !this.open
emit('navigation-toggled', {
open: this.open,
})
},
toggleNavigationByEventBus({ open }) {
this.toggleNavigation(open)
},
},
}
</script>

<style lang="scss" scoped>
@import '../assets/variables.scss';

#app-navigation {
.app-navigation {
will-change: transform;
transition: transform var(--animation-quick);
transition: transform var(--animation-quick), margin var(--animation-quick);
width: $navigation-width;
position: fixed;
position: sticky;
position: -webkit-sticky;
top: $header-height;
left: 0;
z-index: 500;
overflow-y: auto;
overflow-x: hidden;
// Do not use vh because of mobile headers
// are included in the calculation
height: calc(100% - #{$header-height});
// Above appcontent
z-index: 2000;
height: calc(100vh - #{$header-height});
box-sizing: border-box;
background-color: var(--color-main-background);
-webkit-user-select: none;
Expand All @@ -59,25 +144,30 @@ export default {
flex-direction: column;
flex-grow: 0;
flex-shrink: 0;
}

//list of navigation items
ul {
position: relative;
height: 100%;
width: inherit;
overflow-x: hidden;
overflow-y: auto;
box-sizing: border-box;
display: flex;
flex-direction: column;
&--close {
margin-left: - $navigation-width;
transform: translateX(-100%);
}

//list of navigation items
ul {
position: relative;
height: 100%;
width: inherit;
overflow-x: hidden;
overflow-y: auto;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
}

// mobile view only
// When on mobile, we make the navigation slide over the appcontent
@media only screen and (max-width: $breakpoint-mobile) {
// if navigation is shown
.nav-open #app-navigation {
transform: translateX(0);
.app-navigation:not(.app-navigation--close) {
margin-left: - $navigation-width;
}
}

</style>
Loading