forked from FoundKeyGang/FoundKey
Componentize modal (#5386)
This commit is contained in:
parent
34c82776fc
commit
bf654c6f42
6 changed files with 188 additions and 223 deletions
|
@ -1,6 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="felqjxyj" :class="{ splash }">
|
<ui-modal
|
||||||
<div class="bg" ref="bg" @click="onBgClick"></div>
|
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 }">
|
<div class="main" ref="main" :class="{ round: $store.state.device.roundedCorners }">
|
||||||
<template v-if="type == 'signin'">
|
<template v-if="type == 'signin'">
|
||||||
<mk-signin/>
|
<mk-signin/>
|
||||||
|
@ -38,7 +44,7 @@
|
||||||
</ui-horizon-group>
|
</ui-horizon-group>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ui-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -120,14 +126,6 @@ export default Vue.extend({
|
||||||
if (this.user) this.canOk = false;
|
if (this.user) this.canOk = false;
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
(this.$refs.bg as any).style.pointerEvents = 'auto';
|
|
||||||
anime({
|
|
||||||
targets: this.$refs.bg,
|
|
||||||
opacity: 1,
|
|
||||||
duration: 100,
|
|
||||||
easing: 'linear'
|
|
||||||
});
|
|
||||||
|
|
||||||
anime({
|
anime({
|
||||||
targets: this.$refs.main,
|
targets: this.$refs.main,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
|
@ -170,33 +168,27 @@ export default Vue.extend({
|
||||||
this.close();
|
this.close();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onBgClick() {
|
||||||
|
if (this.cancelableByBgClick) this.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
|
this.$refs.modal.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
onBeforeClose() {
|
||||||
this.$el.style.pointerEvents = 'none';
|
this.$el.style.pointerEvents = 'none';
|
||||||
(this.$refs.bg as any).style.pointerEvents = 'none';
|
|
||||||
(this.$refs.main 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({
|
anime({
|
||||||
targets: this.$refs.main,
|
targets: this.$refs.main,
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
scale: 0.8,
|
scale: 0.8,
|
||||||
duration: 300,
|
duration: 300,
|
||||||
easing: 'cubicBezier(0, 0.5, 0.5, 1)',
|
easing: 'cubicBezier(0, 0.5, 0.5, 1)',
|
||||||
complete: () => this.destroyDom()
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onBgClick() {
|
|
||||||
if (this.cancelableByBgClick) {
|
|
||||||
this.cancel();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onInputKeydown(e) {
|
onInputKeydown(e) {
|
||||||
if (e.which == 13) { // Enter
|
if (e.which == 13) { // Enter
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -209,80 +201,63 @@ export default Vue.extend({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.felqjxyj
|
.modal
|
||||||
display flex
|
display flex
|
||||||
align-items center
|
align-items center
|
||||||
justify-content center
|
justify-content center
|
||||||
position fixed
|
|
||||||
z-index 30000
|
|
||||||
top 0
|
|
||||||
left 0
|
|
||||||
width 100%
|
|
||||||
height 100%
|
|
||||||
|
|
||||||
&.splash
|
&.splash
|
||||||
> .main
|
> .main
|
||||||
min-width 0
|
min-width 0
|
||||||
width initial
|
width initial
|
||||||
|
|
||||||
> .bg
|
.main
|
||||||
display block
|
display block
|
||||||
position fixed
|
position fixed
|
||||||
top 0
|
margin auto
|
||||||
left 0
|
padding 32px
|
||||||
width 100%
|
min-width 320px
|
||||||
height 100%
|
max-width 480px
|
||||||
background rgba(#000, 0.7)
|
width calc(100% - 32px)
|
||||||
opacity 0
|
text-align center
|
||||||
pointer-events none
|
background var(--face)
|
||||||
|
color var(--faceText)
|
||||||
|
opacity 0
|
||||||
|
|
||||||
> .main
|
&.round
|
||||||
display block
|
border-radius 8px
|
||||||
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
|
> .icon
|
||||||
border-radius 8px
|
font-size 32px
|
||||||
|
|
||||||
> .icon
|
&.success
|
||||||
font-size 32px
|
color #85da5a
|
||||||
|
|
||||||
&.success
|
&.error
|
||||||
color #85da5a
|
color #ec4137
|
||||||
|
|
||||||
&.error
|
&.warning
|
||||||
color #ec4137
|
color #ecb637
|
||||||
|
|
||||||
&.warning
|
> *
|
||||||
color #ecb637
|
display block
|
||||||
|
margin 0 auto
|
||||||
|
|
||||||
> *
|
& + header
|
||||||
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
|
|
||||||
margin-top 16px
|
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>
|
</style>
|
||||||
|
|
|
@ -1,24 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="dkjvrdxtkvqrwmhfickhndpmnncsgacq" v-hotkey.global="keymap">
|
<ui-modal ref="modal" v-hotkey.global="keymap">
|
||||||
<div class="bg" @click="close"></div>
|
<img :src="image.url" :alt="image.name" :title="image.name" @click="close" />
|
||||||
<img :src="image.url" :alt="image.name" :title="image.name" @click="close"/>
|
</ui-modal>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import anime from 'animejs';
|
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: ['image'],
|
props: ['image'],
|
||||||
mounted() {
|
|
||||||
anime({
|
|
||||||
targets: this.$el,
|
|
||||||
opacity: 1,
|
|
||||||
duration: 100,
|
|
||||||
easing: 'linear'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
keymap(): any {
|
keymap(): any {
|
||||||
return {
|
return {
|
||||||
|
@ -28,50 +18,24 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
close() {
|
close() {
|
||||||
anime({
|
(this.$refs.modal as any).close();
|
||||||
targets: this.$el,
|
|
||||||
opacity: 0,
|
|
||||||
duration: 100,
|
|
||||||
easing: 'linear',
|
|
||||||
complete: () => this.destroyDom()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.dkjvrdxtkvqrwmhfickhndpmnncsgacq
|
img
|
||||||
display block
|
|
||||||
position fixed
|
position fixed
|
||||||
z-index 2048
|
z-index 2
|
||||||
top 0
|
top 0
|
||||||
|
right 0
|
||||||
|
bottom 0
|
||||||
left 0
|
left 0
|
||||||
width 100%
|
max-width 100%
|
||||||
height 100%
|
max-height 100%
|
||||||
opacity 0
|
margin auto
|
||||||
|
cursor zoom-out
|
||||||
> .bg
|
image-orientation from-image
|
||||||
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
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -47,6 +47,7 @@ import uiInfo from './ui/info.vue';
|
||||||
import uiMargin from './ui/margin.vue';
|
import uiMargin from './ui/margin.vue';
|
||||||
import uiHr from './ui/hr.vue';
|
import uiHr from './ui/hr.vue';
|
||||||
import uiPagination from './ui/pagination.vue';
|
import uiPagination from './ui/pagination.vue';
|
||||||
|
import uiModal from './ui/modal.vue';
|
||||||
import formButton from './ui/form/button.vue';
|
import formButton from './ui/form/button.vue';
|
||||||
import formRadio from './ui/form/radio.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-margin', uiMargin);
|
||||||
Vue.component('ui-hr', uiHr);
|
Vue.component('ui-hr', uiHr);
|
||||||
Vue.component('ui-pagination', uiPagination);
|
Vue.component('ui-pagination', uiPagination);
|
||||||
|
Vue.component('ui-modal', uiModal);
|
||||||
Vue.component('form-button', formButton);
|
Vue.component('form-button', formButton);
|
||||||
Vue.component('form-radio', formRadio);
|
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>
|
<template>
|
||||||
<div class="mk-media-video-dialog" v-hotkey.global="keymap">
|
<ui-modal v-hotkey.global="keymap">
|
||||||
<div class="bg" @click="close"></div>
|
<video :src="video.url" :title="video.name" controls autoplay ref="video" @volumechange="volumechange" />
|
||||||
<video :src="video.url" :title="video.name" controls autoplay ref="video" @volumechange="volumechange"/>
|
</ui-modal>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import anime from 'animejs';
|
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: ['video', 'start'],
|
props: ['video', 'start'],
|
||||||
mounted() {
|
mounted() {
|
||||||
anime({
|
|
||||||
targets: this.$el,
|
|
||||||
opacity: 1,
|
|
||||||
duration: 100,
|
|
||||||
easing: 'linear'
|
|
||||||
});
|
|
||||||
const videoTag = this.$refs.video as HTMLVideoElement;
|
const videoTag = this.$refs.video as HTMLVideoElement;
|
||||||
if (this.start) videoTag.currentTime = this.start
|
if (this.start) videoTag.currentTime = this.start
|
||||||
videoTag.volume = this.$store.state.device.mediaVolume;
|
videoTag.volume = this.$store.state.device.mediaVolume;
|
||||||
|
@ -31,13 +23,6 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
close() {
|
close() {
|
||||||
anime({
|
|
||||||
targets: this.$el,
|
|
||||||
opacity: 0,
|
|
||||||
duration: 100,
|
|
||||||
easing: 'linear',
|
|
||||||
complete: () => this.destroyDom()
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
volumechange() {
|
volumechange() {
|
||||||
const videoTag = this.$refs.video as HTMLVideoElement;
|
const videoTag = this.$refs.video as HTMLVideoElement;
|
||||||
|
@ -48,35 +33,15 @@ export default Vue.extend({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.mk-media-video-dialog
|
video
|
||||||
display block
|
|
||||||
position fixed
|
position fixed
|
||||||
z-index 2048
|
z-index 2
|
||||||
top 0
|
top 0
|
||||||
|
right 0
|
||||||
|
bottom 0
|
||||||
left 0
|
left 0
|
||||||
width 100%
|
max-width 80vw
|
||||||
height 100%
|
max-height 80vh
|
||||||
opacity 0
|
margin auto
|
||||||
|
|
||||||
> .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
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="ulveipglmagnxfgvitaxyszerjwiqmwl">
|
<ui-modal
|
||||||
<div class="bg" ref="bg"></div>
|
ref="modal"
|
||||||
|
:close-on-bg-click="false"
|
||||||
|
:close-anime-duration="300"
|
||||||
|
@before-close="onBeforeClose">
|
||||||
<div class="main" ref="main">
|
<div class="main" ref="main">
|
||||||
<x-post-form ref="form"
|
<x-post-form ref="form"
|
||||||
:reply="reply"
|
:reply="reply"
|
||||||
|
@ -12,7 +15,7 @@
|
||||||
@posted="onPosted"
|
@posted="onPosted"
|
||||||
@cancel="onCanceled"/>
|
@cancel="onCanceled"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ui-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -55,14 +58,6 @@ export default Vue.extend({
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
(this.$refs.bg as any).style.pointerEvents = 'auto';
|
|
||||||
anime({
|
|
||||||
targets: this.$refs.bg,
|
|
||||||
opacity: 1,
|
|
||||||
duration: 100,
|
|
||||||
easing: 'linear'
|
|
||||||
});
|
|
||||||
|
|
||||||
anime({
|
anime({
|
||||||
targets: this.$refs.main,
|
targets: this.$refs.main,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
|
@ -78,26 +73,22 @@ export default Vue.extend({
|
||||||
this.$refs.form.focus();
|
this.$refs.form.focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
close() {
|
onBeforeClose() {
|
||||||
(this.$refs.bg as any).style.pointerEvents = 'none';
|
|
||||||
anime({
|
|
||||||
targets: this.$refs.bg,
|
|
||||||
opacity: 0,
|
|
||||||
duration: 300,
|
|
||||||
easing: 'linear'
|
|
||||||
});
|
|
||||||
|
|
||||||
(this.$refs.main as any).style.pointerEvents = 'none';
|
(this.$refs.main as any).style.pointerEvents = 'none';
|
||||||
|
|
||||||
anime({
|
anime({
|
||||||
targets: this.$refs.main,
|
targets: this.$refs.main,
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
translateY: 16,
|
translateY: 16,
|
||||||
duration: 300,
|
duration: 300,
|
||||||
easing: 'easeOutQuad',
|
easing: 'easeOutQuad'
|
||||||
complete: () => this.destroyDom()
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
close() {
|
||||||
|
(this.$refs.modal as any).close();
|
||||||
|
},
|
||||||
|
|
||||||
onPosted() {
|
onPosted() {
|
||||||
this.$emit('posted');
|
this.$emit('posted');
|
||||||
this.close();
|
this.close();
|
||||||
|
@ -112,30 +103,18 @@ export default Vue.extend({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<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
|
.main
|
||||||
display block
|
display block
|
||||||
position fixed
|
position fixed
|
||||||
z-index 10000
|
z-index 10000
|
||||||
top 0
|
top 0
|
||||||
left 0
|
left 0
|
||||||
right 0
|
right 0
|
||||||
height 100%
|
height 100%
|
||||||
overflow auto
|
overflow auto
|
||||||
margin 0 auto 0 auto
|
margin 0 auto 0 auto
|
||||||
opacity 0
|
opacity 0
|
||||||
transform translateY(-16px)
|
transform translateY(-16px)
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue