diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index bcd99548f..b3e140e58 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -343,6 +343,9 @@ export class NoteEntityService implements OnModuleInit { uri: note.uri ?? undefined, url: note.url ?? undefined, updatedAt: note.updatedAt != null ? note.updatedAt.toISOString() : undefined, + ...(meId ? { + myReaction: this.populateMyReaction(note, meId, options?._hint_), + } : {}), ...(opts.detail ? { clippedCount: note.clippedCount, @@ -358,10 +361,6 @@ export class NoteEntityService implements OnModuleInit { }) : undefined, poll: note.hasPoll ? this.populatePoll(note, meId) : undefined, - - ...(meId ? { - myReaction: this.populateMyReaction(note, meId, options?._hint_), - } : {}), } : {}), }); diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index ec7841c39..266721f95 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -116,6 +116,9 @@ SPDX-License-Identifier: AGPL-3.0-only + + + @@ -252,6 +255,7 @@ const renoteButton = shallowRef(); const renoteTime = shallowRef(); const reactButton = shallowRef(); const clipButton = shallowRef(); +const likeButton = shallowRef(); let appearNote = $computed(() => isRenote ? note.renote as Misskey.entities.Note : note); const isMyRenote = $i && ($i.id === note.userId); const showContent = ref(false); @@ -432,6 +436,22 @@ function react(viaKeyboard = false): void { } } +function like(): void { + pleaseLogin(); + showMovedDialog(); + os.api('notes/reactions/create', { + noteId: props.note.id, + reaction: '❤️', + }); + const el = likeButton.value as HTMLElement | null | undefined; + if (el) { + const rect = el.getBoundingClientRect(); + const x = rect.left + (el.offsetWidth / 2); + const y = rect.top + (el.offsetHeight / 2); + os.popup(MkRippleEffect, { x, y }, {}, 'end'); + } +} + function undoReact(note): void { const oldReaction = note.myReaction; if (!oldReaction) return; diff --git a/packages/frontend/src/components/MkNoteSub.vue b/packages/frontend/src/components/MkNoteSub.vue index 73f41e577..345869e48 100644 --- a/packages/frontend/src/components/MkNoteSub.vue +++ b/packages/frontend/src/components/MkNoteSub.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> - + @@ -38,6 +38,9 @@ SPDX-License-Identifier: AGPL-3.0-only + + + @@ -90,6 +93,8 @@ import { reactionPicker } from '@/scripts/reaction-picker.js'; import { claimAchievement } from '@/scripts/achievements.js'; import type { MenuItem } from '@/types/menu.js'; import { getNoteMenu } from '@/scripts/get-note-menu.js'; +import { useNoteCapture } from '@/scripts/use-note-capture.js'; + const canRenote = computed(() => ['public', 'home'].includes(props.note.visibility) || props.note.userId === $i.id); const props = withDefaults(defineProps<{ @@ -102,10 +107,7 @@ const props = withDefaults(defineProps<{ depth: 1, }); -function focus() { - el.value.focus(); -} - +const el = shallowRef(); const muted = ref(checkWordMute(props.note, $i, defaultStore.state.mutedWords)); const translation = ref(null); const translating = ref(false); @@ -113,6 +115,26 @@ const isDeleted = ref(false); const reactButton = shallowRef(); const renoteButton = shallowRef(); const menuButton = shallowRef(); +const likeButton = shallowRef(); + +let appearNote = $computed(() => isRenote ? props.note.renote as Misskey.entities.Note : props.note); + +const isRenote = ( + props.note.renote != null && + props.note.text == null && + props.note.fileIds.length === 0 && + props.note.poll == null +); + +useNoteCapture({ + rootEl: el, + note: $$(appearNote), + isDeletedRef: isDeleted, +}); + +function focus() { + el.value.focus(); +} function reply(viaKeyboard = false): void { pleaseLogin(); @@ -157,6 +179,22 @@ function react(viaKeyboard = false): void { } } +function like(): void { + pleaseLogin(); + showMovedDialog(); + os.api('notes/reactions/create', { + noteId: props.note.id, + reaction: '❤️', + }); + const el = reactButton.value as HTMLElement | null | undefined; + if (el) { + const rect = el.getBoundingClientRect(); + const x = rect.left + (el.offsetWidth / 2); + const y = rect.top + (el.offsetHeight / 2); + os.popup(MkRippleEffect, { x, y }, {}, 'end'); + } +} + function undoReact(note): void { const oldReaction = note.myReaction; if (!oldReaction) return;