mirror of
https://github.com/hotomoe/hotomoe
synced 2024-12-12 05:38:12 +09:00
Componentize modal (#5386)
This commit is contained in:
parent
34c82776fc
commit
bf654c6f42
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
80
src/client/app/common/views/components/ui/modal.vue
Normal file
80
src/client/app/common/views/components/ui/modal.vue
Normal 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>
|
@ -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>
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user