1
0
mirror of https://github.com/hotomoe/hotomoe synced 2024-12-12 05:38:12 +09:00

Componentize modal (#5386)

This commit is contained in:
Aya Morisawa 2019-10-29 09:51:19 +09:00 committed by syuilo
parent 34c82776fc
commit bf654c6f42
6 changed files with 188 additions and 223 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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);

View File

@ -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>

View File

@ -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>

View File

@ -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>