|
|
|
@ -45,107 +45,102 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
<i v-else-if="note.visibility === 'followers'" class="ti ti-lock"></i>
|
|
|
|
|
<i v-else-if="note.visibility === 'specified'" ref="specified" class="ti ti-mail"></i>
|
|
|
|
|
</span>
|
|
|
|
|
<span v-if="note.localOnly" style="margin-left: 0.5em;" :title="i18n.ts._visibility['disableFederation']"><i
|
|
|
|
|
class="ti ti-rocket-off"></i></span>
|
|
|
|
|
<span v-if="note.channel" style="margin-left: 0.5em;" :title="note.channel.name"><i class="ti ti-device-tv"></i></span>
|
|
|
|
|
</div>
|
|
|
|
|
<span v-if="note.localOnly" style="margin-left: 0.5em;" :title="i18n.ts._visibility['disableFederation']"><i class="ti ti-rocket-off"></i></span>
|
|
|
|
|
<span v-if="note.channel" style="margin-left: 0.5em;" :title="note.channel.name"><i class="ti ti-device-tv"></i></span>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget">
|
|
|
|
|
<MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link preview/>
|
|
|
|
|
<Mfm :text="getNoteSummary(appearNote)" :plain="true" :nowrap="true" :author="appearNote.user"
|
|
|
|
|
:class="$style.collapsedRenoteTargetText" @click="renoteCollapsed = false"/>
|
|
|
|
|
</div>
|
|
|
|
|
<article v-else :class="$style.article" @contextmenu.stop="onContextmenu">
|
|
|
|
|
<div v-if="appearNote.channel" :class="$style.colorBar" :style="{ background: appearNote.channel.color }"></div>
|
|
|
|
|
<MkAvatar :class="$style.avatar" :user="appearNote.user" link preview/>
|
|
|
|
|
<div :class="$style.main">
|
|
|
|
|
<MkNoteHeader :note="appearNote" :mini="true"/>
|
|
|
|
|
<MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/>
|
|
|
|
|
<div style="container-type: inline-size;">
|
|
|
|
|
<p v-if="appearNote.cw != null" :class="$style.cw">
|
|
|
|
|
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user"
|
|
|
|
|
:i="$i"/>
|
|
|
|
|
<MkCwButton v-model="showContent" :note="appearNote" style="margin: 4px 0;"/>
|
|
|
|
|
</p>
|
|
|
|
|
<div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]">
|
|
|
|
|
<div :class="$style.text">
|
|
|
|
|
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
|
|
|
|
|
<MkA v-if="appearNote.replyId" :class="$style.replyIcon" :to="`/notes/${appearNote.replyId}`"><i
|
|
|
|
|
class="ti ti-arrow-back-up"></i></MkA>
|
|
|
|
|
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i"
|
|
|
|
|
:emojiUrls="appearNote.emojis"/>
|
|
|
|
|
<div v-if="translating || translation" :class="$style.translation">
|
|
|
|
|
<MkLoading v-if="translating" mini/>
|
|
|
|
|
<div v-else>
|
|
|
|
|
<b>{{ i18n.t('translatedFrom', {x: translation.sourceLang}) }}: </b>
|
|
|
|
|
<Mfm :text="translation.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget">
|
|
|
|
|
<MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link preview/>
|
|
|
|
|
<Mfm :text="getNoteSummary(appearNote)" :plain="true" :nowrap="true" :author="appearNote.user" :class="$style.collapsedRenoteTargetText" @click="renoteCollapsed = false"/>
|
|
|
|
|
</div>
|
|
|
|
|
<article v-else :class="$style.article" @contextmenu.stop="onContextmenu">
|
|
|
|
|
<div v-if="appearNote.channel" :class="$style.colorBar" :style="{ background: appearNote.channel.color }"></div>
|
|
|
|
|
<MkAvatar :class="$style.avatar" :user="appearNote.user" link preview/>
|
|
|
|
|
<div :class="$style.main">
|
|
|
|
|
<MkNoteHeader :note="appearNote" :mini="true"/>
|
|
|
|
|
<MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/>
|
|
|
|
|
<div style="container-type: inline-size;">
|
|
|
|
|
<p v-if="appearNote.cw != null" :class="$style.cw">
|
|
|
|
|
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :i="$i"/>
|
|
|
|
|
<MkCwButton v-model="showContent" :note="appearNote" style="margin: 4px 0;"/>
|
|
|
|
|
</p>
|
|
|
|
|
<div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]">
|
|
|
|
|
<div :class="$style.text">
|
|
|
|
|
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
|
|
|
|
|
<MkA v-if="appearNote.replyId" :class="$style.replyIcon" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
|
|
|
|
|
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/>
|
|
|
|
|
<div v-if="translating || translation" :class="$style.translation">
|
|
|
|
|
<MkLoading v-if="translating" mini/>
|
|
|
|
|
<div v-else>
|
|
|
|
|
<b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b>
|
|
|
|
|
<Mfm :text="translation.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="appearNote.files.length > 0">
|
|
|
|
|
<MkMediaList :mediaList="appearNote.files"/>
|
|
|
|
|
</div>
|
|
|
|
|
<MkPoll v-if="appearNote.poll" :note="appearNote" :class="$style.poll"/>
|
|
|
|
|
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false"
|
|
|
|
|
:class="$style.urlPreview"/>
|
|
|
|
|
<div v-if="appearNote.renote" :class="$style.quote">
|
|
|
|
|
<MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/>
|
|
|
|
|
</div>
|
|
|
|
|
<button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click="collapsed = false">
|
|
|
|
|
<span :class="$style.collapsedLabel">{{ i18n.ts.showMore }}</span>
|
|
|
|
|
</button>
|
|
|
|
|
<button v-else-if="isLong && !collapsed" :class="$style.showLess" class="_button" @click="collapsed = true">
|
|
|
|
|
<span :class="$style.showLessLabel">{{ i18n.ts.showLess }}</span>
|
|
|
|
|
</button>
|
|
|
|
|
</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="appearNote.files.length > 0">
|
|
|
|
|
<MkMediaList :mediaList="appearNote.files"/>
|
|
|
|
|
</div>
|
|
|
|
|
<MkPoll v-if="appearNote.poll" :note="appearNote" :class="$style.poll"/>
|
|
|
|
|
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/>
|
|
|
|
|
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
|
|
|
|
|
<button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click="collapsed = false">
|
|
|
|
|
<span :class="$style.collapsedLabel">{{ i18n.ts.showMore }}</span>
|
|
|
|
|
</button>
|
|
|
|
|
<button v-else-if="isLong && !collapsed" :class="$style.showLess" class="_button" @click="collapsed = true">
|
|
|
|
|
<span :class="$style.showLessLabel">{{ i18n.ts.showLess }}</span>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<MkReactionsViewer :note="appearNote" :maxNumber="16">
|
|
|
|
|
<template #more>
|
|
|
|
|
<div :class="$style.reactionOmitted">{{ i18n.ts.more }}</div>
|
|
|
|
|
</template>
|
|
|
|
|
</MkReactionsViewer>
|
|
|
|
|
<footer :class="$style.footer">
|
|
|
|
|
<button :class="$style.footerButton" class="_button" @click="reply()">
|
|
|
|
|
<i class="ti ti-arrow-back-up"></i>
|
|
|
|
|
<p v-if="appearNote.repliesCount > 0" :class="$style.footerButtonCount">{{ appearNote.repliesCount }}</p>
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
v-if="canRenote"
|
|
|
|
|
ref="renoteButton"
|
|
|
|
|
:class="$style.footerButton"
|
|
|
|
|
class="_button"
|
|
|
|
|
@mousedown="renote()"
|
|
|
|
|
>
|
|
|
|
|
<i class="ti ti-repeat"></i>
|
|
|
|
|
<p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ appearNote.renoteCount }}</p>
|
|
|
|
|
</button>
|
|
|
|
|
<button v-else :class="$style.footerButton" class="_button" disabled>
|
|
|
|
|
<i class="ti ti-ban"></i>
|
|
|
|
|
</button>
|
|
|
|
|
<button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.footerButton" class="_button"
|
|
|
|
|
@mousedown="react()">
|
|
|
|
|
<i v-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="$style.footerButton" class="_button"
|
|
|
|
|
@click="undoReact(appearNote)">
|
|
|
|
|
<i class="ti ti-minus"></i>
|
|
|
|
|
</button>
|
|
|
|
|
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" :class="$style.footerButton"
|
|
|
|
|
class="_button" @mousedown="clip()">
|
|
|
|
|
<i class="ti ti-paperclip"></i>
|
|
|
|
|
</button>
|
|
|
|
|
<button ref="menuButton" :class="$style.footerButton" class="_button" @mousedown="menu()">
|
|
|
|
|
<i class="ti ti-dots"></i>
|
|
|
|
|
</button>
|
|
|
|
|
</footer>
|
|
|
|
|
<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>
|
|
|
|
|
</article>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-else />
|
|
|
|
|
<MkReactionsViewer :note="appearNote" :maxNumber="16">
|
|
|
|
|
<template #more>
|
|
|
|
|
<div :class="$style.reactionOmitted">{{ i18n.ts.more }}</div>
|
|
|
|
|
</template>
|
|
|
|
|
</MkReactionsViewer>
|
|
|
|
|
<footer :class="$style.footer">
|
|
|
|
|
<button :class="$style.footerButton" class="_button" @click="reply()">
|
|
|
|
|
<i class="ti ti-arrow-back-up"></i>
|
|
|
|
|
<p v-if="appearNote.repliesCount > 0" :class="$style.footerButtonCount">{{ appearNote.repliesCount }}</p>
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
v-if="canRenote"
|
|
|
|
|
ref="renoteButton"
|
|
|
|
|
:class="$style.footerButton"
|
|
|
|
|
class="_button"
|
|
|
|
|
@mousedown="renote()"
|
|
|
|
|
>
|
|
|
|
|
<i class="ti ti-repeat"></i>
|
|
|
|
|
<p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ appearNote.renoteCount }}</p>
|
|
|
|
|
</button>
|
|
|
|
|
<button v-else :class="$style.footerButton" class="_button" disabled>
|
|
|
|
|
<i class="ti ti-ban"></i>
|
|
|
|
|
</button>
|
|
|
|
|
<button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.footerButton" class="_button" @mousedown="react()">
|
|
|
|
|
<i v-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="$style.footerButton" class="_button" @click="undoReact(appearNote)">
|
|
|
|
|
<i class="ti ti-minus"></i>
|
|
|
|
|
</button>
|
|
|
|
|
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" :class="$style.footerButton" class="_button" @mousedown="clip()">
|
|
|
|
|
<i class="ti ti-paperclip"></i>
|
|
|
|
|
</button>
|
|
|
|
|
<button ref="menuButton" :class="$style.footerButton" class="_button" @mousedown="menu()">
|
|
|
|
|
<i class="ti ti-dots"></i>
|
|
|
|
|
</button>
|
|
|
|
|
</footer>
|
|
|
|
|
</div>
|
|
|
|
|
</article>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-else-if="muted && !hideMutedNotes" :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)">
|
|
|
|
|
<MkUserName :user="appearNote.user"/>
|
|
|
|
|
</MkA>
|
|
|
|
|
</template>
|
|
|
|
|
</I18n>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
@ -228,6 +223,7 @@ const translation = ref<any>(null);
|
|
|
|
|
const translating = ref(false);
|
|
|
|
|
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.user.instance);
|
|
|
|
|
const canRenote = computed(() => ['public', 'home'].includes(appearNote.visibility) || (appearNote.visibility === 'followers' && appearNote.userId === $i.id));
|
|
|
|
|
const hideMutedNotes = defaultStore.state.hideMutedNotes;
|
|
|
|
|
let renoteCollapsed = $ref(defaultStore.state.collapseRenotes && isRenote && (($i && ($i.id === note.userId || $i.id === appearNote.userId)) || (appearNote.myReaction != null)));
|
|
|
|
|
|
|
|
|
|
const keymap = {
|
|
|
|
|