summaryrefslogtreecommitdiff
path: root/packages/frontend/src/components/MkNoteDetailed.vue
diff options
context:
space:
mode:
Diffstat (limited to 'packages/frontend/src/components/MkNoteDetailed.vue')
-rw-r--r--packages/frontend/src/components/MkNoteDetailed.vue74
1 files changed, 57 insertions, 17 deletions
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index e3ef14120f..ed1c0a9e96 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -68,7 +68,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="$style.noteContent">
<p v-if="appearNote.cw != null" :class="$style.cw">
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'respect'"/>
- <MkCwButton v-model="showContent" :text="appearNote.text" :files="appearNote.files" :poll="appearNote.poll"/>
+ <MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll"/>
</p>
<div v-show="appearNote.cw == null || showContent">
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
@@ -95,7 +95,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkMediaList :mediaList="appearNote.files"/>
</div>
<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
- <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" style="margin-top: 6px;"/>
+ <div v-if="isEnabledUrlPreview">
+ <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" style="margin-top: 6px;"/>
+ </div>
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
</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>
@@ -106,10 +108,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 +121,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.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && 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>
@@ -199,6 +201,7 @@ import * as Misskey from 'misskey-js';
import MkNoteSub from '@/components/MkNoteSub.vue';
import MkNoteSimple from '@/components/MkNoteSimple.vue';
import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
+import MkReactionsViewerDetails from '@/components/MkReactionsViewer.details.vue';
import MkMediaList from '@/components/MkMediaList.vue';
import MkCwButton from '@/components/MkCwButton.vue';
import MkPoll from '@/components/MkPoll.vue';
@@ -209,8 +212,9 @@ 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 { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
import * as sound from '@/scripts/sound.js';
import { defaultStore, noteViewInterruptors } from '@/store.js';
import { reactionPicker } from '@/scripts/reaction-picker.js';
@@ -228,10 +232,14 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue';
import MkPagination, { type Paging } from '@/components/MkPagination.vue';
import MkReactionIcon from '@/components/MkReactionIcon.vue';
import MkButton from '@/components/MkButton.vue';
+import { isEnabledUrlPreview } from '@/instance.js';
-const props = defineProps<{
+const props = withDefaults(defineProps<{
note: Misskey.entities.Note;
-}>();
+ initialTab: string;
+}>(), {
+ initialTab: 'replies',
+});
const inChannel = inject('inChannel', null);
@@ -258,7 +266,9 @@ if (noteViewInterruptors.length > 0) {
const isRenote = (
note.value.renote != null &&
+ note.value.reply == null &&
note.value.text == null &&
+ note.value.cw == null &&
note.value.fileIds && note.value.fileIds.length === 0 &&
note.value.poll == null
);
@@ -299,7 +309,7 @@ provide('react', (reaction: string) => {
});
});
-const tab = ref('replies');
+const tab = ref(props.initialTab);
const reactionTabType = ref<string | null>(null);
const renotesPagination = computed<Paging>(() => ({
@@ -344,6 +354,28 @@ useTooltip(renoteButton, async (showing) => {
}, {}, 'closed');
});
+if (appearNote.value.reactionAcceptance === 'likeOnly') {
+ useTooltip(reactButton, async (showing) => {
+ const reactions = await misskeyApiGet('notes/reactions', {
+ noteId: appearNote.value.id,
+ limit: 10,
+ _cacheKey_: appearNote.value.reactionCount,
+ });
+
+ const users = reactions.map(x => x.user);
+
+ if (users.length < 1) return;
+
+ os.popup(MkReactionsViewerDetails, {
+ showing,
+ reaction: '❤️',
+ users,
+ count: appearNote.value.reactionCount,
+ targetElement: reactButton.value!,
+ }, {}, 'closed');
+ });
+}
+
function renote(viaKeyboard = false) {
pleaseLogin();
showMovedDialog();
@@ -401,14 +433,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;