mirror of
https://github.com/paricafe/misskey.git
synced 2025-03-01 15:24:26 -06:00
fix conflict
This commit is contained in:
parent
e4fdd42555
commit
87ecfe55c8
1 changed files with 897 additions and 820 deletions
|
@ -4,18 +4,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<div
|
||||
<div
|
||||
v-if="!muted"
|
||||
v-show="!isDeleted"
|
||||
ref="rootEl"
|
||||
v-hotkey="keymap"
|
||||
:class="$style.root"
|
||||
:tabindex="isDeleted ? '-1' : '0'"
|
||||
>
|
||||
>
|
||||
<div v-if="appearNote.reply && appearNote.reply.replyId">
|
||||
<div v-if="!conversationLoaded" style="padding: 16px">
|
||||
<!-- <div v-if="!conversationLoaded" style="padding: 16px">
|
||||
<MkButton style="margin: 0 auto;" primary rounded @click="loadConversation">{{ i18n.ts.loadConversation }}</MkButton>
|
||||
</div>
|
||||
</div> -->
|
||||
<MkNoteSub v-for="note in conversation" :key="note.id" :class="$style.replyToMore" :note="note"/>
|
||||
</div>
|
||||
<MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" :class="$style.replyTo"/>
|
||||
|
@ -102,6 +102,19 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<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>
|
||||
|
||||
<div v-if="showingNoteHistoryRef" :class="$style.translation">
|
||||
<b><MkTime :time="showingNoteHistoryRef.createdAt"/>: </b>
|
||||
<div v-if="showingNoteHistoryRef.cw">
|
||||
<p :class="$style.cw">
|
||||
<Mfm style="margin-right: 8px;" :text="showingNoteHistoryRef.cw" :author="appearNote.user" :nyaize="'respect'"/>
|
||||
</p>
|
||||
<hr/>
|
||||
</div>
|
||||
<div v-if="showingNoteHistoryRef.text">
|
||||
<Mfm :text="showingNoteHistoryRef.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div :class="$style.noteFooterInfo">
|
||||
|
@ -137,6 +150,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<i v-else class="ti ti-plus"></i>
|
||||
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.reactionCount) }}</p>
|
||||
</button>
|
||||
<button
|
||||
v-if="appearNote.updatedAt" ref="historyMenuButton" class="_button" :class="[
|
||||
$style.noteFooterButton,
|
||||
$style.noteFooterButtonHistoryMenu,
|
||||
showingNoteHistoryRef ? $style.active : undefined,
|
||||
]" @mousedown="historyMenu()"
|
||||
>
|
||||
<i class="ti ti-history"></i>
|
||||
</button>
|
||||
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown.prevent="clip()">
|
||||
<i class="ti ti-paperclip"></i>
|
||||
</button>
|
||||
|
@ -152,9 +174,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
<div>
|
||||
<div v-if="tab === 'replies'">
|
||||
<div v-if="!repliesLoaded" style="padding: 16px">
|
||||
<!-- <div v-if="!repliesLoaded" style="padding: 16px">
|
||||
<MkButton style="margin: 0 auto;" primary rounded @click="loadReplies">{{ i18n.ts.loadReplies }}</MkButton>
|
||||
</div>
|
||||
</div> -->
|
||||
<MkNoteSub v-for="note in replies" :key="note.id" :note="note" :class="$style.reply" :detail="true"/>
|
||||
</div>
|
||||
<div v-else-if="tab === 'renotes'" :class="$style.tab_renotes">
|
||||
|
@ -186,8 +208,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkPagination>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="_panel" :class="$style.muted" @click="muted = false">
|
||||
</div>
|
||||
<div v-else class="_panel" :class="$style.muted" @click="muted = false">
|
||||
<I18n :src="i18n.ts.userSaysSomething" tag="small">
|
||||
<template #name>
|
||||
<MkA v-user-preview="appearNote.userId" :to="userPage(appearNote.user)">
|
||||
|
@ -195,65 +217,65 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkA>
|
||||
</template>
|
||||
</I18n>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, onMounted, provide, ref, shallowRef } from 'vue';
|
||||
import * as mfm from 'mfm-js';
|
||||
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';
|
||||
import MkUsersTooltip from '@/components/MkUsersTooltip.vue';
|
||||
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
||||
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
|
||||
import { pleaseLogin, type OpenOnRemoteOptions } 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, 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';
|
||||
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { host } from '@/config.js';
|
||||
import { getNoteClipMenu, getNoteMenu, getRenoteMenu } from '@/scripts/get-note-menu.js';
|
||||
import { useNoteCapture } from '@/scripts/use-note-capture.js';
|
||||
import { deepClone } from '@/scripts/clone.js';
|
||||
import { useTooltip } from '@/scripts/use-tooltip.js';
|
||||
import { claimAchievement } from '@/scripts/achievements.js';
|
||||
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
||||
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';
|
||||
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
||||
import { type Keymap } from '@/scripts/hotkey.js';
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, onMounted, provide, ref, shallowRef } from 'vue';
|
||||
import * as mfm from 'mfm-js';
|
||||
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';
|
||||
import MkUsersTooltip from '@/components/MkUsersTooltip.vue';
|
||||
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
||||
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
|
||||
import { pleaseLogin, type OpenOnRemoteOptions } 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, 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';
|
||||
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { host } from '@/config.js';
|
||||
import { getNoteClipMenu, getNoteMenu, getRenoteMenu } from '@/scripts/get-note-menu.js';
|
||||
import { useNoteCapture } from '@/scripts/use-note-capture.js';
|
||||
import { deepClone } from '@/scripts/clone.js';
|
||||
import { useTooltip } from '@/scripts/use-tooltip.js';
|
||||
import { claimAchievement } from '@/scripts/achievements.js';
|
||||
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
||||
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';
|
||||
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
||||
import { type Keymap } from '@/scripts/hotkey.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
const props = withDefaults(defineProps<{
|
||||
note: Misskey.entities.Note;
|
||||
initialTab: string;
|
||||
}>(), {
|
||||
}>(), {
|
||||
initialTab: 'replies',
|
||||
});
|
||||
});
|
||||
|
||||
const inChannel = inject('inChannel', null);
|
||||
const inChannel = inject('inChannel', null);
|
||||
|
||||
const note = ref(deepClone(props.note));
|
||||
const note = ref(deepClone(props.note));
|
||||
|
||||
// plugin
|
||||
if (noteViewInterruptors.length > 0) {
|
||||
// plugin
|
||||
if (noteViewInterruptors.length > 0) {
|
||||
onMounted(async () => {
|
||||
let result: Misskey.entities.Note | null = deepClone(note.value);
|
||||
for (const interruptor of noteViewInterruptors) {
|
||||
|
@ -269,37 +291,45 @@ if (noteViewInterruptors.length > 0) {
|
|||
}
|
||||
note.value = result as Misskey.entities.Note;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const isRenote = Misskey.note.isPureRenote(note.value);
|
||||
const isRenote = Misskey.note.isPureRenote(note.value);
|
||||
|
||||
const rootEl = shallowRef<HTMLElement>();
|
||||
const menuButton = shallowRef<HTMLElement>();
|
||||
const renoteButton = shallowRef<HTMLElement>();
|
||||
const renoteTime = shallowRef<HTMLElement>();
|
||||
const reactButton = shallowRef<HTMLElement>();
|
||||
const clipButton = shallowRef<HTMLElement>();
|
||||
const appearNote = computed(() => getAppearNote(note.value));
|
||||
const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
|
||||
const isMyRenote = $i && ($i.id === note.value.userId);
|
||||
const showContent = ref(false);
|
||||
const isDeleted = ref(false);
|
||||
const muted = ref($i ? checkWordMute(appearNote.value, $i, $i.mutedWords) : false);
|
||||
const translation = ref<Misskey.entities.NotesTranslateResponse | null>(null);
|
||||
const translating = ref(false);
|
||||
const parsed = appearNote.value.text ? mfm.parse(appearNote.value.text) : null;
|
||||
const urls = parsed ? extractUrlFromMfm(parsed).filter((url) => appearNote.value.renote?.url !== url && appearNote.value.renote?.uri !== url) : null;
|
||||
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.value.user.instance);
|
||||
const conversation = ref<Misskey.entities.Note[]>([]);
|
||||
const replies = ref<Misskey.entities.Note[]>([]);
|
||||
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || appearNote.value.userId === $i?.id);
|
||||
const rootEl = shallowRef<HTMLElement>();
|
||||
const menuButton = shallowRef<HTMLElement>();
|
||||
const renoteButton = shallowRef<HTMLElement>();
|
||||
const renoteTime = shallowRef<HTMLElement>();
|
||||
const reactButton = shallowRef<HTMLElement>();
|
||||
const clipButton = shallowRef<HTMLElement>();
|
||||
const historyMenuButton = shallowRef<HTMLElement>();
|
||||
const appearNote = computed(() => getAppearNote(note.value));
|
||||
const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
|
||||
const isMyRenote = $i && ($i.id === note.value.userId);
|
||||
const showContent = ref(false);
|
||||
const isDeleted = ref(false);
|
||||
const muted = ref($i ? checkWordMute(appearNote.value, $i, $i.mutedWords) : false);
|
||||
const translation = ref<Misskey.entities.NotesTranslateResponse | null>(null);
|
||||
const translating = ref(false);
|
||||
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
|
||||
const urls = computed(() => parsed.value ? extractUrlFromMfm(parsed.value).filter((url) => appearNote.value.renote?.url !== url && appearNote.value.renote?.uri !== url) : null);
|
||||
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.value.user.instance);
|
||||
const conversation = ref<Misskey.entities.Note[]>([]);
|
||||
const replies = ref<Misskey.entities.Note[]>([]);
|
||||
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || appearNote.value.userId === $i?.id);
|
||||
|
||||
const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({
|
||||
type ShowingNoteHistoryState = {
|
||||
createdAt: string | null;
|
||||
text: string | null;
|
||||
cw?: string | null;
|
||||
} | null;
|
||||
const showingNoteHistoryRef = ref<ShowingNoteHistoryState>(null);
|
||||
|
||||
const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({
|
||||
type: 'lookup',
|
||||
url: `https://${host}/notes/${appearNote.value.id}`,
|
||||
}));
|
||||
}));
|
||||
|
||||
const keymap = {
|
||||
const keymap = {
|
||||
'r': () => reply(),
|
||||
'e|a|plus': () => react(),
|
||||
'q': () => renote(),
|
||||
|
@ -318,43 +348,43 @@ const keymap = {
|
|||
allowRepeat: true,
|
||||
callback: () => blur(),
|
||||
},
|
||||
} as const satisfies Keymap;
|
||||
} as const satisfies Keymap;
|
||||
|
||||
provide('react', (reaction: string) => {
|
||||
provide('react', (reaction: string) => {
|
||||
misskeyApi('notes/reactions/create', {
|
||||
noteId: appearNote.value.id,
|
||||
reaction: reaction,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const tab = ref(props.initialTab);
|
||||
const reactionTabType = ref<string | null>(null);
|
||||
const tab = ref(props.initialTab);
|
||||
const reactionTabType = ref<string | null>(null);
|
||||
|
||||
const renotesPagination = computed<Paging>(() => ({
|
||||
const renotesPagination = computed<Paging>(() => ({
|
||||
endpoint: 'notes/renotes',
|
||||
limit: 10,
|
||||
params: {
|
||||
noteId: appearNote.value.id,
|
||||
},
|
||||
}));
|
||||
}));
|
||||
|
||||
const reactionsPagination = computed<Paging>(() => ({
|
||||
const reactionsPagination = computed<Paging>(() => ({
|
||||
endpoint: 'notes/reactions',
|
||||
limit: 10,
|
||||
params: {
|
||||
noteId: appearNote.value.id,
|
||||
type: reactionTabType.value,
|
||||
},
|
||||
}));
|
||||
}));
|
||||
|
||||
useNoteCapture({
|
||||
useNoteCapture({
|
||||
rootEl: rootEl,
|
||||
note: appearNote,
|
||||
pureNote: note,
|
||||
isDeletedRef: isDeleted,
|
||||
});
|
||||
});
|
||||
|
||||
useTooltip(renoteButton, async (showing) => {
|
||||
useTooltip(renoteButton, async (showing) => {
|
||||
const renotes = await misskeyApi('notes/renotes', {
|
||||
noteId: appearNote.value.id,
|
||||
limit: 11,
|
||||
|
@ -372,9 +402,9 @@ useTooltip(renoteButton, async (showing) => {
|
|||
}, {
|
||||
closed: () => dispose(),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (appearNote.value.reactionAcceptance === 'likeOnly') {
|
||||
if (appearNote.value.reactionAcceptance === 'likeOnly') {
|
||||
useTooltip(reactButton, async (showing) => {
|
||||
const reactions = await misskeyApiGet('notes/reactions', {
|
||||
noteId: appearNote.value.id,
|
||||
|
@ -396,17 +426,17 @@ if (appearNote.value.reactionAcceptance === 'likeOnly') {
|
|||
closed: () => dispose(),
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renote() {
|
||||
function renote() {
|
||||
pleaseLogin(undefined, pleaseLoginContext.value);
|
||||
showMovedDialog();
|
||||
|
||||
const { menu } = getRenoteMenu({ note: note.value, renoteButton });
|
||||
os.popupMenu(menu, renoteButton.value);
|
||||
}
|
||||
}
|
||||
|
||||
function reply(): void {
|
||||
function reply(): void {
|
||||
pleaseLogin(undefined, pleaseLoginContext.value);
|
||||
showMovedDialog();
|
||||
os.post({
|
||||
|
@ -415,9 +445,9 @@ function reply(): void {
|
|||
}).then(() => {
|
||||
focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function react(): void {
|
||||
function react(): void {
|
||||
pleaseLogin(undefined, pleaseLoginContext.value);
|
||||
showMovedDialog();
|
||||
if (appearNote.value.reactionAcceptance === 'likeOnly') {
|
||||
|
@ -452,25 +482,25 @@ function react(): void {
|
|||
focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function undoReact(targetNote: Misskey.entities.Note): void {
|
||||
function undoReact(targetNote: Misskey.entities.Note): void {
|
||||
const oldReaction = targetNote.myReaction;
|
||||
if (!oldReaction) return;
|
||||
misskeyApi('notes/reactions/delete', {
|
||||
noteId: targetNote.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toggleReact() {
|
||||
function toggleReact() {
|
||||
if (appearNote.value.myReaction == null) {
|
||||
react();
|
||||
} else {
|
||||
undoReact(appearNote.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onContextmenu(ev: MouseEvent): void {
|
||||
function onContextmenu(ev: MouseEvent): void {
|
||||
const isLink = (el: HTMLElement): boolean => {
|
||||
if (el.tagName === 'A') return true;
|
||||
if (el.parentElement) {
|
||||
|
@ -489,18 +519,53 @@ function onContextmenu(ev: MouseEvent): void {
|
|||
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, isDeleted });
|
||||
os.contextMenu(menu, ev).then(focus).finally(cleanup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showMenu(): void {
|
||||
function showMenu(): void {
|
||||
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, isDeleted });
|
||||
os.popupMenu(menu, menuButton.value).then(focus).finally(cleanup);
|
||||
}
|
||||
}
|
||||
|
||||
async function clip(): Promise<void> {
|
||||
const setCurrentNoteInfo = (state: ShowingNoteHistoryState) => {
|
||||
// Set current showing
|
||||
showingNoteHistoryRef.value = state;
|
||||
};
|
||||
|
||||
const fullHistoryWithLatest = computed(() =>
|
||||
appearNote.value.updatedAt ? [{
|
||||
createdAt: appearNote.value.updatedAt,
|
||||
text: appearNote.value.text,
|
||||
cw: appearNote.value.cw,
|
||||
displayText: i18n.ts.latestVersion,
|
||||
clearState: true,
|
||||
}, ...appearNote.value.history
|
||||
.map(h => ({
|
||||
...h,
|
||||
displayText: null,
|
||||
clearState: false,
|
||||
})),
|
||||
] : [],
|
||||
);
|
||||
|
||||
function historyMenu(viaKeyboard = false): void {
|
||||
const currentNoteUpdatedAtDate = new Date(showingNoteHistoryRef.value?.createdAt || appearNote.value.updatedAt).getTime();
|
||||
const menu = fullHistoryWithLatest.value
|
||||
.sort((h1, h2) => new Date(h2.createdAt).getTime() - new Date(h1.createdAt).getTime())
|
||||
.map(h => ({
|
||||
active: new Date(h.createdAt).getTime() === currentNoteUpdatedAtDate,
|
||||
text: h.displayText || new Date(h.createdAt).toISOString(),
|
||||
action: () => setCurrentNoteInfo(h.clearState ? null : h),
|
||||
}));
|
||||
os.popupMenu(menu, historyMenuButton.value, {
|
||||
viaKeyboard,
|
||||
}).then(focus);
|
||||
}
|
||||
|
||||
async function clip(): Promise<void> {
|
||||
os.popupMenu(await getNoteClipMenu({ note: note.value, isDeleted }), clipButton.value).then(focus);
|
||||
}
|
||||
}
|
||||
|
||||
function showRenoteMenu(): void {
|
||||
function showRenoteMenu(): void {
|
||||
if (!isMyRenote) return;
|
||||
pleaseLogin(undefined, pleaseLoginContext.value);
|
||||
os.popupMenu([{
|
||||
|
@ -514,43 +579,49 @@ function showRenoteMenu(): void {
|
|||
isDeleted.value = true;
|
||||
},
|
||||
}], renoteTime.value);
|
||||
}
|
||||
}
|
||||
|
||||
function focus() {
|
||||
function focus() {
|
||||
rootEl.value?.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function blur() {
|
||||
function blur() {
|
||||
rootEl.value?.blur();
|
||||
}
|
||||
}
|
||||
|
||||
const repliesLoaded = ref(false);
|
||||
// const repliesLoaded = ref(false);
|
||||
|
||||
function loadReplies() {
|
||||
repliesLoaded.value = true;
|
||||
function loadReplies() {
|
||||
// repliesLoaded.value = true;
|
||||
misskeyApi('notes/children', {
|
||||
noteId: appearNote.value.id,
|
||||
limit: 30,
|
||||
}).then(res => {
|
||||
replies.value = res;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const conversationLoaded = ref(false);
|
||||
// const conversationLoaded = ref(false);
|
||||
|
||||
function loadConversation() {
|
||||
conversationLoaded.value = true;
|
||||
function loadConversation() {
|
||||
// conversationLoaded.value = true;
|
||||
if (appearNote.value.replyId == null) return;
|
||||
misskeyApi('notes/conversation', {
|
||||
noteId: appearNote.value.replyId,
|
||||
}).then(res => {
|
||||
conversation.value = res.reverse();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
}
|
||||
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
// Extend note content automatically (no manual click)
|
||||
onMounted(() => {
|
||||
loadReplies();
|
||||
loadConversation();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
position: relative;
|
||||
transition: box-shadow 0.1s ease;
|
||||
overflow: clip;
|
||||
|
@ -577,98 +648,98 @@ function loadConversation() {
|
|||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.replyTo {
|
||||
.replyTo {
|
||||
opacity: 0.7;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.replyToMore {
|
||||
.replyToMore {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.renote {
|
||||
.renote {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px 32px 8px 32px;
|
||||
line-height: 28px;
|
||||
white-space: pre;
|
||||
color: var(--renote);
|
||||
}
|
||||
}
|
||||
|
||||
.renoteAvatar {
|
||||
.renoteAvatar {
|
||||
flex-shrink: 0;
|
||||
display: inline-block;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
margin: 0 8px 0 0;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.renoteText {
|
||||
.renoteText {
|
||||
overflow: hidden;
|
||||
flex-shrink: 1;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.renoteName {
|
||||
.renoteName {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.renoteInfo {
|
||||
.renoteInfo {
|
||||
margin-left: auto;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
|
||||
.renoteTime {
|
||||
.renoteTime {
|
||||
flex-shrink: 0;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.renote + .note {
|
||||
.renote + .note {
|
||||
padding-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.note {
|
||||
.note {
|
||||
padding: 32px;
|
||||
font-size: 1.2em;
|
||||
|
||||
&:hover > .main > .footer > .button {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.noteHeader {
|
||||
.noteHeader {
|
||||
display: flex;
|
||||
position: relative;
|
||||
margin-bottom: 16px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.noteHeaderAvatar {
|
||||
.noteHeaderAvatar {
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
}
|
||||
}
|
||||
|
||||
.noteHeaderBody {
|
||||
.noteHeaderBody {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding-left: 16px;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
}
|
||||
|
||||
.noteHeaderName {
|
||||
.noteHeaderName {
|
||||
font-weight: bold;
|
||||
line-height: 1.3;
|
||||
}
|
||||
}
|
||||
|
||||
.isBot {
|
||||
.isBot {
|
||||
display: inline-block;
|
||||
margin: 0 0.5em;
|
||||
padding: 4px 6px;
|
||||
|
@ -676,76 +747,76 @@ function loadConversation() {
|
|||
line-height: 1;
|
||||
border: solid 0.5px var(--divider);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.noteHeaderInfo {
|
||||
.noteHeaderInfo {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.noteHeaderUsername {
|
||||
.noteHeaderUsername {
|
||||
margin-bottom: 2px;
|
||||
line-height: 1.3;
|
||||
word-wrap: anywhere;
|
||||
}
|
||||
}
|
||||
|
||||
.noteContent {
|
||||
.noteContent {
|
||||
container-type: inline-size;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.cw {
|
||||
.cw {
|
||||
cursor: default;
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.noteReplyTarget {
|
||||
.noteReplyTarget {
|
||||
color: var(--accent);
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.rn {
|
||||
.rn {
|
||||
margin-left: 4px;
|
||||
font-style: oblique;
|
||||
color: var(--renote);
|
||||
}
|
||||
}
|
||||
|
||||
.translation {
|
||||
.translation {
|
||||
border: solid 0.5px var(--divider);
|
||||
border-radius: var(--radius);
|
||||
padding: 12px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.poll {
|
||||
.poll {
|
||||
font-size: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
.quote {
|
||||
.quote {
|
||||
padding: 8px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.quoteNote {
|
||||
.quoteNote {
|
||||
padding: 16px;
|
||||
border: dashed 1px var(--renote);
|
||||
border-radius: 8px;
|
||||
overflow: clip;
|
||||
}
|
||||
}
|
||||
|
||||
.channel {
|
||||
.channel {
|
||||
opacity: 0.7;
|
||||
font-size: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
.noteFooterInfo {
|
||||
.noteFooterInfo {
|
||||
margin: 16px 0;
|
||||
opacity: 0.7;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
|
||||
.noteFooterButton {
|
||||
.noteFooterButton {
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
opacity: 0.7;
|
||||
|
@ -757,9 +828,9 @@ function loadConversation() {
|
|||
&:hover {
|
||||
color: var(--fgHighlighted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.noteFooterButtonCount {
|
||||
.noteFooterButtonCount {
|
||||
display: inline;
|
||||
margin: 0 0 0 8px;
|
||||
opacity: 0.7;
|
||||
|
@ -767,61 +838,67 @@ function loadConversation() {
|
|||
&.reacted {
|
||||
color: var(--accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reply:not(:first-child) {
|
||||
.noteFooterButtonHistoryMenu {
|
||||
&.active {
|
||||
color: var(--accent);
|
||||
}
|
||||
}
|
||||
|
||||
.reply:not(:first-child) {
|
||||
border-top: solid 0.5px var(--divider);
|
||||
}
|
||||
}
|
||||
|
||||
.tabs {
|
||||
.tabs {
|
||||
border-top: solid 0.5px var(--divider);
|
||||
border-bottom: solid 0.5px var(--divider);
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.tab {
|
||||
.tab {
|
||||
flex: 1;
|
||||
padding: 12px 8px;
|
||||
border-top: solid 2px transparent;
|
||||
border-bottom: solid 2px transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.tabActive {
|
||||
.tabActive {
|
||||
border-bottom: solid 2px var(--accent);
|
||||
}
|
||||
}
|
||||
|
||||
.tab_renotes {
|
||||
.tab_renotes {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.tab_reactions {
|
||||
.tab_reactions {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.reactionTabs {
|
||||
.reactionTabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.reactionTab {
|
||||
.reactionTab {
|
||||
padding: 4px 6px;
|
||||
border: solid 1px var(--divider);
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.reactionTabActive {
|
||||
.reactionTabActive {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
}
|
||||
|
||||
@container (max-width: 500px) {
|
||||
@container (max-width: 500px) {
|
||||
.root {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@container (max-width: 450px) {
|
||||
@container (max-width: 450px) {
|
||||
.renote {
|
||||
padding: 8px 16px 0 16px;
|
||||
}
|
||||
|
@ -834,17 +911,17 @@ function loadConversation() {
|
|||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@container (max-width: 350px) {
|
||||
@container (max-width: 350px) {
|
||||
.noteFooterButton {
|
||||
&:not(:last-child) {
|
||||
margin-right: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@container (max-width: 300px) {
|
||||
@container (max-width: 300px) {
|
||||
.root {
|
||||
font-size: 0.825em;
|
||||
}
|
||||
|
@ -859,11 +936,11 @@ function loadConversation() {
|
|||
margin-right: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.muted {
|
||||
.muted {
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Add table
Reference in a new issue