2023-07-27 05:31:52 +00:00
|
|
|
<!--
|
|
|
|
SPDX-FileCopyrightText: syuilo and other misskey contributors
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
-->
|
|
|
|
|
2020-01-29 19:37:25 +00:00
|
|
|
<template>
|
2023-12-19 09:07:38 +00:00
|
|
|
<div v-show="!isDeleted" v-if="!muted" ref="el" :class="[$style.root, { [$style.children]: depth > 1 }]">
|
2023-01-09 20:45:33 +00:00
|
|
|
<div :class="$style.main">
|
2023-05-11 07:26:35 +00:00
|
|
|
<div v-if="note.channel" :class="$style.colorBar" :style="{ background: note.channel.color }"></div>
|
2023-01-16 05:18:11 +00:00
|
|
|
<MkAvatar :class="$style.avatar" :user="note.user" link preview/>
|
2023-01-09 20:45:33 +00:00
|
|
|
<div :class="$style.body">
|
2023-12-02 12:09:25 +00:00
|
|
|
<MkNoteHeader :class="$style.header" :note="note" :mini="true"/>
|
2023-10-22 20:48:49 +00:00
|
|
|
<div :class="$style.content">
|
2023-01-09 20:45:33 +00:00
|
|
|
<p v-if="note.cw != null" :class="$style.cw">
|
2023-11-15 02:09:54 +00:00
|
|
|
<Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :nyaize="'respect'"/>
|
2023-11-30 04:49:31 +00:00
|
|
|
<MkCwButton v-model="showContent" :text="note.text" :files="note.files" :poll="note.poll"/>
|
2020-05-10 07:22:39 +00:00
|
|
|
</p>
|
2023-09-22 23:26:57 +00:00
|
|
|
<div v-show="note.cw == null || showContent">
|
2023-10-19 20:23:27 +00:00
|
|
|
<MkSubNoteContent :class="$style.text" :note="note" :translating="translating" :translation="translation"/>
|
2020-05-10 07:22:39 +00:00
|
|
|
</div>
|
2020-01-29 19:37:25 +00:00
|
|
|
</div>
|
2023-10-15 17:01:28 +00:00
|
|
|
<footer :class="$style.footer">
|
2023-09-30 22:51:57 +00:00
|
|
|
<MkReactionsViewer ref="reactionsViewer" :note="note"/>
|
|
|
|
<button class="_button" :class="$style.noteFooterButton" @click="reply()">
|
2023-11-03 22:20:53 +00:00
|
|
|
<i class="ph-arrow-u-up-left ph-bold ph-lg"></i>
|
2023-09-30 22:51:57 +00:00
|
|
|
<p v-if="note.repliesCount > 0" :class="$style.noteFooterButtonCount">{{ note.repliesCount }}</p>
|
|
|
|
</button>
|
|
|
|
<button
|
2023-10-13 19:53:38 +00:00
|
|
|
v-if="canRenote"
|
|
|
|
ref="renoteButton"
|
|
|
|
class="_button"
|
|
|
|
:class="$style.noteFooterButton"
|
|
|
|
:style="renoted ? 'color: var(--accent) !important;' : ''"
|
2023-12-03 23:19:34 +00:00
|
|
|
@mousedown="renoted ? undoRenote() : boostVisibility()"
|
2023-09-30 22:51:57 +00:00
|
|
|
>
|
2023-10-13 19:53:38 +00:00
|
|
|
<i class="ph-rocket-launch ph-bold ph-lg"></i>
|
2023-09-30 22:51:57 +00:00
|
|
|
<p v-if="note.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ note.renoteCount }}</p>
|
|
|
|
</button>
|
2023-10-15 00:16:02 +00:00
|
|
|
<button
|
|
|
|
v-if="canRenote"
|
|
|
|
ref="quoteButton"
|
|
|
|
class="_button"
|
|
|
|
:class="$style.noteFooterButton"
|
2023-11-29 21:26:10 +00:00
|
|
|
@mousedown="quote()"
|
2023-10-15 00:16:02 +00:00
|
|
|
>
|
|
|
|
<i class="ph-quotes ph-bold ph-lg"></i>
|
|
|
|
</button>
|
2023-09-30 22:51:57 +00:00
|
|
|
<button v-else class="_button" :class="$style.noteFooterButton" disabled>
|
|
|
|
<i class="ph-prohibit ph-bold ph-lg"></i>
|
|
|
|
</button>
|
2023-09-30 23:53:17 +00:00
|
|
|
<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>
|
2023-09-30 22:51:57 +00:00
|
|
|
<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>
|
|
|
|
</button>
|
|
|
|
<button v-if="note.myReaction != null" ref="reactButton" class="_button" :class="[$style.noteFooterButton, $style.reacted]" @click="undoReact(note)">
|
|
|
|
<i class="ph-minus ph-bold ph-lg"></i>
|
|
|
|
</button>
|
|
|
|
<button ref="menuButton" class="_button" :class="$style.noteFooterButton" @mousedown="menu()">
|
|
|
|
<i class="ph-dots-three ph-bold ph-lg"></i>
|
|
|
|
</button>
|
|
|
|
</footer>
|
2020-01-29 19:37:25 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2023-12-07 13:54:31 +00:00
|
|
|
<template v-if="depth < numberOfReplies">
|
2023-12-21 16:00:59 +00:00
|
|
|
<MkNoteSub v-for="reply in replies" :key="reply.id" :note="reply" :class="$style.reply" :detail="true" :depth="depth + 1" :expandAllCws="props.expandAllCws" :onDeleteCallback="removeReply"/>
|
2021-11-18 13:11:44 +00:00
|
|
|
</template>
|
2023-01-09 20:45:33 +00:00
|
|
|
<div v-else :class="$style.more">
|
2023-09-30 22:46:42 +00:00
|
|
|
<MkA class="_link" :to="notePage(note)">{{ i18n.ts.continueThread }} <i class="ph-caret-double-right ph-bold ph-lg"></i></MkA>
|
2021-11-18 13:11:44 +00:00
|
|
|
</div>
|
2020-01-29 19:37:25 +00:00
|
|
|
</div>
|
2023-08-14 04:02:59 +00:00
|
|
|
<div v-else :class="$style.muted" @click="muted = false">
|
|
|
|
<I18n :src="i18n.ts.userSaysSomething" tag="small">
|
|
|
|
<template #name>
|
|
|
|
<MkA v-user-preview="note.userId" :to="userPage(note.user)">
|
|
|
|
<MkUserName :user="note.user"/>
|
|
|
|
</MkA>
|
|
|
|
</template>
|
|
|
|
</I18n>
|
|
|
|
</div>
|
2020-01-29 19:37:25 +00:00
|
|
|
</template>
|
|
|
|
|
2022-01-14 01:25:51 +00:00
|
|
|
<script lang="ts" setup>
|
2023-10-17 02:45:32 +00:00
|
|
|
import { computed, ref, shallowRef, watch } from 'vue';
|
2023-09-04 04:33:38 +00:00
|
|
|
import * as Misskey from 'misskey-js';
|
2022-12-30 04:56:22 +00:00
|
|
|
import MkNoteHeader from '@/components/MkNoteHeader.vue';
|
2023-09-30 22:51:57 +00:00
|
|
|
import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
|
2022-08-30 15:24:33 +00:00
|
|
|
import MkSubNoteContent from '@/components/MkSubNoteContent.vue';
|
2022-12-30 04:56:22 +00:00
|
|
|
import MkCwButton from '@/components/MkCwButton.vue';
|
2023-09-19 07:37:43 +00:00
|
|
|
import { notePage } from '@/filters/note.js';
|
|
|
|
import * as os from '@/os.js';
|
|
|
|
import { i18n } from '@/i18n.js';
|
|
|
|
import { $i } from '@/account.js';
|
2023-10-03 11:26:11 +00:00
|
|
|
import { userPage } from '@/filters/user.js';
|
|
|
|
import { checkWordMute } from '@/scripts/check-word-mute.js';
|
2023-12-23 01:09:23 +00:00
|
|
|
import { defaultStore } from '@/store.js';
|
2023-09-30 22:51:57 +00:00
|
|
|
import { pleaseLogin } from '@/scripts/please-login.js';
|
|
|
|
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
|
|
|
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
|
|
|
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
|
|
|
import { claimAchievement } from '@/scripts/achievements.js';
|
|
|
|
import { getNoteMenu } from '@/scripts/get-note-menu.js';
|
2023-09-30 23:53:17 +00:00
|
|
|
import { useNoteCapture } from '@/scripts/use-note-capture.js';
|
|
|
|
|
2023-09-30 22:51:57 +00:00
|
|
|
const canRenote = computed(() => ['public', 'home'].includes(props.note.visibility) || props.note.userId === $i.id);
|
2020-01-29 19:37:25 +00:00
|
|
|
|
2022-01-14 01:25:51 +00:00
|
|
|
const props = withDefaults(defineProps<{
|
2023-09-04 04:33:38 +00:00
|
|
|
note: Misskey.entities.Note;
|
2022-01-14 01:25:51 +00:00
|
|
|
detail?: boolean;
|
2023-10-17 02:45:32 +00:00
|
|
|
expandAllCws?: boolean;
|
2023-12-21 16:00:59 +00:00
|
|
|
onDeleteCallback?: (id: Misskey.entities.Note['id']) => void;
|
2021-11-18 13:11:44 +00:00
|
|
|
|
2022-01-14 01:25:51 +00:00
|
|
|
// how many notes are in between this one and the note being viewed in detail
|
|
|
|
depth?: number;
|
|
|
|
}>(), {
|
|
|
|
depth: 1,
|
2020-01-29 19:37:25 +00:00
|
|
|
});
|
2022-01-14 01:25:51 +00:00
|
|
|
|
2023-09-30 23:53:17 +00:00
|
|
|
const el = shallowRef<HTMLElement>();
|
2023-10-03 11:26:11 +00:00
|
|
|
const muted = ref($i ? checkWordMute(props.note, $i, $i.mutedWords) : false);
|
2023-10-19 20:23:27 +00:00
|
|
|
const translation = ref<any>(null);
|
2023-09-30 22:51:57 +00:00
|
|
|
const translating = ref(false);
|
|
|
|
const isDeleted = ref(false);
|
2023-10-13 19:53:38 +00:00
|
|
|
const renoted = ref(false);
|
2023-12-07 13:54:31 +00:00
|
|
|
const numberOfReplies = ref(defaultStore.state.numberOfReplies);
|
2023-09-30 22:51:57 +00:00
|
|
|
const reactButton = shallowRef<HTMLElement>();
|
|
|
|
const renoteButton = shallowRef<HTMLElement>();
|
2023-10-15 00:16:02 +00:00
|
|
|
const quoteButton = shallowRef<HTMLElement>();
|
2023-09-30 22:51:57 +00:00
|
|
|
const menuButton = shallowRef<HTMLElement>();
|
2023-09-30 23:53:17 +00:00
|
|
|
const likeButton = shallowRef<HTMLElement>();
|
|
|
|
|
2023-12-23 01:09:23 +00:00
|
|
|
let appearNote = computed(() => isRenote ? props.note.renote as Misskey.entities.Note : props.note);
|
2023-11-28 16:49:50 +00:00
|
|
|
const defaultLike = computed(() => defaultStore.state.like ? defaultStore.state.like : null);
|
2023-12-19 09:07:32 +00:00
|
|
|
const replies = ref<Misskey.entities.Note[]>([]);
|
2023-09-30 23:53:17 +00:00
|
|
|
|
|
|
|
const isRenote = (
|
|
|
|
props.note.renote != null &&
|
|
|
|
props.note.text == null &&
|
|
|
|
props.note.fileIds.length === 0 &&
|
|
|
|
props.note.poll == null
|
|
|
|
);
|
|
|
|
|
2023-12-21 16:00:59 +00:00
|
|
|
async function addReplyTo(replyNote: Misskey.entities.Note) {
|
2023-12-19 09:07:32 +00:00
|
|
|
replies.value.unshift(replyNote);
|
2023-12-23 14:47:14 +00:00
|
|
|
appearNote.value.repliesCount += 1;
|
2023-12-21 16:00:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async function removeReply(id: Misskey.entities.Note['id']) {
|
|
|
|
const replyIdx = replies.value.findIndex(note => note.id === id);
|
|
|
|
if (replyIdx >= 0) {
|
|
|
|
replies.value.splice(replyIdx, 1);
|
2023-12-23 14:47:14 +00:00
|
|
|
appearNote.value.repliesCount -= 1;
|
2023-12-21 16:00:59 +00:00
|
|
|
}
|
2023-12-19 09:07:32 +00:00
|
|
|
}
|
|
|
|
|
2023-09-30 23:53:17 +00:00
|
|
|
useNoteCapture({
|
|
|
|
rootEl: el,
|
2023-12-23 01:09:23 +00:00
|
|
|
note: appearNote,
|
2023-09-30 23:53:17 +00:00
|
|
|
isDeletedRef: isDeleted,
|
2023-12-19 09:07:32 +00:00
|
|
|
// only update replies if we are, in fact, showing replies
|
|
|
|
onReplyCallback: props.detail && props.depth < numberOfReplies.value ? addReplyTo : undefined,
|
2023-12-21 16:00:59 +00:00
|
|
|
onDeleteCallback: props.detail && props.depth < numberOfReplies.value ? props.onDeleteCallback : undefined,
|
2023-09-30 23:53:17 +00:00
|
|
|
});
|
|
|
|
|
2023-10-13 19:53:38 +00:00
|
|
|
if ($i) {
|
2023-12-23 01:09:23 +00:00
|
|
|
os.api('notes/renotes', {
|
|
|
|
noteId: appearNote.value.id,
|
2023-10-13 19:53:38 +00:00
|
|
|
userId: $i.id,
|
|
|
|
limit: 1,
|
|
|
|
}).then((res) => {
|
|
|
|
renoted.value = res.length > 0;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-30 23:53:17 +00:00
|
|
|
function focus() {
|
|
|
|
el.value.focus();
|
|
|
|
}
|
2023-09-30 22:51:57 +00:00
|
|
|
|
|
|
|
function reply(viaKeyboard = false): void {
|
|
|
|
pleaseLogin();
|
|
|
|
showMovedDialog();
|
|
|
|
os.post({
|
|
|
|
reply: props.note,
|
|
|
|
channel: props.note.channel,
|
|
|
|
animation: !viaKeyboard,
|
|
|
|
}, () => {
|
|
|
|
focus();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function react(viaKeyboard = false): void {
|
|
|
|
pleaseLogin();
|
|
|
|
showMovedDialog();
|
|
|
|
if (props.note.reactionAcceptance === 'likeOnly') {
|
2023-11-16 22:47:44 +00:00
|
|
|
os.api('notes/like', {
|
2023-09-30 22:51:57 +00:00
|
|
|
noteId: props.note.id,
|
2023-11-16 22:47:44 +00:00
|
|
|
override: defaultLike.value,
|
2023-09-30 22:51:57 +00:00
|
|
|
});
|
|
|
|
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');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
blur();
|
|
|
|
reactionPicker.show(reactButton.value, reaction => {
|
|
|
|
os.api('notes/reactions/create', {
|
|
|
|
noteId: props.note.id,
|
|
|
|
reaction: reaction,
|
|
|
|
});
|
|
|
|
if (props.note.text && props.note.text.length > 100 && (Date.now() - new Date(props.note.createdAt).getTime() < 1000 * 3)) {
|
|
|
|
claimAchievement('reactWithoutRead');
|
|
|
|
}
|
|
|
|
}, () => {
|
|
|
|
focus();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-30 23:53:17 +00:00
|
|
|
function like(): void {
|
|
|
|
pleaseLogin();
|
|
|
|
showMovedDialog();
|
2023-11-16 22:47:44 +00:00
|
|
|
os.api('notes/like', {
|
2023-09-30 23:53:17 +00:00
|
|
|
noteId: props.note.id,
|
2023-11-16 22:47:44 +00:00
|
|
|
override: defaultLike.value,
|
2023-09-30 23:53:17 +00:00
|
|
|
});
|
2023-12-29 17:36:15 +00:00
|
|
|
const el = likeButton.value as HTMLElement | null | undefined;
|
2023-09-30 23:53:17 +00:00
|
|
|
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');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-30 22:51:57 +00:00
|
|
|
function undoReact(note): void {
|
|
|
|
const oldReaction = note.myReaction;
|
|
|
|
if (!oldReaction) return;
|
|
|
|
os.api('notes/reactions/delete', {
|
|
|
|
noteId: note.id,
|
|
|
|
});
|
|
|
|
}
|
2023-08-14 04:02:59 +00:00
|
|
|
|
2023-10-13 19:53:38 +00:00
|
|
|
function undoRenote() : void {
|
2023-10-13 19:54:57 +00:00
|
|
|
if (!renoted.value) return;
|
2023-12-23 01:09:23 +00:00
|
|
|
os.api('notes/unrenote', {
|
|
|
|
noteId: appearNote.value.id,
|
2023-10-13 19:53:38 +00:00
|
|
|
});
|
2023-10-15 16:00:09 +00:00
|
|
|
os.toast(i18n.ts.rmboost);
|
2023-10-13 19:53:38 +00:00
|
|
|
renoted.value = false;
|
2023-10-15 16:00:09 +00:00
|
|
|
|
|
|
|
const el = renoteButton.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');
|
|
|
|
}
|
2023-10-13 19:53:38 +00:00
|
|
|
}
|
|
|
|
|
2023-12-23 01:09:23 +00:00
|
|
|
let showContent = ref(defaultStore.state.uncollapseCW);
|
2023-10-17 02:45:32 +00:00
|
|
|
|
|
|
|
watch(() => props.expandAllCws, (expandAllCws) => {
|
2023-12-23 01:09:23 +00:00
|
|
|
if (expandAllCws !== showContent.value) showContent.value = expandAllCws;
|
2023-10-17 02:45:32 +00:00
|
|
|
});
|
|
|
|
|
2023-12-03 23:19:34 +00:00
|
|
|
function boostVisibility() {
|
|
|
|
os.popupMenu([
|
|
|
|
{
|
|
|
|
type: 'button',
|
|
|
|
icon: 'ph-globe-hemisphere-west ph-bold ph-lg',
|
|
|
|
text: i18n.ts._visibility['public'],
|
|
|
|
action: () => {
|
|
|
|
renote('public');
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'button',
|
|
|
|
icon: 'ph-house ph-bold ph-lg',
|
|
|
|
text: i18n.ts._visibility['home'],
|
|
|
|
action: () => {
|
|
|
|
renote('home');
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'button',
|
|
|
|
icon: 'ph-lock ph-bold ph-lg',
|
|
|
|
text: i18n.ts._visibility['followers'],
|
|
|
|
action: () => {
|
|
|
|
renote('followers');
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'button',
|
|
|
|
icon: 'ph-planet ph-bold ph-lg',
|
|
|
|
text: i18n.ts._timelines.local,
|
|
|
|
action: () => {
|
|
|
|
renote('local');
|
|
|
|
},
|
|
|
|
}], renoteButton.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
function renote(visibility: 'public' | 'home' | 'followers' | 'specified' | 'local') {
|
2023-09-30 22:51:57 +00:00
|
|
|
pleaseLogin();
|
|
|
|
showMovedDialog();
|
|
|
|
|
2023-12-23 01:09:23 +00:00
|
|
|
if (appearNote.value.channel) {
|
2023-10-15 00:16:02 +00:00
|
|
|
const el = renoteButton.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');
|
|
|
|
}
|
2023-09-30 22:51:57 +00:00
|
|
|
|
2023-10-15 00:16:02 +00:00
|
|
|
os.api('notes/create', {
|
|
|
|
renoteId: props.note.id,
|
|
|
|
channelId: props.note.channelId,
|
|
|
|
}).then(() => {
|
|
|
|
os.toast(i18n.ts.renoted);
|
|
|
|
renoted.value = true;
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
const el = renoteButton.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');
|
|
|
|
}
|
|
|
|
|
|
|
|
os.api('notes/create', {
|
|
|
|
renoteId: props.note.id,
|
2023-12-03 23:19:34 +00:00
|
|
|
localOnly: visibility === 'local' ? true : false,
|
2023-12-03 23:26:47 +00:00
|
|
|
visibility: visibility === 'local' || visibility === 'specified' ? props.note.visibility : visibility,
|
2023-10-15 00:16:02 +00:00
|
|
|
}).then(() => {
|
|
|
|
os.toast(i18n.ts.renoted);
|
|
|
|
renoted.value = true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function quote() {
|
|
|
|
pleaseLogin();
|
|
|
|
showMovedDialog();
|
|
|
|
|
2023-12-23 01:09:23 +00:00
|
|
|
if (appearNote.value.channel) {
|
2023-10-15 00:16:02 +00:00
|
|
|
os.post({
|
2023-12-23 01:09:23 +00:00
|
|
|
renote: appearNote.value,
|
|
|
|
channel: appearNote.value.channel,
|
2023-10-15 00:16:02 +00:00
|
|
|
}).then(() => {
|
2023-12-23 01:09:23 +00:00
|
|
|
os.api('notes/renotes', {
|
2023-10-15 00:16:02 +00:00
|
|
|
noteId: props.note.id,
|
|
|
|
userId: $i.id,
|
|
|
|
limit: 1,
|
|
|
|
quote: true,
|
|
|
|
}).then((res) => {
|
2023-10-15 16:03:27 +00:00
|
|
|
if (!(res.length > 0)) return;
|
2023-10-15 00:16:02 +00:00
|
|
|
const el = quoteButton.value as HTMLElement | null | undefined;
|
|
|
|
if (el && res.length > 0) {
|
2023-09-30 22:51:57 +00:00
|
|
|
const rect = el.getBoundingClientRect();
|
|
|
|
const x = rect.left + (el.offsetWidth / 2);
|
|
|
|
const y = rect.top + (el.offsetHeight / 2);
|
|
|
|
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
|
|
|
}
|
|
|
|
|
2023-10-15 16:00:09 +00:00
|
|
|
os.toast(i18n.ts.quoted);
|
2023-09-30 22:51:57 +00:00
|
|
|
});
|
2023-10-15 00:16:02 +00:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
os.post({
|
2023-12-23 01:09:23 +00:00
|
|
|
renote: appearNote.value,
|
2023-10-15 00:16:02 +00:00
|
|
|
}).then(() => {
|
2023-12-23 01:09:23 +00:00
|
|
|
os.api('notes/renotes', {
|
2023-10-15 00:16:02 +00:00
|
|
|
noteId: props.note.id,
|
|
|
|
userId: $i.id,
|
|
|
|
limit: 1,
|
|
|
|
quote: true,
|
|
|
|
}).then((res) => {
|
2023-10-15 16:03:27 +00:00
|
|
|
if (!(res.length > 0)) return;
|
2023-10-15 00:16:02 +00:00
|
|
|
const el = quoteButton.value as HTMLElement | null | undefined;
|
|
|
|
if (el && res.length > 0) {
|
|
|
|
const rect = el.getBoundingClientRect();
|
|
|
|
const x = rect.left + (el.offsetWidth / 2);
|
|
|
|
const y = rect.top + (el.offsetHeight / 2);
|
|
|
|
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
|
|
|
}
|
2023-09-30 22:51:57 +00:00
|
|
|
|
2023-10-15 16:00:09 +00:00
|
|
|
os.toast(i18n.ts.quoted);
|
2023-10-15 00:16:02 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
2023-09-30 22:51:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function menu(viaKeyboard = false): void {
|
|
|
|
const { menu, cleanup } = getNoteMenu({ note: props.note, translating, translation, menuButton, isDeleted });
|
|
|
|
os.popupMenu(menu, menuButton.value, {
|
|
|
|
viaKeyboard,
|
|
|
|
}).then(focus).finally(cleanup);
|
|
|
|
}
|
|
|
|
|
2022-01-14 01:25:51 +00:00
|
|
|
if (props.detail) {
|
|
|
|
os.api('notes/children', {
|
|
|
|
noteId: props.note.id,
|
2023-12-07 13:54:31 +00:00
|
|
|
limit: numberOfReplies.value,
|
2023-12-03 19:43:25 +00:00
|
|
|
showQuotes: false,
|
2022-01-14 01:25:51 +00:00
|
|
|
}).then(res => {
|
2023-12-07 05:42:09 +00:00
|
|
|
replies.value = res;
|
2022-01-14 01:25:51 +00:00
|
|
|
});
|
|
|
|
}
|
2020-01-29 19:37:25 +00:00
|
|
|
</script>
|
|
|
|
|
2023-01-09 20:45:33 +00:00
|
|
|
<style lang="scss" module>
|
|
|
|
.root {
|
2023-12-02 12:09:25 +00:00
|
|
|
padding: 16px 32px;
|
2020-01-29 19:37:25 +00:00
|
|
|
font-size: 0.9em;
|
2023-05-11 07:26:35 +00:00
|
|
|
position: relative;
|
2020-01-29 19:37:25 +00:00
|
|
|
|
2020-05-10 07:22:39 +00:00
|
|
|
&.children {
|
|
|
|
padding: 10px 0 0 16px;
|
|
|
|
font-size: 1em;
|
2020-01-29 19:37:25 +00:00
|
|
|
}
|
2023-01-09 20:45:33 +00:00
|
|
|
}
|
2020-01-29 19:37:25 +00:00
|
|
|
|
2023-10-15 17:01:28 +00:00
|
|
|
.footer {
|
2023-12-02 12:09:25 +00:00
|
|
|
position: relative;
|
|
|
|
z-index: 1;
|
|
|
|
margin-top: 0.4em;
|
|
|
|
width: max-content;
|
2023-12-23 18:21:37 +00:00
|
|
|
min-width: min-content;
|
|
|
|
max-width: fit-content;
|
2023-10-15 17:01:28 +00:00
|
|
|
}
|
|
|
|
|
2023-01-09 20:45:33 +00:00
|
|
|
.main {
|
|
|
|
display: flex;
|
|
|
|
}
|
2020-01-29 19:37:25 +00:00
|
|
|
|
2023-05-11 07:26:35 +00:00
|
|
|
.colorBar {
|
|
|
|
position: absolute;
|
|
|
|
top: 8px;
|
|
|
|
left: 8px;
|
|
|
|
width: 5px;
|
|
|
|
height: calc(100% - 8px);
|
2023-10-31 18:44:34 +00:00
|
|
|
border-radius: var(--radius-ellipse);
|
2023-05-11 07:26:35 +00:00
|
|
|
pointer-events: none;
|
|
|
|
}
|
|
|
|
|
2023-01-09 20:45:33 +00:00
|
|
|
.avatar {
|
|
|
|
flex-shrink: 0;
|
|
|
|
display: block;
|
2023-12-02 12:09:25 +00:00
|
|
|
margin: 0 8px 0 0;
|
|
|
|
width: 38px;
|
|
|
|
height: 38px;
|
2023-10-31 18:44:34 +00:00
|
|
|
border-radius: var(--radius-sm);
|
2023-01-09 20:45:33 +00:00
|
|
|
}
|
2020-01-29 19:37:25 +00:00
|
|
|
|
2023-01-09 20:45:33 +00:00
|
|
|
.body {
|
|
|
|
flex: 1;
|
|
|
|
min-width: 0;
|
|
|
|
}
|
2020-05-10 07:22:39 +00:00
|
|
|
|
2023-10-22 20:48:49 +00:00
|
|
|
.content {
|
|
|
|
overflow: hidden;
|
|
|
|
}
|
|
|
|
|
2023-01-09 20:45:33 +00:00
|
|
|
.header {
|
|
|
|
margin-bottom: 2px;
|
|
|
|
}
|
2021-11-18 13:11:44 +00:00
|
|
|
|
2023-09-30 22:51:57 +00:00
|
|
|
.noteFooterButton {
|
|
|
|
margin: 0;
|
|
|
|
padding: 8px;
|
|
|
|
padding-top: 10px;
|
|
|
|
opacity: 0.7;
|
|
|
|
|
|
|
|
&:not(:last-child) {
|
2023-10-15 17:01:28 +00:00
|
|
|
margin-right: 1.5em;
|
2023-09-30 22:51:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
color: var(--fgHighlighted);
|
|
|
|
}
|
|
|
|
}
|
2023-10-17 02:45:32 +00:00
|
|
|
|
2023-10-15 17:25:36 +00:00
|
|
|
@container (max-width: 400px) {
|
|
|
|
.noteFooterButton {
|
|
|
|
&:not(:last-child) {
|
|
|
|
margin-right: 0.7em;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-09-30 22:51:57 +00:00
|
|
|
|
|
|
|
.noteFooterButtonCount {
|
|
|
|
display: inline;
|
|
|
|
margin: 0 0 0 8px;
|
|
|
|
opacity: 0.7;
|
|
|
|
|
|
|
|
&.reacted {
|
|
|
|
color: var(--accent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-09 20:45:33 +00:00
|
|
|
.cw {
|
|
|
|
display: block;
|
|
|
|
margin: 0;
|
|
|
|
padding: 0;
|
|
|
|
overflow-wrap: break-word;
|
|
|
|
}
|
|
|
|
|
|
|
|
.text {
|
|
|
|
margin: 0;
|
|
|
|
padding: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.reply, .more {
|
|
|
|
border-left: solid 0.5px var(--divider);
|
|
|
|
margin-top: 10px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.more {
|
|
|
|
padding: 10px 0 0 16px;
|
2020-01-29 19:37:25 +00:00
|
|
|
}
|
2022-12-25 23:40:13 +00:00
|
|
|
|
2023-12-02 12:09:25 +00:00
|
|
|
@container (max-width: 450px) {
|
2023-01-09 20:45:33 +00:00
|
|
|
.root {
|
2023-12-02 12:09:25 +00:00
|
|
|
padding: 14px 16px;
|
2022-12-25 23:40:13 +00:00
|
|
|
|
|
|
|
&.children {
|
|
|
|
padding: 10px 0 0 8px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-08-14 04:02:59 +00:00
|
|
|
|
|
|
|
.muted {
|
|
|
|
text-align: center;
|
|
|
|
padding: 8px !important;
|
|
|
|
border: 1px solid var(--divider);
|
|
|
|
margin: 8px 8px 0 8px;
|
2023-10-31 18:44:34 +00:00
|
|
|
border-radius: var(--radius-sm);
|
2023-08-14 04:02:59 +00:00
|
|
|
}
|
2020-01-29 19:37:25 +00:00
|
|
|
</style>
|