forked from AkkomaGang/akkoma-fe
Merge branch 'modal-scroll-lock' into 'develop'
Lock body scroll when modal is open globally See merge request pleroma/pleroma-fe!974
This commit is contained in:
commit
cd95618520
9 changed files with 106 additions and 83 deletions
25
src/App.scss
25
src/App.scss
|
@ -705,31 +705,6 @@ nav {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes modal-background-fadein {
|
|
||||||
from {
|
|
||||||
background-color: rgba(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-view {
|
|
||||||
z-index: 1000;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
overflow: auto;
|
|
||||||
animation-duration: 0.2s;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
animation-name: modal-background-fadein;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-icon {
|
.button-icon {
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import StillImage from '../still-image/still-image.vue'
|
import StillImage from '../still-image/still-image.vue'
|
||||||
import VideoAttachment from '../video_attachment/video_attachment.vue'
|
import VideoAttachment from '../video_attachment/video_attachment.vue'
|
||||||
|
import Modal from '../modal/modal.vue'
|
||||||
import fileTypeService from '../../services/file_type/file_type.service.js'
|
import fileTypeService from '../../services/file_type/file_type.service.js'
|
||||||
|
|
||||||
const MediaModal = {
|
const MediaModal = {
|
||||||
components: {
|
components: {
|
||||||
StillImage,
|
StillImage,
|
||||||
VideoAttachment
|
VideoAttachment,
|
||||||
|
Modal
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
showing () {
|
showing () {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<Modal
|
||||||
v-if="showing"
|
v-if="showing"
|
||||||
v-body-scroll-lock="showing"
|
class="media-modal-view"
|
||||||
class="modal-view media-modal-view"
|
@backdropClicked="hide"
|
||||||
@click.prevent="hide"
|
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
v-if="type === 'image'"
|
v-if="type === 'image'"
|
||||||
|
@ -33,21 +32,15 @@
|
||||||
>
|
>
|
||||||
<i class="icon-right-open arrow-icon" />
|
<i class="icon-right-open arrow-icon" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./media_modal.js"></script>
|
<script src="./media_modal.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '../../_variables.scss';
|
.modal-view.media-modal-view {
|
||||||
|
|
||||||
.media-modal-view {
|
|
||||||
z-index: 1001;
|
z-index: 1001;
|
||||||
|
|
||||||
body:not(.scroll-locked) & {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.modal-view-button-arrow {
|
.modal-view-button-arrow {
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
|
@ -114,5 +107,4 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
52
src/components/modal/modal.vue
Normal file
52
src/components/modal/modal.vue
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
v-show="isOpen"
|
||||||
|
v-body-scroll-lock="isOpen"
|
||||||
|
class="modal-view"
|
||||||
|
@click.self="$emit('backdropClicked')"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
isOpen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.modal-view {
|
||||||
|
z-index: 1000;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
overflow: auto;
|
||||||
|
animation-duration: 0.2s;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
animation-name: modal-background-fadein;
|
||||||
|
|
||||||
|
body:not(.scroll-locked) & {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes modal-background-fadein {
|
||||||
|
from {
|
||||||
|
background-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,9 +1,11 @@
|
||||||
import PostStatusForm from '../post_status_form/post_status_form.vue'
|
import PostStatusForm from '../post_status_form/post_status_form.vue'
|
||||||
|
import Modal from '../modal/modal.vue'
|
||||||
import get from 'lodash/get'
|
import get from 'lodash/get'
|
||||||
|
|
||||||
const PostStatusModal = {
|
const PostStatusModal = {
|
||||||
components: {
|
components: {
|
||||||
PostStatusForm
|
PostStatusForm,
|
||||||
|
Modal
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<Modal
|
||||||
v-if="isLoggedIn && !resettingForm"
|
v-if="isLoggedIn && !resettingForm"
|
||||||
v-show="modalActivated"
|
:is-open="modalActivated"
|
||||||
class="post-form-modal-view modal-view"
|
class="post-form-modal-view"
|
||||||
@click="closeModal"
|
@backdropClicked="closeModal"
|
||||||
>
|
>
|
||||||
<div
|
<div class="post-form-modal-panel panel">
|
||||||
class="post-form-modal-panel panel"
|
|
||||||
@click.stop=""
|
|
||||||
>
|
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
{{ $t('post_status.new_status') }}
|
{{ $t('post_status.new_status') }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,15 +15,13 @@
|
||||||
@posted="closeModal"
|
@posted="closeModal"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./post_status_modal.js"></script>
|
<script src="./post_status_modal.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '../../_variables.scss';
|
.modal-view.post-form-modal-view {
|
||||||
|
|
||||||
.post-form-modal-view {
|
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,14 @@
|
||||||
import Status from '../status/status.vue'
|
import Status from '../status/status.vue'
|
||||||
import List from '../list/list.vue'
|
import List from '../list/list.vue'
|
||||||
import Checkbox from '../checkbox/checkbox.vue'
|
import Checkbox from '../checkbox/checkbox.vue'
|
||||||
|
import Modal from '../modal/modal.vue'
|
||||||
|
|
||||||
const UserReportingModal = {
|
const UserReportingModal = {
|
||||||
components: {
|
components: {
|
||||||
Status,
|
Status,
|
||||||
List,
|
List,
|
||||||
Checkbox
|
Checkbox,
|
||||||
|
Modal
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<Modal
|
||||||
v-if="isOpen"
|
v-if="isOpen"
|
||||||
class="modal-view"
|
@backdropClicked="closeModal"
|
||||||
@click="closeModal"
|
|
||||||
>
|
>
|
||||||
<div
|
<div class="user-reporting-panel panel">
|
||||||
class="user-reporting-panel panel"
|
|
||||||
@click.stop=""
|
|
||||||
>
|
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
{{ $t('user_reporting.title', [user.screen_name]) }}
|
{{ $t('user_reporting.title', [user.screen_name]) }}
|
||||||
|
@ -69,7 +65,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./user_reporting_modal.js"></script>
|
<script src="./user_reporting_modal.js"></script>
|
||||||
|
|
|
@ -2,42 +2,49 @@ import * as bodyScrollLock from 'body-scroll-lock'
|
||||||
|
|
||||||
let previousNavPaddingRight
|
let previousNavPaddingRight
|
||||||
let previousAppBgWrapperRight
|
let previousAppBgWrapperRight
|
||||||
|
const lockerEls = new Set([])
|
||||||
|
|
||||||
const disableBodyScroll = (el) => {
|
const disableBodyScroll = (el) => {
|
||||||
const scrollBarGap = window.innerWidth - document.documentElement.clientWidth
|
const scrollBarGap = window.innerWidth - document.documentElement.clientWidth
|
||||||
bodyScrollLock.disableBodyScroll(el, {
|
bodyScrollLock.disableBodyScroll(el, {
|
||||||
reserveScrollBarGap: true
|
reserveScrollBarGap: true
|
||||||
})
|
})
|
||||||
|
lockerEls.add(el)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// If previousNavPaddingRight is already set, don't set it again.
|
if (lockerEls.size <= 1) {
|
||||||
if (previousNavPaddingRight === undefined) {
|
// If previousNavPaddingRight is already set, don't set it again.
|
||||||
const navEl = document.getElementById('nav')
|
if (previousNavPaddingRight === undefined) {
|
||||||
previousNavPaddingRight = window.getComputedStyle(navEl).getPropertyValue('padding-right')
|
const navEl = document.getElementById('nav')
|
||||||
navEl.style.paddingRight = previousNavPaddingRight ? `calc(${previousNavPaddingRight} + ${scrollBarGap}px)` : `${scrollBarGap}px`
|
previousNavPaddingRight = window.getComputedStyle(navEl).getPropertyValue('padding-right')
|
||||||
|
navEl.style.paddingRight = previousNavPaddingRight ? `calc(${previousNavPaddingRight} + ${scrollBarGap}px)` : `${scrollBarGap}px`
|
||||||
|
}
|
||||||
|
// If previousAppBgWrapeprRight is already set, don't set it again.
|
||||||
|
if (previousAppBgWrapperRight === undefined) {
|
||||||
|
const appBgWrapperEl = document.getElementById('app_bg_wrapper')
|
||||||
|
previousAppBgWrapperRight = window.getComputedStyle(appBgWrapperEl).getPropertyValue('right')
|
||||||
|
appBgWrapperEl.style.right = previousAppBgWrapperRight ? `calc(${previousAppBgWrapperRight} + ${scrollBarGap}px)` : `${scrollBarGap}px`
|
||||||
|
}
|
||||||
|
document.body.classList.add('scroll-locked')
|
||||||
}
|
}
|
||||||
// If previousAppBgWrapeprRight is already set, don't set it again.
|
|
||||||
if (previousAppBgWrapperRight === undefined) {
|
|
||||||
const appBgWrapperEl = document.getElementById('app_bg_wrapper')
|
|
||||||
previousAppBgWrapperRight = window.getComputedStyle(appBgWrapperEl).getPropertyValue('right')
|
|
||||||
appBgWrapperEl.style.right = previousAppBgWrapperRight ? `calc(${previousAppBgWrapperRight} + ${scrollBarGap}px)` : `${scrollBarGap}px`
|
|
||||||
}
|
|
||||||
document.body.classList.add('scroll-locked')
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const enableBodyScroll = (el) => {
|
const enableBodyScroll = (el) => {
|
||||||
|
lockerEls.delete(el)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (previousNavPaddingRight !== undefined) {
|
if (lockerEls.size === 0) {
|
||||||
document.getElementById('nav').style.paddingRight = previousNavPaddingRight
|
if (previousNavPaddingRight !== undefined) {
|
||||||
// Restore previousNavPaddingRight to undefined so disableBodyScroll knows it can be set again.
|
document.getElementById('nav').style.paddingRight = previousNavPaddingRight
|
||||||
previousNavPaddingRight = undefined
|
// Restore previousNavPaddingRight to undefined so disableBodyScroll knows it can be set again.
|
||||||
|
previousNavPaddingRight = undefined
|
||||||
|
}
|
||||||
|
if (previousAppBgWrapperRight !== undefined) {
|
||||||
|
document.getElementById('app_bg_wrapper').style.right = previousAppBgWrapperRight
|
||||||
|
// Restore previousAppBgWrapperRight to undefined so disableBodyScroll knows it can be set again.
|
||||||
|
previousAppBgWrapperRight = undefined
|
||||||
|
}
|
||||||
|
document.body.classList.remove('scroll-locked')
|
||||||
}
|
}
|
||||||
if (previousAppBgWrapperRight !== undefined) {
|
|
||||||
document.getElementById('app_bg_wrapper').style.right = previousAppBgWrapperRight
|
|
||||||
// Restore previousAppBgWrapperRight to undefined so disableBodyScroll knows it can be set again.
|
|
||||||
previousAppBgWrapperRight = undefined
|
|
||||||
}
|
|
||||||
document.body.classList.remove('scroll-locked')
|
|
||||||
})
|
})
|
||||||
bodyScrollLock.enableBodyScroll(el)
|
bodyScrollLock.enableBodyScroll(el)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue