diff options
| author | Marie <marie@kaifa.ch> | 2023-10-01 01:55:40 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-10-01 01:55:40 +0200 |
| commit | e5d9eb3082b89725ac0d1ef2b98b192d6cb5e50b (patch) | |
| tree | 6e6600d07382a285bfb89346597cd0b9f1dacb88 | |
| parent | Merge pull request #31 from transfem-org/icons (diff) | |
| parent | Merge branch 'icons' of https://github.com/transfem-org/Sharkey into icons (diff) | |
| download | sharkey-e5d9eb3082b89725ac0d1ef2b98b192d6cb5e50b.tar.gz sharkey-e5d9eb3082b89725ac0d1ef2b98b192d6cb5e50b.tar.bz2 sharkey-e5d9eb3082b89725ac0d1ef2b98b192d6cb5e50b.zip | |
merge: add like button #32
Add Like Button
| -rw-r--r-- | packages/backend/src/core/entities/NoteEntityService.ts | 7 | ||||
| -rw-r--r-- | packages/frontend/src/components/MkNoteDetailed.vue | 20 | ||||
| -rw-r--r-- | packages/frontend/src/components/MkNoteSub.vue | 48 |
3 files changed, 66 insertions, 9 deletions
diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index bcd99548fe..b3e140e588 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 73769b6a6a..1bd2cef80c 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 <button v-else class="_button" :class="$style.noteFooterButton" disabled> <i class="ph-prohibit ph-bold ph-lg"></i> </button> + <button v-if="appearNote.myReaction == null && appearNote.reactionAcceptance !== 'likeOnly'" ref="likeButton" :class="$style.noteFooterButton" class="_button" @mousedown="like()"> + <i class="ph-heart ph-bold ph-lg"></i> + </button> <button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.noteFooterButton" class="_button" @mousedown="react()"> <i v-if="appearNote.reactionAcceptance === 'likeOnly'" class="ph-heart ph-bold ph-lg"></i> <i v-else class="ph-smiley ph-bold ph-lg"></i> @@ -252,6 +255,7 @@ const renoteButton = shallowRef<HTMLElement>(); const renoteTime = shallowRef<HTMLElement>(); const reactButton = shallowRef<HTMLElement>(); const clipButton = shallowRef<HTMLElement>(); +const likeButton = shallowRef<HTMLElement>(); 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 6e30ac484f..36e7c694c4 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 --> <template> -<div v-if="!muted" :class="[$style.root, { [$style.children]: depth > 1 }]"> +<div ref="el" v-if="!muted" :class="[$style.root, { [$style.children]: depth > 1 }]"> <div :class="$style.main"> <div v-if="note.channel" :class="$style.colorBar" :style="{ background: note.channel.color }"></div> <MkAvatar :class="$style.avatar" :user="note.user" link preview/> @@ -38,6 +38,9 @@ SPDX-License-Identifier: AGPL-3.0-only <button v-else class="_button" :class="$style.noteFooterButton" disabled> <i class="ph-prohibit ph-bold ph-lg"></i> </button> + <button v-if="note.myReaction == null && note.reactionAcceptance !== 'likeOnly'" ref="likeButton" :class="$style.noteFooterButton" class="_button" @mousedown="like()"> + <i class="ph-heart ph-bold ph-lg"></i> + </button> <button v-if="note.myReaction == null" ref="reactButton" :class="$style.noteFooterButton" class="_button" @mousedown="react()"> <i v-if="note.reactionAcceptance === 'likeOnly'" class="ph-heart ph-bold ph-lg"></i> <i v-else class="ph-smiley ph-bold ph-lg"></i> @@ -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<HTMLElement>(); 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<HTMLElement>(); const renoteButton = shallowRef<HTMLElement>(); const menuButton = shallowRef<HTMLElement>(); +const likeButton = shallowRef<HTMLElement>(); + +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; |