Skip to content

Instantly share code, notes, and snippets.

@d-levin
Created October 17, 2017 16:15
Show Gist options
  • Save d-levin/07f1cc3d03d0bb4e895b0de7bd1f21fc to your computer and use it in GitHub Desktop.
Save d-levin/07f1cc3d03d0bb4e895b0de7bd1f21fc to your computer and use it in GitHub Desktop.
A simple responsive dashboard layout component with a collapsible drawer
<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