From 6f33be6c75866bc40cdfc95beb8ba6e1714f1e42 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Sat, 11 Feb 2023 13:05:36 +0900 Subject: [PATCH] =?UTF-8?q?enhance(client):=20MkNote=E3=81=AE=E3=83=AA?= =?UTF-8?q?=E3=82=A2=E3=82=AF=E3=82=B7=E3=83=A7=E3=83=B3=E3=81=AE=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E6=95=B0=E3=81=AF16=E3=81=AB=E5=88=B6=E9=99=90=20(#98?= =?UTF-8?q?41)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance(client): MkNoteのリアクションの表示数は16に制限・リアクションの横の?ボタンでリアクション詳細 * info-circleにする * - Layout Shiftが起こらないように - 自分のリアクションは必ずつける * https://github.com/misskey-dev/misskey/pull/9841#issuecomment-1423786235 * remove logger * refactor * refactor Co-authored-by: acid-chicken <root@acid-chicken.com> * Revert "https://github.com/misskey-dev/misskey/pull/9841#issuecomment-1423786235" This reverts commit ec1315b1fb207e0c5b2a5f2f4a00de7379c7a29b. * wip * wip * :art: * fix * fix * fix * :art: * wip * remove extras from MkNoteDetailed * もっと! * no v-if * dashed --------- Co-authored-by: acid-chicken <root@acid-chicken.com> --- packages/frontend/src/components/MkNote.vue | 35 +++++++++++-- .../components/MkReactionsViewer.reaction.vue | 2 +- .../src/components/MkReactionsViewer.vue | 51 ++++++++++++++++--- 3 files changed, 76 insertions(+), 12 deletions(-) diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index d830e0e47..e910fbab0 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -5,7 +5,7 @@ ref="el" v-hotkey="keymap" :class="$style.root" - :tabindex="!isDeleted ? '-1' : null" + :tabindex="!isDeleted ? '-1' : undefined" > <MkNoteSub v-if="appearNote.reply && !renoteCollapsed" :note="appearNote.reply" :class="$style.replyTo"/> <div v-if="pinned" :class="$style.tip"><i class="ti ti-pin"></i> {{ i18n.ts.pinnedNote }}</div> @@ -77,7 +77,13 @@ <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> <footer :class="$style.footer"> - <MkReactionsViewer :note="appearNote"/> + <MkReactionsViewer :note="appearNote" :max-number="16"> + <template v-slot:more> + <button class="_button" :class="$style.reactionDetailsButton" @click="showReactions"> + {{ i18n.ts.more }} + </button> + </template> + </MkReactionsViewer> <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> @@ -120,7 +126,7 @@ </template> <script lang="ts" setup> -import { computed, inject, onMounted, onUnmounted, reactive, ref, shallowRef, Ref } from 'vue'; +import { computed, inject, onMounted, onUnmounted, reactive, ref, shallowRef, Ref, defineAsyncComponent } from 'vue'; import * as mfm from 'mfm-js'; import * as misskey from 'misskey-js'; import MkNoteSub from '@/components/MkNoteSub.vue'; @@ -196,7 +202,7 @@ const isLong = (appearNote.cw == null && appearNote.text != null && ( const collapsed = ref(appearNote.cw == null && isLong); const isDeleted = ref(false); const muted = ref(checkWordMute(appearNote, $i, defaultStore.state.mutedWords)); -const translation = ref(null); +const translation = ref<any>(null); const translating = ref(false); const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.user.instance); const canRenote = computed(() => ['public', 'home'].includes(appearNote.visibility) || appearNote.userId === $i.id); @@ -361,6 +367,12 @@ function readPromo() { }); isDeleted.value = true; } + +function showReactions(): void { + os.popup(defineAsyncComponent(() => import('@/components/MkReactedUsersDialog.vue')), { + noteId: appearNote.id, + }, {}, 'closed'); +} </script> <style lang="scss" module> @@ -697,4 +709,19 @@ function readPromo() { text-align: center; opacity: 0.7; } + +.reactionDetailsButton { + display: inline-block; + height: 32px; + margin: 2px; + padding: 0 6px; + border: dashed 1px var(--divider); + border-radius: 4px; + background: transparent; + opacity: .8; + + &:hover { + background: var(--X5); + } +} </style> diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue index 83fdf0f98..4abd2562d 100644 --- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue +++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue @@ -107,7 +107,7 @@ useTooltip(buttonEl, async (showing) => { border-radius: 4px; &.canToggle { - background: rgba(0, 0, 0, 0.05); + background: var(--buttonBg); &:hover { background: rgba(0, 0, 0, 0.1); diff --git a/packages/frontend/src/components/MkReactionsViewer.vue b/packages/frontend/src/components/MkReactionsViewer.vue index 5981471c6..cdd6f528e 100644 --- a/packages/frontend/src/components/MkReactionsViewer.vue +++ b/packages/frontend/src/components/MkReactionsViewer.vue @@ -7,23 +7,60 @@ :move-class="$store.state.animation ? $style.transition_x_move : ''" tag="div" :class="$style.root" > - <XReaction v-for="(count, reaction) in note.reactions" :key="reaction" :reaction="reaction" :count="count" :is-initial="initialReactions.has(reaction)" :note="note"/> + <XReaction v-for="[reaction, count] in reactions" :key="reaction" :reaction="reaction" :count="count" :is-initial="initialReactions.has(reaction)" :note="note"/> + <slot v-if="hasMoreReactions" name="more" /> </TransitionGroup> </template> <script lang="ts" setup> -import { computed } from 'vue'; import * as misskey from 'misskey-js'; -import { $i } from '@/account'; import XReaction from '@/components/MkReactionsViewer.reaction.vue'; +import { watch } from 'vue'; -const props = defineProps<{ - note: misskey.entities.Note; -}>(); +const props = withDefaults(defineProps<{ + note: misskey.entities.Note; + maxNumber?: number; +}>(), { + maxNumber: Infinity, +}); const initialReactions = new Set(Object.keys(props.note.reactions)); -const isMe = computed(() => $i && $i.id === props.note.userId); +let reactions = $ref<[string, number][]>([]); +let hasMoreReactions = $ref(false); + +if (props.note.myReaction && !Object.keys(reactions).includes(props.note.myReaction)) { + reactions[props.note.myReaction] = props.note.reactions[props.note.myReaction]; +} + +watch([() => props.note.reactions, () => props.maxNumber], ([newSource, maxNumber]) => { + let newReactions: [string, number][] = []; + hasMoreReactions = Object.keys(newSource).length > maxNumber; + + for (let i = 0; i < reactions.length; i++) { + const reaction = reactions[i][0]; + if (reaction in newSource && newSource[reaction] !== 0) { + reactions[i][1] = newSource[reaction]; + newReactions.push(reactions[i]); + } + } + + const newReactionsNames = newReactions.map(([x]) => x); + newReactions = [ + ...newReactions, + ...Object.entries(newSource) + .sort(([, a], [, b]) => b - a) + .filter(([y], i) => i < maxNumber && !newReactionsNames.includes(y)), + ] + + newReactions = newReactions.slice(0, props.maxNumber); + + if (props.note.myReaction && !newReactions.map(([x]) => x).includes(props.note.myReaction)) { + newReactions.push([props.note.myReaction, newSource[props.note.myReaction]]); + } + + reactions = newReactions; +}, { immediate: true, deep: true }); </script> <style lang="scss" module>