Skip to content

Instantly share code, notes, and snippets.

@MichaelGitArt
Last active August 17, 2021 07:11
Show Gist options
  • Save MichaelGitArt/68f86e0d553dcd4c6ac7a4eb678ba903 to your computer and use it in GitHub Desktop.
Save MichaelGitArt/68f86e0d553dcd4c6ac7a4eb678ba903 to your computer and use it in GitHub Desktop.
VuetifyDialog
<template>
<div>
<Component
:is="modal.component"
v-for="(modal, index) in dialogs"
:key="index"
:index="index"
v-bind="modal.props"
@close="onCloseModal(index)"
/>
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
name: 'App',
computed: {
...mapState('core', ['dialogs']),
},
methods: {
onCloseModal(index) {
this.$store.dispatch('core/hideDialog', index).then(() => {
setTimeout(() => {
this.$store.dispatch('core/removeDialog', index);
}, 100);
});
},
},
};
</script>
<template>
<div class="dialog-wrapper">
<VDialog
:value="value"
:max-width="maxWidth"
:content-class="contentClasses"
:fullscreen="$vuetify.breakpoint.xsOnly && !disableFullscreen"
:persistent="persistent"
@input="onInput"
>
<div class="header">
<slot name="toolbar" :scrolled="scrolled">
<DialogDefaultToolbar
v-if="!disableDefaultToolbar"
:title="title"
:scrolled="scrolled"
@close="onClose"
>
<slot name="toolbar-title" />
</DialogDefaultToolbar>
</slot>
</div>
<div
v-scroll.self="onScroll"
class="body"
:class="{
'px-sm-8 px-4 pb-4': !disablePadding
}"
>
<slot />
</div>
<div v-if="$slots['footer']" class="footer">
<slot name="footer" />
</div>
</VDialog>
</div>
</template>
<script>
import DialogDefaultToolbar from './DialogDefaultToolbar.vue';
export default {
name: 'DialogDefault',
components: {
DialogDefaultToolbar,
},
props: {
/**
* The dialog state
*/
value: {
type: Boolean,
default: true,
},
/**
* Dialog title in the default toolbar
*/
title: {
type: String,
default: '',
},
/**
* Max width of the dialog
*/
maxWidth: {
type: [Number, String],
default: 480,
},
/**
* Clicking outside of the dialog does not close it
*/
persistent: {
type: Boolean,
default: false,
},
/**
* Disable main slot padding
*/
disablePadding: {
type: Boolean,
default: false,
},
/**
* Disable default toolbar
*/
disableDefaultToolbar: {
type: Boolean,
default: false,
},
/**
* Disable default padding on the sides of the modal
*/
disableFullscreen: {
type: Boolean,
default: false,
},
contentClass: {
type: String,
default: '',
},
},
data: () => ({
scrolled: false,
closed: false,
}),
computed: {
contentClasses() {
return `dialog-default ${this.contentClass}`;
},
},
methods: {
onScroll(e) {
this.scrolled = e.target.scrollTop > 0;
},
onInput(value) {
if (!value && !this.closed) {
this.closed = true;
this.onClose();
}
},
onClose() {
this.$emit('close');
this.$emit('input', false);
},
},
};
</script>
<style lang="scss" scoped>
// eslint-disable-next-line vue-scoped-css/require-v-deep-argument
::v-deep {
.dialog-default {
display: flex;
flex-direction: column;
background-color: #fff;
.header {
flex-grow: 0;
z-index: 2;
}
.body {
overflow-x: hidden;
overflow-y: auto;
flex-grow: 1;
}
.footer {
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.2) !important;
flex-grow: 0;
z-index: 2;
}
}
}
</style>
<template>
<VToolbar
color="#f5f4fa"
class="dialog-toolbar pl-sm-4"
:class="{
'dialog-toolbar--scrolled': scrolled,
}"
>
<slot>
<VToolbarTitle>
{{ title }}
</VToolbarTitle>
</slot>
<VSpacer />
<VBtn
rounded
icon
@click="onClose"
>
<VIcon>mdi-close</VIcon>
</VBtn>
</VToolbar>
</template>
<script>
export default {
name: 'DialogDefaultToolbar',
props: {
/**
* Dialog title
*/
title: {
type: String,
default: '',
},
/**
* Determines whether the dialog content is scrolled
*/
scrolled: {
type: Boolean,
required: true,
},
},
methods: {
onClose() {
this.$emit('close')
},
},
}
</script>
<style lang="scss" scoped>
.dialog-toolbar {
box-shadow: none !important;
z-index: 2;
flex-grow: 0;
&--scrolled {
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.08) !important;
}
}
</style>
const state = () => ({
dialogs: [],
})
const actions = {
/**
* open a dialog
* @param {Object} context
* @param {Object} payload
* @param {Object} payload.component dialog component
* @param {Object} [payload.props] props for the component
*/
addDialog({ commit }, payload) {
commit('addDialog', {
...payload,
props: {
...payload.props,
value: true,
},
});
},
/**
* remove dialog
*/
removeDialog({ commit }, index) {
commit('removeDialog', index);
},
/**
* hide dialog before removing
*/
hideDialog({ commit }, index) {
commit('hideDialog', index);
},
}
const mutations = {
addDialog(state, modal) {
state.dialogs.push(modal);
},
removeDialog(state, index) {
state.dialogs.splice(index, 1);
},
hideDialog(state, index) {
state.dialogs[index].props.value = false;
},
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment