diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index ebc41b067..e5a37fdc2 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -413,6 +413,10 @@ common/views/pages/explore.vue: explore: "{host}を探索" users-info: "現在{users}ユーザーが登録されています" +common/views/components/reactions-viewer.details.vue: + few-users: "{users}が{reaction}をリアクション" + many-users: "{users}と他{omitted}人が{reaction}をリアクション" + common/views/components/url-preview.vue: enable-player: "プレイヤーを開く" disable-player: "プレイヤーを閉じる" diff --git a/src/client/app/common/views/components/reactions-viewer.details.vue b/src/client/app/common/views/components/reactions-viewer.details.vue new file mode 100644 index 000000000..27eb860d5 --- /dev/null +++ b/src/client/app/common/views/components/reactions-viewer.details.vue @@ -0,0 +1,103 @@ + + + + + {{ users.join(', ') }} + + + + {{ users.slice(0, 10).join(', ') }} + {{ users.length - 10 }} + + + + + + + + + diff --git a/src/client/app/common/views/components/reactions-viewer.reaction.vue b/src/client/app/common/views/components/reactions-viewer.reaction.vue index 02ee87b09..5bb9a9522 100644 --- a/src/client/app/common/views/components/reactions-viewer.reaction.vue +++ b/src/client/app/common/views/components/reactions-viewer.reaction.vue @@ -5,6 +5,9 @@ @click="toggleReaction(reaction)" v-if="count > 0" v-particle="!isMe" + @mouseover="onMouseover" + @mouseleave="onMouseleave" + ref="reaction" > {{ count }} @@ -15,6 +18,7 @@ import Vue from 'vue'; import Icon from './reaction-icon.vue'; import anime from 'animejs'; +import XDetails from './reactions-viewer.details.vue'; export default Vue.extend({ props: { @@ -40,6 +44,12 @@ export default Vue.extend({ default: true, }, }, + data() { + return { + details: null, + detailsTimeoutId: null + }; + }, computed: { isMe(): boolean { return this.$store.getters.isSignedIn && this.$store.state.i.id === this.note.userId; @@ -51,6 +61,7 @@ export default Vue.extend({ watch: { count(newCount, oldCount) { if (oldCount < newCount) this.anime(); + if (this.details != null) this.openDetails(); }, }, methods: { @@ -77,6 +88,35 @@ export default Vue.extend({ }); } }, + onMouseover() { + this.detailsTimeoutId = setTimeout(this.openDetails, 300); + }, + onMouseleave() { + clearTimeout(this.detailsTimeoutId); + this.closeDetails(); + }, + openDetails() { + this.$root.api('notes/reactions', { + noteId: this.note.id + }).then((reactions: any[]) => { + const users = reactions.filter(x => x.type === this.reaction) + .sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()) + .map(x => x.user.username); + + this.closeDetails(); + this.details = this.$root.new(XDetails, { + reaction: this.reaction, + users, + source: this.$refs.reaction + }); + }); + }, + closeDetails() { + if (this.details != null) { + this.details.close(); + this.details = null; + } + }, anime() { if (this.$store.state.device.reduceMotion) return; if (document.hidden) return;