Skip to content

Instantly share code, notes, and snippets.

@FabienVINCENT
Last active May 26, 2022 10:49
Show Gist options
  • Save FabienVINCENT/285cfca33c196e958371b5deb009f586 to your computer and use it in GitHub Desktop.
Save FabienVINCENT/285cfca33c196e958371b5deb009f586 to your computer and use it in GitHub Desktop.
Modal bootstrap 5 + VueJs (Nuxt)
<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