Last active
May 26, 2022 10:49
-
-
Save FabienVINCENT/285cfca33c196e958371b5deb009f586 to your computer and use it in GitHub Desktop.
Modal bootstrap 5 + VueJs (Nuxt)
This file contains 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 ref="modal" class="modal fade" tabindex="-1" role="dialog" :aria-hidden="!show"> | |
<div | |
class="modal-dialog modal-dialog-centered modal-dialog-scrollable" | |
:class="[{ [`modal-${size}`]: size }, { [`modal-${fullscreen}`]: fullscreen }]" | |
> | |
<div class="modal-content"> | |
<div v-if="$slots.header" class="modal-header"> | |
<h5 class="modal-title"> | |
<slot name="header" /> | |
</h5> | |
<button | |
v-if="showClose" | |
type="button" | |
class="btn-close btn-close-sunr" | |
data-dismiss="modal" | |
aria-label="Close" | |
@click="closeModal" | |
/> | |
</div> | |
<div class="modal-body" :class="{ 'shadow-inset': scrollbarVisible }"> | |
<slot /> | |
</div> | |
<div v-if="$slots.footer" class="modal-footer d-flex justify-content-end align-items-center"> | |
<a v-if="showClose" href="#" class="link-cancel" @click.prevent="closeModal">Annuler</a> | |
<slot name="footer" /> | |
</div> | |
</div> | |
</div> | |
</div> | |
</template> | |
<script> | |
const bootstrap = typeof window !== `undefined` && import('bootstrap') | |
let uid = 0 | |
export default { | |
name: 'Modal', | |
props: { | |
show: Boolean, | |
showClose: { | |
type: Boolean, | |
default: true, | |
}, | |
size: { | |
type: String, | |
description: 'Modal size', | |
default: '', | |
validator(value) { | |
const acceptedValues = ['', 'sm', 'lg', 'xl'] | |
return acceptedValues.includes(value) | |
}, | |
}, | |
fullscreen: { | |
type: String, | |
description: 'Modal fullscreen', | |
default: '', | |
validator(value) { | |
const acceptedValues = [ | |
'', | |
'fullscreen', | |
'fullscreen-sm-down', | |
'fullscreen-md-down', | |
'fullscreen-lg-down', | |
'fullscreen-xl-down', | |
'fullscreen-xxl-down', | |
] | |
return acceptedValues.includes(value) | |
}, | |
}, | |
}, | |
data() { | |
uid += 1 | |
return { | |
modal: null, | |
uid: 'modal-' + uid, | |
scrollbarVisible: false, | |
} | |
}, | |
watch: { | |
show(val) { | |
if (!this.modal) return | |
if (val) { | |
this.modal.show() | |
} else { | |
this.modal.hide() | |
} | |
}, | |
}, | |
mounted() { | |
bootstrap?.then(({ Modal }) => { | |
this.modal = new Modal(this.$refs.modal, { backdrop: false }) | |
if (this.show) { | |
this.modal.show() | |
} | |
const body = this.$refs.modal.querySelector('.modal-body') | |
new ResizeObserver(() => this.handleResize()).observe(body) | |
this.handleResize() | |
}) | |
}, | |
methods: { | |
handleResize() { | |
if (!this.$refs.modal) return false | |
const element = this.$refs.modal.querySelector('.modal-body') | |
this.scrollbarVisible = element.scrollHeight > element.clientHeight | |
}, | |
closeModal() { | |
this.$emit('close') | |
}, | |
}, | |
} | |
</script> | |
<style scoped lang="scss"> | |
@import './assets/sass/variables'; | |
.modal { | |
&::before { | |
content: ''; | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
opacity: 0; | |
background-color: #232b2f; | |
transition: opacity 0.2s ease-in-out; | |
} | |
&.show::before { | |
opacity: 0.5; | |
} | |
& .modal-body.shadow-inset { | |
box-shadow: inset 0px -16px 26px -30px #000000, inset 0px 16px 26px -30px #000000; | |
padding-top: 2rem; | |
padding-bottom: 2rem; | |
} | |
} | |
.modal-content { | |
padding-bottom: 2rem; | |
& .modal-footer { | |
padding-bottom: 0; | |
} | |
} | |
h5.modal-title { | |
font-size: 1.4rem; | |
font-weight: 600; | |
} | |
.modal-body { | |
padding: 0 2rem; | |
} | |
a.link-cancel { | |
color: $font-color-label-input; | |
font-weight: 600; | |
text-decoration: none; | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment