diff options
| author | かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> | 2024-03-06 21:08:42 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-06 21:08:42 +0900 |
| commit | 7ead98cbe592e6911e4a54550cb7bb507e782d7c (patch) | |
| tree | 8a8c57c5dda5d6971da212a63e46954ef212a5b0 /packages/frontend/src | |
| parent | Revert "perf: boot.jsの調整" (diff) | |
| download | misskey-7ead98cbe592e6911e4a54550cb7bb507e782d7c.tar.gz misskey-7ead98cbe592e6911e4a54550cb7bb507e782d7c.tar.bz2 misskey-7ead98cbe592e6911e4a54550cb7bb507e782d7c.zip | |
enhance(frontend): リアクションの総数を表示するように (#13532)
* enhance(frontend): リアクションの総数を表示するように
* Update Changelog
* リアクション選択済の色をaccentに
Diffstat (limited to 'packages/frontend/src')
8 files changed, 66 insertions, 29 deletions
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 03a283cab3..656ccc7959 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -93,7 +93,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA> </div> - <MkReactionsViewer :note="appearNote" :maxNumber="16" @mockUpdateMyReaction="emitUpdReaction"> + <MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" :note="appearNote" :maxNumber="16" @mockUpdateMyReaction="emitUpdReaction"> <template #more> <div :class="$style.reactionOmitted">{{ i18n.ts.more }}</div> </template> @@ -101,7 +101,7 @@ SPDX-License-Identifier: AGPL-3.0-only <footer :class="$style.footer"> <button :class="$style.footerButton" class="_button" @click="reply()"> <i class="ti ti-arrow-back-up"></i> - <p v-if="appearNote.repliesCount > 0" :class="$style.footerButtonCount">{{ appearNote.repliesCount }}</p> + <p v-if="appearNote.repliesCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.repliesCount) }}</p> </button> <button v-if="canRenote" @@ -111,17 +111,17 @@ SPDX-License-Identifier: AGPL-3.0-only @mousedown="renote()" > <i class="ti ti-repeat"></i> - <p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ appearNote.renoteCount }}</p> + <p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.renoteCount) }}</p> </button> <button v-else :class="$style.footerButton" class="_button" disabled> <i class="ti ti-ban"></i> </button> - <button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.footerButton" class="_button" @mousedown="react()"> - <i v-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i> + <button ref="reactButton" :class="$style.footerButton" class="_button" @click="toggleReact()"> + <i v-if="appearNote.reactionAcceptance === 'likeOnly' && appearNote.myReaction != null" class="ti ti-heart-filled" style="color: var(--eventReactionHeart);"></i> + <i v-else-if="appearNote.myReaction != null" class="ti ti-minus" style="color: var(--accent);"></i> + <i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i> <i v-else class="ti ti-plus"></i> - </button> - <button v-if="appearNote.myReaction != null" ref="reactButton" :class="$style.footerButton" class="_button" @click="undoReact(appearNote)"> - <i class="ti ti-minus"></i> + <p v-if="appearNote.reactionCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.reactionCount) }}</p> </button> <button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" :class="$style.footerButton" class="_button" @mousedown="clip()"> <i class="ti ti-paperclip"></i> @@ -175,6 +175,7 @@ import { pleaseLogin } from '@/scripts/please-login.js'; import { focusPrev, focusNext } from '@/scripts/focus.js'; import { checkWordMute } from '@/scripts/check-word-mute.js'; import { userPage } from '@/filters/user.js'; +import number from '@/filters/number.js'; import * as os from '@/os.js'; import * as sound from '@/scripts/sound.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; @@ -420,6 +421,14 @@ function undoReact(targetNote: Misskey.entities.Note): void { }); } +function toggleReact() { + if (appearNote.value.myReaction == null) { + react(); + } else { + undoReact(appearNote.value); + } +} + function onContextmenu(ev: MouseEvent): void { if (props.mock) { return; diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index e3ef14120f..2d2930ee7c 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -106,10 +106,10 @@ SPDX-License-Identifier: AGPL-3.0-only <MkTime :time="appearNote.createdAt" mode="detail" colored/> </MkA> </div> - <MkReactionsViewer ref="reactionsViewer" :note="appearNote"/> + <MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" ref="reactionsViewer" :note="appearNote"/> <button class="_button" :class="$style.noteFooterButton" @click="reply()"> <i class="ti ti-arrow-back-up"></i> - <p v-if="appearNote.repliesCount > 0" :class="$style.noteFooterButtonCount">{{ appearNote.repliesCount }}</p> + <p v-if="appearNote.repliesCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.repliesCount) }}</p> </button> <button v-if="canRenote" @@ -119,17 +119,17 @@ SPDX-License-Identifier: AGPL-3.0-only @mousedown="renote()" > <i class="ti ti-repeat"></i> - <p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ appearNote.renoteCount }}</p> + <p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.renoteCount) }}</p> </button> <button v-else class="_button" :class="$style.noteFooterButton" disabled> <i class="ti ti-ban"></i> </button> - <button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.noteFooterButton" class="_button" @mousedown="react()"> - <i v-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i> + <button ref="reactButton" :class="$style.noteFooterButton" class="_button" @click="toggleReact()"> + <i v-if="appearNote.reactionAcceptance === 'likeOnly' && appearNote.myReaction != null" class="ti ti-heart-filled" style="color: var(--eventReactionHeart);"></i> + <i v-else-if="appearNote.myReaction != null" class="ti ti-minus" style="color: var(--accent);"></i> + <i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i> <i v-else class="ti ti-plus"></i> - </button> - <button v-if="appearNote.myReaction != null" ref="reactButton" class="_button" :class="[$style.noteFooterButton, $style.reacted]" @click="undoReact(appearNote)"> - <i class="ti ti-minus"></i> + <p v-if="appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.reactionCount) }}</p> </button> <button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown="clip()"> <i class="ti ti-paperclip"></i> @@ -209,6 +209,7 @@ import { pleaseLogin } from '@/scripts/please-login.js'; import { checkWordMute } from '@/scripts/check-word-mute.js'; import { userPage } from '@/filters/user.js'; import { notePage } from '@/filters/note.js'; +import number from '@/filters/number.js'; import * as os from '@/os.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import * as sound from '@/scripts/sound.js'; @@ -401,14 +402,22 @@ function react(viaKeyboard = false): void { } } -function undoReact(note): void { - const oldReaction = note.myReaction; +function undoReact(targetNote: Misskey.entities.Note): void { + const oldReaction = targetNote.myReaction; if (!oldReaction) return; misskeyApi('notes/reactions/delete', { - noteId: note.id, + noteId: targetNote.id, }); } +function toggleReact() { + if (appearNote.value.myReaction == null) { + react(); + } else { + undoReact(appearNote.value); + } +} + function onContextmenu(ev: MouseEvent): void { const isLink = (el: HTMLElement): boolean => { if (el.tagName === 'A') return true; diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index 322b9400be..0d3a5c13ba 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -8,6 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.head"> <MkAvatar v-if="['pollEnded', 'note'].includes(notification.type) && notification.note" :class="$style.icon" :user="notification.note.user" link preview/> <MkAvatar v-else-if="['roleAssigned', 'achievementEarned'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/> + <div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ti ti-heart" style="line-height: 1;"></i></div> <div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ti ti-plus" style="line-height: 1;"></i></div> <div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div> <img v-else-if="notification.type === 'test'" :class="$style.icon" :src="infoImageUrl"/> @@ -57,6 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only <span v-else-if="notification.type === 'achievementEarned'">{{ i18n.ts._notification.achievementEarned }}</span> <span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span> <MkA v-else-if="notification.type === 'follow' || notification.type === 'mention' || notification.type === 'reply' || notification.type === 'renote' || notification.type === 'quote' || notification.type === 'reaction' || notification.type === 'receiveFollowRequest' || notification.type === 'followRequestAccepted'" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA> + <span v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'">{{ i18n.tsx._notification.likedBySomeUsers({ n: notification.reactions.length }) }}</span> <span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: notification.reactions.length }) }}</span> <span v-else-if="notification.type === 'renote:grouped'">{{ i18n.tsx._notification.renotedBySomeUsers({ n: notification.users.length }) }}</span> <span v-else-if="notification.type === 'app'">{{ notification.header }}</span> @@ -201,6 +203,7 @@ const rejectFollowRequest = () => { } .icon_reactionGroup, +.icon_reactionGroupHeart, .icon_renoteGroup { display: grid; align-items: center; @@ -213,11 +216,15 @@ const rejectFollowRequest = () => { } .icon_reactionGroup { - background: #e99a0b; + background: var(--eventReaction); +} + +.icon_reactionGroupHeart { + background: var(--eventReactionHeart); } .icon_renoteGroup { - background: #36d298; + background: var(--eventRenote); } .icon_app { @@ -246,49 +253,49 @@ const rejectFollowRequest = () => { .t_follow, .t_followRequestAccepted, .t_receiveFollowRequest { padding: 3px; - background: #36aed2; + background: var(--eventFollow); pointer-events: none; } .t_renote { padding: 3px; - background: #36d298; + background: var(--eventRenote); pointer-events: none; } .t_quote { padding: 3px; - background: #36d298; + background: var(--eventRenote); pointer-events: none; } .t_reply { padding: 3px; - background: #007aff; + background: var(--eventReply); pointer-events: none; } .t_mention { padding: 3px; - background: #88a6b7; + background: var(--eventOther); pointer-events: none; } .t_pollEnded { padding: 3px; - background: #88a6b7; + background: var(--eventOther); pointer-events: none; } .t_achievementEarned { padding: 3px; - background: #cb9a11; + background: var(--eventAchievement); pointer-events: none; } .t_roleAssigned { padding: 3px; - background: #88a6b7; + background: var(--eventOther); pointer-events: none; } diff --git a/packages/frontend/src/components/MkTutorialDialog.Note.vue b/packages/frontend/src/components/MkTutorialDialog.Note.vue index f03a83293b..2a26d22dc2 100644 --- a/packages/frontend/src/components/MkTutorialDialog.Note.vue +++ b/packages/frontend/src/components/MkTutorialDialog.Note.vue @@ -63,6 +63,7 @@ const exampleNote = reactive<Misskey.entities.Note>({ reactionAcceptance: null, renoteCount: 0, repliesCount: 1, + reactionCount: 0, reactions: {}, reactionEmojis: {}, fileIds: [], diff --git a/packages/frontend/src/components/MkTutorialDialog.PostNote.vue b/packages/frontend/src/components/MkTutorialDialog.PostNote.vue index 2b8c586dac..e1d88b5e5c 100644 --- a/packages/frontend/src/components/MkTutorialDialog.PostNote.vue +++ b/packages/frontend/src/components/MkTutorialDialog.PostNote.vue @@ -68,6 +68,7 @@ const exampleCWNote = reactive<Misskey.entities.Note>({ reactionAcceptance: null, renoteCount: 0, repliesCount: 1, + reactionCount: 0, reactions: {}, reactionEmojis: {}, fileIds: [], diff --git a/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue b/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue index b17ec66461..7ae48dcd15 100644 --- a/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue +++ b/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue @@ -58,6 +58,7 @@ const exampleNote = reactive<Misskey.entities.Note>({ reactionAcceptance: null, renoteCount: 0, repliesCount: 1, + reactionCount: 0, reactions: {}, reactionEmojis: {}, fileIds: ['0000000002'], diff --git a/packages/frontend/src/scripts/use-note-capture.ts b/packages/frontend/src/scripts/use-note-capture.ts index 524ac5d3fe..542d8ab52b 100644 --- a/packages/frontend/src/scripts/use-note-capture.ts +++ b/packages/frontend/src/scripts/use-note-capture.ts @@ -35,6 +35,7 @@ export function useNoteCapture(props: { const currentCount = (note.value.reactions || {})[reaction] || 0; note.value.reactions[reaction] = currentCount + 1; + note.value.reactionCount += 1; if ($i && (body.userId === $i.id)) { note.value.myReaction = reaction; @@ -49,6 +50,7 @@ export function useNoteCapture(props: { const currentCount = (note.value.reactions || {})[reaction] || 0; note.value.reactions[reaction] = Math.max(0, currentCount - 1); + note.value.reactionCount = Math.max(0, note.value.reactionCount - 1); if (note.value.reactions[reaction] === 0) delete note.value.reactions[reaction]; if ($i && (body.userId === $i.id)) { diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss index 0951a7d98d..187d902733 100644 --- a/packages/frontend/src/style.scss +++ b/packages/frontend/src/style.scss @@ -22,6 +22,13 @@ } //--ad: rgb(255 169 0 / 10%); + --eventFollow: #36aed2; + --eventRenote: #36d298; + --eventReply: #007aff; + --eventReactionHeart: #dd2e44; + --eventReaction: #e99a0b; + --eventAchievement: #cb9a11; + --eventOther: #88a6b7; } ::selection { |