diff options
| author | MeiMei <30769358+mei23@users.noreply.github.com> | 2019-02-07 02:05:49 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2019-02-07 02:05:49 +0900 |
| commit | d5205d7328be91aefa3e692c127c586b4445dbad (patch) | |
| tree | d44249a79c34a0c9891a0b8a9af854ef91bfe698 /src | |
| parent | リアクションマージン再調整 (#4169) (diff) | |
| download | misskey-d5205d7328be91aefa3e692c127c586b4445dbad.tar.gz misskey-d5205d7328be91aefa3e692c127c586b4445dbad.tar.bz2 misskey-d5205d7328be91aefa3e692c127c586b4445dbad.zip | |
Refactor reaction-viewer (#4171)
* Refactor reaction-viewer
* code style
* fix
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/app/common/views/components/reactions-viewer.reaction.vue | 147 | ||||
| -rw-r--r-- | src/client/app/common/views/components/reactions-viewer.vue | 150 |
2 files changed, 154 insertions, 143 deletions
diff --git a/src/client/app/common/views/components/reactions-viewer.reaction.vue b/src/client/app/common/views/components/reactions-viewer.reaction.vue new file mode 100644 index 0000000000..b7c321fc9f --- /dev/null +++ b/src/client/app/common/views/components/reactions-viewer.reaction.vue @@ -0,0 +1,147 @@ +<template> +<span + class="reaction" + :class="{ reacted: note.myReaction == reaction }" + @click="toggleReaction(reaction)" + v-if="count > 0" + v-particle="!isMe" +> + <mk-reaction-icon :reaction="reaction" ref="icon"/> + <span>{{ count }}</span> +</span> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import Icon from './reaction-icon.vue'; +import anime from 'animejs'; + +export default Vue.extend({ + props: { + reaction: { + type: String, + required: true, + }, + count: { + type: Number, + required: true, + }, + note: { + type: Object, + required: true, + }, + canToggle: { + type: Boolean, + required: false, + default: true, + }, + }, + computed: { + isMe(): boolean { + return this.$store.getters.isSignedIn && this.$store.state.i.id === this.note.userId; + }, + }, + watch: { + count() { + this.anime(); + }, + }, + methods: { + toggleReaction() { + if (this.isMe) return; + if (!this.canToggle) return; + + const oldReaction = this.note.myReaction; + if (oldReaction) { + this.$root.api('notes/reactions/delete', { + noteId: this.note.id + }).then(() => { + if (oldReaction !== this.reaction) { + this.$root.api('notes/reactions/create', { + noteId: this.note.id, + reaction: this.reaction + }); + } + }); + } else { + this.$root.api('notes/reactions/create', { + noteId: this.note.id, + reaction: this.reaction + }); + } + }, + anime() { + if (this.$store.state.device.reduceMotion) return; + if (document.hidden) return; + + this.$nextTick(() => { + const rect = this.$refs.icon.$el.getBoundingClientRect(); + + const x = rect.left; + const y = rect.top; + + const icon = new Icon({ + parent: this, + propsData: { + reaction: this.reaction + } + }).$mount(); + + icon.$el.style.position = 'absolute'; + icon.$el.style.zIndex = 100; + icon.$el.style.top = (y + window.scrollY) + 'px'; + icon.$el.style.left = (x + window.scrollX) + 'px'; + icon.$el.style.fontSize = window.getComputedStyle(this.$refs.icon.$el).fontSize; + + document.body.appendChild(icon.$el); + + anime({ + targets: icon.$el, + opacity: [1, 0], + translateY: [0, -64], + duration: 1000, + easing: 'linear', + complete: () => { + icon.destroyDom(); + } + }); + }); + }, + } +}); +</script> + +<style lang="stylus" scoped> +.reaction + display inline-block + height 32px + margin 2px + padding 0 6px + border-radius 4px + cursor pointer + + * + user-select none + pointer-events none + + &.reacted + background var(--primary) + + > span + color var(--primaryForeground) + + &:not(.reacted) + background var(--reactionViewerButtonBg) + + &:hover + background var(--reactionViewerButtonHoverBg) + + > .mk-reaction-icon + font-size 1.4em + + > span + font-size 1.1em + line-height 32px + vertical-align middle + color var(--text) +</style> diff --git a/src/client/app/common/views/components/reactions-viewer.vue b/src/client/app/common/views/components/reactions-viewer.vue index 32a27cbb69..cf7f88b2f5 100644 --- a/src/client/app/common/views/components/reactions-viewer.vue +++ b/src/client/app/common/views/components/reactions-viewer.vue @@ -1,133 +1,31 @@ <template> <div class="mk-reactions-viewer" :class="{ isMe }"> - <template v-if="reactions"> - <span :class="{ reacted: note.myReaction == 'like' }" @click="toggleReaction('like')" v-if="reactions.like" v-particle="!isMe"><mk-reaction-icon reaction="like" ref="like"/><span>{{ reactions.like }}</span></span> - <span :class="{ reacted: note.myReaction == 'love' }" @click="toggleReaction('love')" v-if="reactions.love" v-particle="!isMe"><mk-reaction-icon reaction="love" ref="love"/><span>{{ reactions.love }}</span></span> - <span :class="{ reacted: note.myReaction == 'laugh' }" @click="toggleReaction('laugh')" v-if="reactions.laugh" v-particle="!isMe"><mk-reaction-icon reaction="laugh" ref="laugh"/><span>{{ reactions.laugh }}</span></span> - <span :class="{ reacted: note.myReaction == 'hmm' }" @click="toggleReaction('hmm')" v-if="reactions.hmm" v-particle="!isMe"><mk-reaction-icon reaction="hmm" ref="hmm"/><span>{{ reactions.hmm }}</span></span> - <span :class="{ reacted: note.myReaction == 'surprise' }" @click="toggleReaction('surprise')" v-if="reactions.surprise" v-particle="!isMe"><mk-reaction-icon reaction="surprise" ref="surprise"/><span>{{ reactions.surprise }}</span></span> - <span :class="{ reacted: note.myReaction == 'congrats' }" @click="toggleReaction('congrats')" v-if="reactions.congrats" v-particle="!isMe"><mk-reaction-icon reaction="congrats" ref="congrats"/><span>{{ reactions.congrats }}</span></span> - <span :class="{ reacted: note.myReaction == 'angry' }" @click="toggleReaction('angry')" v-if="reactions.angry" v-particle="!isMe"><mk-reaction-icon reaction="angry" ref="angry"/><span>{{ reactions.angry }}</span></span> - <span :class="{ reacted: note.myReaction == 'confused' }" @click="toggleReaction('confused')" v-if="reactions.confused" v-particle="!isMe"><mk-reaction-icon reaction="confused" ref="confused"/><span>{{ reactions.confused }}</span></span> - <span :class="{ reacted: note.myReaction == 'rip' }" @click="toggleReaction('rip')" v-if="reactions.rip" v-particle="!isMe"><mk-reaction-icon reaction="rip" ref="rip"/><span>{{ reactions.rip }}</span></span> - <span :class="{ reacted: note.myReaction == 'pudding' }" @click="toggleReaction('pudding')" v-if="reactions.pudding" v-particle="!isMe"><mk-reaction-icon reaction="pudding" ref="pudding"/><span>{{ reactions.pudding }}</span></span> - </template> + <x-reaction v-for="(count, reaction) in reactions" :reaction="reaction" :count="count" :note="note" :key="reaction"/> </div> </template> <script lang="ts"> import Vue from 'vue'; -import Icon from './reaction-icon.vue'; -import anime from 'animejs'; +import XReaction from './reactions-viewer.reaction.vue'; export default Vue.extend({ + components: { + XReaction + }, props: { note: { type: Object, required: true - } + }, }, computed: { reactions(): any { return this.note.reactionCounts; }, isMe(): boolean { - return this.$store.getters.isSignedIn && (this.$store.state.i.id === this.note.userId); - } - }, - watch: { - 'reactions.like'() { - this.anime('like'); - }, - 'reactions.love'() { - this.anime('love'); - }, - 'reactions.laugh'() { - this.anime('laugh'); - }, - 'reactions.hmm'() { - this.anime('hmm'); - }, - 'reactions.surprise'() { - this.anime('surprise'); - }, - 'reactions.congrats'() { - this.anime('congrats'); + return this.$store.getters.isSignedIn && this.$store.state.i.id === this.note.userId; }, - 'reactions.angry'() { - this.anime('angry'); - }, - 'reactions.confused'() { - this.anime('confused'); - }, - 'reactions.rip'() { - this.anime('rip'); - }, - 'reactions.pudding'() { - this.anime('pudding'); - } }, - methods: { - toggleReaction(reaction: string) { - if (this.isMe) return; - - const oldReaction = this.note.myReaction; - if (oldReaction) { - this.$root.api('notes/reactions/delete', { - noteId: this.note.id - }).then(() => { - if (oldReaction !== reaction) { - this.$root.api('notes/reactions/create', { - noteId: this.note.id, - reaction: reaction - }); - } - }); - } else { - this.$root.api('notes/reactions/create', { - noteId: this.note.id, - reaction: reaction - }); - } - }, - anime(reaction: string) { - if (this.$store.state.device.reduceMotion) return; - if (document.hidden) return; - - this.$nextTick(() => { - const rect = this.$refs[reaction].$el.getBoundingClientRect(); - - const x = rect.left; - const y = rect.top; - - const icon = new Icon({ - parent: this, - propsData: { - reaction: reaction - } - }).$mount(); - - icon.$el.style.position = 'absolute'; - icon.$el.style.zIndex = 100; - icon.$el.style.top = (y + window.scrollY) + 'px'; - icon.$el.style.left = (x + window.scrollX) + 'px'; - icon.$el.style.fontSize = window.getComputedStyle(this.$refs[reaction].$el).fontSize; - - document.body.appendChild(icon.$el); - - anime({ - targets: icon.$el, - opacity: [1, 0], - translateY: [0, -64], - duration: 1000, - easing: 'linear', - complete: () => { - icon.destroyDom(); - } - }); - }); - } - } }); </script> @@ -144,38 +42,4 @@ export default Vue.extend({ &:hover background var(--reactionViewerButtonBg) !important - - > span - display inline-block - height 32px - margin 2px - padding 0 6px - border-radius 4px - cursor pointer - - * - user-select none - pointer-events none - - &.reacted - background var(--primary) - - > span - color var(--primaryForeground) - - &:not(.reacted) - background var(--reactionViewerButtonBg) - - &:hover - background var(--reactionViewerButtonHoverBg) - - > .mk-reaction-icon - font-size 1.4em - - > span - font-size 1.1em - line-height 32px - vertical-align middle - color var(--text) - </style> |