Created
October 17, 2017 16:15
-
-
Save d-levin/07f1cc3d03d0bb4e895b0de7bd1f21fc to your computer and use it in GitHub Desktop.
A simple responsive dashboard layout component with a collapsible drawer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div class="wrapper"> | |
<transition name="fade"> | |
<div v-if="drawerOpenOnMobile" class="overlay" @click="toggleDrawer"></div> | |
</transition> | |
<transition name="slide"> | |
<aside v-if="drawerOpen" class="drawer"> | |
<p>First item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Drawer item</p><p>Last item</p> | |
</aside> | |
</transition> | |
<div class="main" :class="mainWidthClass"> | |
<header class="header"> | |
<div v-if="isMobile" class="drawer-toggle"> | |
<a @click="toggleDrawer" class="button is-small"> | |
<span class="icon is-small"> | |
<i class="fa fa-bars"></i> | |
</span> | |
</a> | |
</div> | |
<div class="header-left"> | |
<h1 class="title is-inline-block">Dashboard</h1> | |
</div> | |
<div class="header-right"> | |
<a class="button is-small"> | |
<span class="icon is-small"> | |
<i class="fa fa-ellipsis-v"></i> | |
</span> | |
</a> | |
</div> | |
</header> | |
<section class="content"> | |
<div class="content-inner"> | |
<p>First content</p><p>Viral waistcoat post-ironic chicharrones, venmo tilde cardigan irony photo booth. Forage pug hashtag, small batch pickled helvetica cornhole. Cold-pressed beard microdosing, 3 wolf moon normcore banjo ugh thundercats kinfolk trust fund church-key chambray direct trade. Fashion axe copper mug pug glossier ramps. Vice kitsch kickstarter, pickled tousled post-ironic hoodie cred vexillologist beard viral poke small batch williamsburg. Retro chillwave gastropub pop-up beard. Af twee photo booth, kombucha drinking vinegar kale chips organic fingerstache vaporware coloring book keffiyeh migas pabst unicorn mumblecore. Hammock shaman enamel pin DIY raclette, ugh yr poke narwhal deep v four loko air plant copper mug. Retro la croix jean shorts live-edge, pour-over banjo chartreuse kinfolk meh kogi neutra.</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Last content</p> | |
</div> | |
</section> | |
</div> | |
</div> | |
</template> | |
<script> | |
// Bulma mobile breakpoint | |
const breakpoint = 768; | |
export default { | |
name: 'LayoutMain', | |
data() { | |
const windowWidth = window.innerWidth; | |
return { | |
appTitle: 'Sarkina', | |
drawerOpen: windowWidth > breakpoint, | |
windowWidth, | |
}; | |
}, | |
computed: { | |
drawerOpenOnMobile() { | |
return this.drawerOpen && this.isMobile; | |
}, | |
drawerOpenOnDesktop() { | |
return this.drawerOpen && !this.isMobile; | |
}, | |
isMobile() { | |
return this.windowWidth <= breakpoint; | |
}, | |
mainWidthClass() { | |
return this.drawerOpenOnDesktop ? 'main__drawer-offset' : 'main__full-width'; | |
}, | |
}, | |
watch: { | |
isMobile(isMobile) { | |
this.drawerOpen = !isMobile; | |
}, | |
}, | |
methods: { | |
toggleDrawer() { | |
this.drawerOpen = !this.drawerOpen; | |
}, | |
handleWindowResize(event) { | |
this.windowWidth = event.currentTarget.innerWidth; | |
}, | |
}, | |
beforeDestroy() { | |
window.removeEventListener('resize', this.handleWindowResize); | |
}, | |
mounted() { | |
window.addEventListener('resize', this.handleWindowResize); | |
}, | |
}; | |
</script> | |
<style lang="scss" scoped> | |
$drawer-width: 240px; | |
$drawer-z-index: 9999; | |
$header-height: 55px; | |
$transition-duration: 0.8s; | |
@mixin shadow($shadow) { | |
-webkit-box-shadow: $shadow; | |
-moz-box-shadow: $shadow; | |
box-shadow: $shadow; | |
} | |
@mixin transition($transition) { | |
-webkit-transition: $transition; | |
-moz-transition: $transition; | |
-o-transition: $transition; | |
transition: $transition; | |
} | |
@mixin transform($transform) { | |
-webkit-transform: $transform; | |
-moz-transform: $transform; | |
-ms-transform: $transform; | |
-o-transform: $transform; | |
transform: $transform; | |
} | |
.wrapper { | |
height: 100%; | |
position: relative; | |
} | |
.overlay { | |
position: fixed; | |
left: 0; | |
right: 0; | |
top: 0; | |
bottom: 0; | |
background-color: rgba(black, 0.4); | |
will-change: opacity; | |
/* Place just below drawer */ | |
z-index: $drawer-z-index - 1; | |
} | |
.drawer { | |
position: absolute; | |
left: 0; | |
top: 0; | |
bottom: 0; | |
width: $drawer-width; | |
padding: 1rem; | |
background-color: bisque; | |
overflow-y: auto; | |
z-index: $drawer-z-index; | |
will-change: transform; | |
@include shadow(-2px 0 6px #333333); | |
} | |
.main { | |
background-color: gray; | |
position: relative; | |
min-height: 100%; | |
height: 100%; | |
float: right; | |
will-change: width; | |
@include transition(width $transition-duration); | |
&.main__full-width { | |
width: 100%; | |
} | |
&.main__drawer-offset { | |
width: calc(100% - #{$drawer-width}); | |
} | |
} | |
.header { | |
position: fixed; | |
top: 0; | |
height: $header-height; | |
padding: 0 1rem; | |
overflow: hidden; | |
width: inherit; | |
background-color: lightblue; | |
display: flex; | |
align-items: center; | |
.header-left { | |
flex-grow: 1; | |
} | |
.drawer-toggle { | |
margin-right: 1rem; | |
} | |
} | |
.content { | |
padding-top: $header-height; | |
background-color: thistle; | |
.content-inner { | |
overflow-y: auto; | |
padding: 2rem 1rem; | |
} | |
} | |
.content, | |
.content-inner { | |
height: inherit; | |
} | |
/* Transitions */ | |
// Slide | |
.slide-leave-active, | |
.slide-enter-active { | |
@include transition(transform $transition-duration); | |
} | |
.slide-enter, | |
.slide-leave-to { | |
@include transform(translateX(-100%)); | |
} | |
// Fade | |
.fade-leave-active, | |
.fade-enter-active { | |
@include transition(opacity $transition-duration); | |
} | |
.fade-enter, | |
.fade-leave-to { | |
opacity: 0; | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment