Skip to content

Instantly share code, notes, and snippets.

@bhushan
Last active March 29, 2021 12:24
Show Gist options
  • Save bhushan/2fdbfed632cfd79cb6d40b12a85e8b9f to your computer and use it in GitHub Desktop.
Save bhushan/2fdbfed632cfd79cb6d40b12a85e8b9f to your computer and use it in GitHub Desktop.
Reusable Vue Components
🗃️ Dropdown Menu in Vue using Tailwind css
<template>
<div class="flex-shrink-0 relative ml-4">
<button
class="bg-white rounded-full flex focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-900"
@click="open = !open"
>
<span class="sr-only">{{ srOnly }}</span>
<slot name="menu"></slot>
</button>
<transition
enter-active-class="transition ease-out duration-100"
enter-class="transform opacity-0 scale-95"
enter-to-class="transform opacity-100 scale-100"
leave-active-class="transition ease-in duration-75"
leave-class="transform opacity-100 scale-100"
leave-to-class="transform opacity-0 scale-95"
>
<div
v-if="open"
class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 py-1"
role="menu"
aria-orientation="vertical"
aria-labelledby="user-menu"
>
<template v-for="(item, index) in items">
<a
:key="`menu-item-${index}-${item.name}`"
:href="item.href"
class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100"
role="menuitem"
>
{{ item.name }}
</a>
</template>
</div>
</transition>
</div>
</template>
<script>
export default {
name: 'Dropdown',
props: {
items: {
type: Array,
default: () => [],
validator: (items) => {
let isValid = true;
for (let i = 0; i < items.length; i++) {
if (!('name' in items[i]) || !('href' in items[i])) {
isValid = false;
break;
}
}
return isValid;
},
},
srOnly: {
type: String,
default: '',
},
},
data () {
return {
open: false,
};
},
};
</script>
// usage
<Dropdown
:items="profileDropdownItems"
:sr-only="'Open User Menu'"
>
<template #menu>
<img
class="h-8 w-8 rounded-full"
src="https://images.unsplash.com/photo-1517365830460-955ce3ccd263?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=4&amp;w=256&amp;h=256&amp;q=80"
alt="user-profile"
/>
</template>
</Dropdown>
data() {
return {
profileDropdownItems: [
{
name: 'Dashboard',
href: '/dashboard',
},
{
name: 'Sign Out',
href: '/sign-out',
},
],
}
},
@rckstrbhushan
🗃️ Graphs in Vue using Chart.js
<template>
<canvas
ref="canvas"
class="p-4"
></canvas>
</template>
<script>
import Chart from 'chart.js';
export default {
name: 'Graph',
props: {
labels: {
type: Array,
default: () => [],
},
type: {
type: String,
default: 'line',
validator: (value) => {
return [
'pie',
'bar',
'line',
'radar',
'doughnut',
'polarArea',
].includes(value);
},
},
datasets: {
type: Array,
default: () => [],
validator: (items) => {
let isValid = true;
for (let i = 0; i < items.length; i++) {
if (!('label' in items[i]) || !('data' in items[i])) {
isValid = false;
break;
}
}
return isValid;
},
},
options: {
type: Object,
default: () => {
return {
responsive: true,
};
},
},
},
data () {
return {
chart: null,
};
},
mounted () {
this.$nextTick(function () {
this.chart = new Chart(this.$refs.canvas.getContext('2d'), {
type: this.type,
data: {
labels: this.labels,
datasets: this.datasets,
},
options: this.options,
});
});
},
beforeDestroy () {
this.chart.destroy();
},
};
</script>
//usage
<template>
<div>
<Graph
:labels="labels"
:datasets="datasets"
/>
<Graph
type="bar"
:labels="labels"
:datasets="datasets"
/>
<Graph
type="radar"
:labels="labels"
:datasets="datasets"
/>
<Graph
type="pie"
:labels="labels"
:datasets="datasets"
/>
<Graph
type="doughnut"
:labels="labels"
:datasets="datasets"
/>
<Graph
type="polarArea"
:labels="labels"
:datasets="datasets"
/>
</div>
</template>
<script>
export default {
name: 'DashboardPage',
data () {
return {
labels: ['Jan', 'Feb', 'March'],
datasets: [
{
label: '2020',
data: [10, 20, 30],
backgroundColor: 'rgb(255, 0, 0, 0.4)',
},
{
label: '2021',
data: [12, 22, 35],
backgroundColor: 'rgb(0, 255, 0, 0.4)',
},
{
label: '2022',
data: [1, 2, 5],
backgroundColor: 'rgba(0, 0, 255, 0.4)',
},
],
};
},
};
</script>
@rckstrbhushan
🗃️ Hamburger Menu in Vue using Tailwind css
<template>
<div class="relative z-10 flex items-center lg:hidden">
<button
class="rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:bg-gray-100 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-gray-900"
@click.prevent="changed"
>
<span class="sr-only">Open menu</span>
<svg
class="h-6 w-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
:d="open ? 'M4 6h16M4 12h16M4 18h16' : 'M6 18L18 6M6 6l12 12'"
/>
</svg>
</button>
</div>
</template>
<script>
export default {
name: 'HamburgerMenu',
props: {
value: {
type: Boolean,
default: false,
},
},
data () {
return {
open: true,
};
},
methods: {
changed () {
this.open = !this.open;
this.$emit('input', this.open);
},
},
};
</script>
// usage
<HamburgerMenu v-model="isHamburgerOpen" />
@rckstrbhushan
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment