diff --git a/src/client/app/common/views/components/dialog.vue b/src/client/app/common/views/components/dialog.vue index d5906eb4c4..2744903007 100644 --- a/src/client/app/common/views/components/dialog.vue +++ b/src/client/app/common/views/components/dialog.vue @@ -1,6 +1,12 @@ <template> -<div class="felqjxyj" :class="{ splash }"> - <div class="bg" ref="bg" @click="onBgClick"></div> +<ui-modal + ref="modal" + class="modal" + :class="{ splash }" + :close-anime-duration="300" + :close-on-bg-click="false" + @bg-click="onBgClick" + @before-close="onBeforeClose"> <div class="main" ref="main" :class="{ round: $store.state.device.roundedCorners }"> <template v-if="type == 'signin'"> <mk-signin/> @@ -38,7 +44,7 @@ </ui-horizon-group> </template> </div> -</div> +</ui-modal> </template> <script lang="ts"> @@ -120,14 +126,6 @@ export default Vue.extend({ if (this.user) this.canOk = false; this.$nextTick(() => { - (this.$refs.bg as any).style.pointerEvents = 'auto'; - anime({ - targets: this.$refs.bg, - opacity: 1, - duration: 100, - easing: 'linear' - }); - anime({ targets: this.$refs.main, opacity: 1, @@ -170,33 +168,27 @@ export default Vue.extend({ this.close(); }, + onBgClick() { + if (this.cancelableByBgClick) this.cancel(); + } + close() { + this.$refs.modal.close(); + }, + + onBeforeClose() { this.$el.style.pointerEvents = 'none'; - (this.$refs.bg as any).style.pointerEvents = 'none'; (this.$refs.main as any).style.pointerEvents = 'none'; - anime({ - targets: this.$refs.bg, - opacity: 0, - duration: 300, - easing: 'linear' - }); anime({ targets: this.$refs.main, opacity: 0, scale: 0.8, duration: 300, easing: 'cubicBezier(0, 0.5, 0.5, 1)', - complete: () => this.destroyDom() }); }, - onBgClick() { - if (this.cancelableByBgClick) { - this.cancel(); - } - }, - onInputKeydown(e) { if (e.which == 13) { // Enter e.preventDefault(); @@ -209,80 +201,63 @@ export default Vue.extend({ </script> <style lang="stylus" scoped> -.felqjxyj +.modal display flex align-items center justify-content center - position fixed - z-index 30000 - top 0 - left 0 - width 100% - height 100% &.splash > .main min-width 0 width initial - > .bg - display block - position fixed - top 0 - left 0 - width 100% - height 100% - background rgba(#000, 0.7) - opacity 0 - pointer-events none +.main + display block + position fixed + margin auto + padding 32px + min-width 320px + max-width 480px + width calc(100% - 32px) + text-align center + background var(--face) + color var(--faceText) + opacity 0 - > .main - display block - position fixed - margin auto - padding 32px - min-width 320px - max-width 480px - width calc(100% - 32px) - text-align center - background var(--face) - color var(--faceText) - opacity 0 + &.round + border-radius 8px - &.round - border-radius 8px + > .icon + font-size 32px - > .icon - font-size 32px + &.success + color #85da5a - &.success - color #85da5a + &.error + color #ec4137 - &.error - color #ec4137 + &.warning + color #ecb637 - &.warning - color #ecb637 + > * + display block + margin 0 auto - > * - display block - margin 0 auto - - & + header - margin-top 16px - - > header - margin 0 0 8px 0 - font-weight bold - font-size 20px - - & + .body - margin-top 8px - - > .body - margin 16px 0 0 0 - - > .buttons + & + header margin-top 16px + > header + margin 0 0 8px 0 + font-weight bold + font-size 20px + + & + .body + margin-top 8px + + > .body + margin 16px 0 0 0 + + > .buttons + margin-top 16px + </style> diff --git a/src/client/app/common/views/components/image-viewer.vue b/src/client/app/common/views/components/image-viewer.vue index 7787942ca8..63b5e28d00 100644 --- a/src/client/app/common/views/components/image-viewer.vue +++ b/src/client/app/common/views/components/image-viewer.vue @@ -1,24 +1,14 @@ <template> -<div class="dkjvrdxtkvqrwmhfickhndpmnncsgacq" v-hotkey.global="keymap"> - <div class="bg" @click="close"></div> - <img :src="image.url" :alt="image.name" :title="image.name" @click="close"/> -</div> +<ui-modal ref="modal" v-hotkey.global="keymap"> + <img :src="image.url" :alt="image.name" :title="image.name" @click="close" /> +</ui-modal> </template> <script lang="ts"> import Vue from 'vue'; -import anime from 'animejs'; export default Vue.extend({ props: ['image'], - mounted() { - anime({ - targets: this.$el, - opacity: 1, - duration: 100, - easing: 'linear' - }); - }, computed: { keymap(): any { return { @@ -28,50 +18,24 @@ export default Vue.extend({ }, methods: { close() { - anime({ - targets: this.$el, - opacity: 0, - duration: 100, - easing: 'linear', - complete: () => this.destroyDom() - }); + (this.$refs.modal as any).close(); } } }); </script> <style lang="stylus" scoped> -.dkjvrdxtkvqrwmhfickhndpmnncsgacq - display block +img position fixed - z-index 2048 + z-index 2 top 0 + right 0 + bottom 0 left 0 - width 100% - height 100% - opacity 0 - - > .bg - display block - position fixed - z-index 1 - top 0 - left 0 - width 100% - height 100% - background rgba(#000, 0.7) - - > img - position fixed - z-index 2 - top 0 - right 0 - bottom 0 - left 0 - max-width 100% - max-height 100% - margin auto - cursor zoom-out - image-orientation from-image + max-width 100% + max-height 100% + margin auto + cursor zoom-out + image-orientation from-image </style> diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts index 4253118ba8..88cd4931d4 100644 --- a/src/client/app/common/views/components/index.ts +++ b/src/client/app/common/views/components/index.ts @@ -47,6 +47,7 @@ import uiInfo from './ui/info.vue'; import uiMargin from './ui/margin.vue'; import uiHr from './ui/hr.vue'; import uiPagination from './ui/pagination.vue'; +import uiModal from './ui/modal.vue'; import formButton from './ui/form/button.vue'; import formRadio from './ui/form/radio.vue'; @@ -97,5 +98,6 @@ Vue.component('ui-info', uiInfo); Vue.component('ui-margin', uiMargin); Vue.component('ui-hr', uiHr); Vue.component('ui-pagination', uiPagination); +Vue.component('ui-modal', uiModal); Vue.component('form-button', formButton); Vue.component('form-radio', formRadio); diff --git a/src/client/app/common/views/components/ui/modal.vue b/src/client/app/common/views/components/ui/modal.vue new file mode 100644 index 0000000000..413dc39fa5 --- /dev/null +++ b/src/client/app/common/views/components/ui/modal.vue @@ -0,0 +1,80 @@ +<template> +<div class="modal"> + <div class="bg" ref="bg" @click="onBgClick" /> + <slot class="main" /> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import anime from 'animejs'; + +export default Vue.extend({ + props: { + closeOnBgClick: { + type: Boolean, + required: false, + default: true + }, + openAnimeDuration: { + type: Number, + required: false, + default: 100 + }, + closeAnimeDuration: { + type: Number, + required: false, + default: 100 + } + }, + mounted() { + anime({ + targets: this.$refs.bg, + opacity: 1, + duration: this.openAnimeDuration, + easing: 'linear' + }); + }, + methods: { + onBgClick() { + this.$emit('bg-click'); + if (this.closeOnBgClick) this.close(); + }, + close() { + this.$emit('before-close'); + + anime({ + targets: this.$refs.bg, + opacity: 0, + duration: this.closeAnimeDuration, + easing: 'linear', + complete: () => (this as any).destroyDom() + }); + } + } +}); +</script> + +<style lang="stylus" scoped> +.modal + position fixed + z-index 2048 + top 0 + left 0 + width 100% + height 100% + +.bg + display block + position fixed + z-index 1 + top 0 + left 0 + width 100% + height 100% + background rgba(#000, 0.7) + opacity 0 + +.main + z-index 1 +</style> diff --git a/src/client/app/desktop/views/components/media-video-dialog.vue b/src/client/app/desktop/views/components/media-video-dialog.vue index 803350506a..9d2d0527ef 100644 --- a/src/client/app/desktop/views/components/media-video-dialog.vue +++ b/src/client/app/desktop/views/components/media-video-dialog.vue @@ -1,23 +1,15 @@ <template> -<div class="mk-media-video-dialog" v-hotkey.global="keymap"> - <div class="bg" @click="close"></div> - <video :src="video.url" :title="video.name" controls autoplay ref="video" @volumechange="volumechange"/> -</div> +<ui-modal v-hotkey.global="keymap"> + <video :src="video.url" :title="video.name" controls autoplay ref="video" @volumechange="volumechange" /> +</ui-modal> </template> <script lang="ts"> import Vue from 'vue'; -import anime from 'animejs'; export default Vue.extend({ props: ['video', 'start'], mounted() { - anime({ - targets: this.$el, - opacity: 1, - duration: 100, - easing: 'linear' - }); const videoTag = this.$refs.video as HTMLVideoElement; if (this.start) videoTag.currentTime = this.start videoTag.volume = this.$store.state.device.mediaVolume; @@ -31,13 +23,6 @@ export default Vue.extend({ }, methods: { close() { - anime({ - targets: this.$el, - opacity: 0, - duration: 100, - easing: 'linear', - complete: () => this.destroyDom() - }); }, volumechange() { const videoTag = this.$refs.video as HTMLVideoElement; @@ -48,35 +33,15 @@ export default Vue.extend({ </script> <style lang="stylus" scoped> -.mk-media-video-dialog - display block +video position fixed - z-index 2048 + z-index 2 top 0 + right 0 + bottom 0 left 0 - width 100% - height 100% - opacity 0 - - > .bg - display block - position fixed - z-index 1 - top 0 - left 0 - width 100% - height 100% - background rgba(#000, 0.7) - - > video - position fixed - z-index 2 - top 0 - right 0 - bottom 0 - left 0 - max-width 80vw - max-height 80vh - margin auto + max-width 80vw + max-height 80vh + margin auto </style> diff --git a/src/client/app/mobile/views/components/post-form-dialog.vue b/src/client/app/mobile/views/components/post-form-dialog.vue index 716ad8fd07..4ae79dbd7b 100644 --- a/src/client/app/mobile/views/components/post-form-dialog.vue +++ b/src/client/app/mobile/views/components/post-form-dialog.vue @@ -1,6 +1,9 @@ <template> -<div class="ulveipglmagnxfgvitaxyszerjwiqmwl"> - <div class="bg" ref="bg"></div> +<ui-modal + ref="modal" + :close-on-bg-click="false" + :close-anime-duration="300" + @before-close="onBeforeClose"> <div class="main" ref="main"> <x-post-form ref="form" :reply="reply" @@ -12,7 +15,7 @@ @posted="onPosted" @cancel="onCanceled"/> </div> -</div> +</ui-modal> </template> <script lang="ts"> @@ -55,14 +58,6 @@ export default Vue.extend({ mounted() { this.$nextTick(() => { - (this.$refs.bg as any).style.pointerEvents = 'auto'; - anime({ - targets: this.$refs.bg, - opacity: 1, - duration: 100, - easing: 'linear' - }); - anime({ targets: this.$refs.main, opacity: 1, @@ -78,26 +73,22 @@ export default Vue.extend({ this.$refs.form.focus(); }, - close() { - (this.$refs.bg as any).style.pointerEvents = 'none'; - anime({ - targets: this.$refs.bg, - opacity: 0, - duration: 300, - easing: 'linear' - }); - + onBeforeClose() { (this.$refs.main as any).style.pointerEvents = 'none'; + anime({ targets: this.$refs.main, opacity: 0, translateY: 16, duration: 300, - easing: 'easeOutQuad', - complete: () => this.destroyDom() + easing: 'easeOutQuad' }); }, + close() { + (this.$refs.modal as any).close(); + }, + onPosted() { this.$emit('posted'); this.close(); @@ -112,30 +103,18 @@ export default Vue.extend({ </script> <style lang="stylus" scoped> -.ulveipglmagnxfgvitaxyszerjwiqmwl - > .bg - display block - position fixed - z-index 10000 - top 0 - left 0 - width 100% - height 100% - background rgba(#000, 0.7) - opacity 0 - pointer-events none - > .main - display block - position fixed - z-index 10000 - top 0 - left 0 - right 0 - height 100% - overflow auto - margin 0 auto 0 auto - opacity 0 - transform translateY(-16px) +.main + display block + position fixed + z-index 10000 + top 0 + left 0 + right 0 + height 100% + overflow auto + margin 0 auto 0 auto + opacity 0 + transform translateY(-16px) </style>