summaryrefslogtreecommitdiff
path: root/packages/frontend/src/components
diff options
context:
space:
mode:
authordakkar <dakkar@thenautilus.net>2024-12-12 13:04:51 +0000
committerdakkar <dakkar@thenautilus.net>2024-12-12 13:04:51 +0000
commit6d4ae935921ef1dcc5c908f216f6e8affc6e60c3 (patch)
tree6c1f7724b63efa8f48f1c9e21f2789f9d9c000b2 /packages/frontend/src/components
parentfix(backend): アドレス入力で直接ユーザのプロフィールペー... (diff)
parentmerge: Schedule Notes (!804) (diff)
downloadsharkey-6d4ae935921ef1dcc5c908f216f6e8affc6e60c3.tar.gz
sharkey-6d4ae935921ef1dcc5c908f216f6e8affc6e60c3.tar.bz2
sharkey-6d4ae935921ef1dcc5c908f216f6e8affc6e60c3.zip
Merge branch 'develop' into feature/2024.10
Diffstat (limited to 'packages/frontend/src/components')
-rw-r--r--packages/frontend/src/components/MkMediaList.vue6
-rw-r--r--packages/frontend/src/components/MkNote.vue2
-rw-r--r--packages/frontend/src/components/MkNoteHeader.vue5
-rw-r--r--packages/frontend/src/components/MkNoteSimple.vue53
-rw-r--r--packages/frontend/src/components/MkNotification.vue19
-rw-r--r--packages/frontend/src/components/MkPostForm.vue54
-rw-r--r--packages/frontend/src/components/MkScheduleEditor.vue65
-rw-r--r--packages/frontend/src/components/MkSchedulePostListDialog.vue62
-rw-r--r--packages/frontend/src/components/SkNote.vue2
9 files changed, 260 insertions, 8 deletions
diff --git a/packages/frontend/src/components/MkMediaList.vue b/packages/frontend/src/components/MkMediaList.vue
index 313b3b0165..487cf509d6 100644
--- a/packages/frontend/src/components/MkMediaList.vue
+++ b/packages/frontend/src/components/MkMediaList.vue
@@ -195,6 +195,12 @@ onMounted(() => {
textBox.textContent = pswp.currSlide?.data.comment;
});
+
+ // `passive: true` is for Safari compatibility, apparently
+ const stopEvent = name => textBox.addEventListener(name, event => event.stopPropagation(), { passive: true });
+ stopEvent('wheel');
+ stopEvent('pointerdown');
+ stopEvent('pointercancel');
},
});
});
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 7b3cd84c04..39f4806f0c 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkA>:
<Mfm :text="getNoteSummary(appearNote.reply)" :plain="true" :nowrap="true" :author="appearNote.reply.user" :nyaize="'respect'" :class="$style.collapsedInReplyToText" @click="inReplyToCollapsed = false"/>
</div>
- <MkNoteSub v-if="appearNote.reply && !renoteCollapsed && !inReplyToCollapsed" :note="appearNote.reply" :class="$style.replyTo"/>
+ <MkNoteSub v-if="appearNote.reply" v-show="!renoteCollapsed && !inReplyToCollapsed" :note="appearNote.reply" :class="$style.replyTo"/>
<div v-if="pinned" :class="$style.tip"><i class="ti ti-pin"></i> {{ i18n.ts.pinnedNote }}</div>
<!--<div v-if="appearNote._prId_" class="tip"><i class="ti ti-speakerphone"></i> {{ i18n.ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ i18n.ts.hideThisNote }} <i class="ti ti-x"></i></button></div>-->
<!--<div v-if="appearNote._featuredId_" class="tip"><i class="ti ti-bolt"></i> {{ i18n.ts.featured }}</div>-->
diff --git a/packages/frontend/src/components/MkNoteHeader.vue b/packages/frontend/src/components/MkNoteHeader.vue
index b01f87a121..3b15242685 100644
--- a/packages/frontend/src/components/MkNoteHeader.vue
+++ b/packages/frontend/src/components/MkNoteHeader.vue
@@ -46,7 +46,10 @@ import { popupMenu } from '@/os.js';
import { defaultStore } from '@/store.js';
const props = defineProps<{
- note: Misskey.entities.Note;
+ note: Misskey.entities.Note & {
+ isSchedule?: boolean
+ };
+ scheduled?: boolean;
}>();
const menuVersionsButton = shallowRef<HTMLElement>();
diff --git a/packages/frontend/src/components/MkNoteSimple.vue b/packages/frontend/src/components/MkNoteSimple.vue
index 273d49efd6..aabe666041 100644
--- a/packages/frontend/src/components/MkNoteSimple.vue
+++ b/packages/frontend/src/components/MkNoteSimple.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<div :class="$style.root">
+<div v-if="!isDeleted" :class="$style.root">
<MkAvatar :class="$style.avatar" :user="note.user" link preview/>
<div :class="$style.main">
<MkNoteHeader :class="$style.header" :note="note" :mini="true"/>
@@ -15,6 +15,10 @@ SPDX-License-Identifier: AGPL-3.0-only
</p>
<div v-show="note.cw == null || showContent">
<MkSubNoteContent :hideFiles="hideFiles" :class="$style.text" :note="note" :expandAllCws="props.expandAllCws"/>
+ <div v-if="note.isSchedule" style="margin-top: 10px;">
+ <MkButton :class="$style.button" inline @click.stop.prevent="editScheduleNote()"><i class="ti ti-eraser"></i> {{ i18n.ts.deleteAndEdit }}</MkButton>
+ <MkButton :class="$style.button" inline danger @click.stop.prevent="deleteScheduleNote()"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
+ </div>
</div>
</div>
</div>
@@ -24,18 +28,58 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref, watch } from 'vue';
import * as Misskey from 'misskey-js';
+import * as os from '@/os.js';
import MkNoteHeader from '@/components/MkNoteHeader.vue';
import MkSubNoteContent from '@/components/MkSubNoteContent.vue';
import MkCwButton from '@/components/MkCwButton.vue';
+import MkButton from '@/components/MkButton.vue';
import { defaultStore } from '@/store.js';
+import { i18n } from '@/i18n.js';
const props = defineProps<{
- note: Misskey.entities.Note;
+ note: Misskey.entities.Note & {
+ isSchedule? : boolean,
+ scheduledNoteId?: string
+ };
expandAllCws?: boolean;
hideFiles?: boolean;
}>();
let showContent = ref(defaultStore.state.uncollapseCW);
+const isDeleted = ref(false);
+
+const emit = defineEmits<{
+ (ev: 'editScheduleNote'): void;
+}>();
+
+async function deleteScheduleNote() {
+ const { canceled } = await os.confirm({
+ type: 'warning',
+ text: i18n.ts.deleteConfirm,
+ okText: i18n.ts.delete,
+ cancelText: i18n.ts.cancel,
+ });
+ if (canceled) return;
+ await os.apiWithDialog('notes/schedule/delete', { noteId: props.note.id })
+ .then(() => {
+ isDeleted.value = true;
+ });
+}
+
+async function editScheduleNote() {
+ await os.apiWithDialog('notes/schedule/delete', { noteId: props.note.id })
+ .then(() => {
+ isDeleted.value = true;
+ });
+
+ await os.post({
+ initialNote: props.note,
+ renote: props.note.renote,
+ reply: props.note.reply,
+ channel: props.note.channel,
+ });
+ emit('editScheduleNote');
+}
watch(() => props.expandAllCws, (expandAllCws) => {
if (expandAllCws !== showContent.value) showContent.value = expandAllCws;
@@ -50,6 +94,11 @@ watch(() => props.expandAllCws, (expandAllCws) => {
font-size: 0.95em;
}
+.button{
+ margin-right: var(--margin);
+ margin-bottom: var(--margin);
+}
+
.avatar {
flex-shrink: 0;
display: block;
diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue
index 7976cdab5b..4620b966af 100644
--- a/packages/frontend/src/components/MkNotification.vue
+++ b/packages/frontend/src/components/MkNotification.vue
@@ -6,8 +6,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div :class="$style.root">
<div :class="$style.head">
- <MkAvatar v-if="['pollEnded', 'note', 'edited'].includes(notification.type) && 'note' in notification" :class="$style.icon" :user="notification.note.user" link preview/>
- <MkAvatar v-else-if="['roleAssigned', 'achievementEarned', 'exportCompleted', 'login'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
+ <MkAvatar v-if="['pollEnded', 'note', 'edited', 'scheduledNotePosted'].includes(notification.type) && 'note' in notification" :class="$style.icon" :user="notification.note.user" link preview/>
+ <MkAvatar v-else-if="['roleAssigned', 'achievementEarned', 'exportCompleted', 'login', 'scheduledNoteFailed'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
<div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ph-smiley ph-bold ph-lg" style="line-height: 1;"></i></div>
<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ph-smiley ph-bold ph-lg" style="line-height: 1;"></i></div>
<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div>
@@ -29,6 +29,8 @@ SPDX-License-Identifier: AGPL-3.0-only
[$style.t_login]: notification.type === 'login',
[$style.t_roleAssigned]: notification.type === 'roleAssigned' && notification.role.iconUrl == null,
[$style.t_pollEnded]: notification.type === 'edited',
+ [$style.t_roleAssigned]: notification.type === 'scheduledNoteFailed',
+ [$style.t_pollEnded]: notification.type === 'scheduledNotePosted',
}]"
> <!-- we re-use t_pollEnded for "edited" instead of making an identical style -->
<i v-if="notification.type === 'follow'" class="ti ti-plus"></i>
@@ -47,6 +49,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<i v-else class="ti ti-badges"></i>
</template>
<i v-else-if="notification.type === 'edited'" class="ph-pencil ph-bold ph-lg"></i>
+ <i v-else-if="notification.type === 'scheduledNoteFailed'" class="ti ti-calendar-event"></i>
+ <i v-else-if="notification.type === 'scheduledNotePosted'" class="ti ti-calendar-event"></i>
<!-- notification.reaction が null になることはまずないが、ここでoptional chaining使うと一部ブラウザで刺さるので念の為 -->
<MkReactionIcon
v-else-if="notification.type === 'reaction'"
@@ -72,6 +76,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<span v-else-if="notification.type === 'renote:grouped'">{{ i18n.tsx._notification.renotedBySomeUsers({ n: notification.users.length }) }}</span>
<span v-else-if="notification.type === 'app'">{{ notification.header }}</span>
<span v-else-if="notification.type === 'edited'">{{ i18n.ts._notification.edited }}</span>
+ <span v-else-if="notification.type === 'scheduledNoteFailed'">{{ i18n.ts._notification.scheduledNoteFailed }}</span>
+ <span v-else-if="notification.type === 'scheduledNotePosted'">{{ i18n.ts._notification.scheduledNotePosted }}</span>
<MkTime v-if="withTime" :time="notification.createdAt" :class="$style.headerTime"/>
</header>
<div>
@@ -111,6 +117,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkA v-else-if="notification.type === 'exportCompleted'" :class="$style.text" :to="`/my/drive/file/${notification.fileId}`">
{{ i18n.ts.showFile }}
</MkA>
+ <div v-else-if="notification.type === 'scheduledNoteFailed'" :class="$style.text">
+ {{ notification.reason }}
+ </div>
<template v-else-if="notification.type === 'follow'">
<span :class="$style.text" style="opacity: 0.6;">{{ i18n.ts.youGotNewFollower }}</span>
</template>
@@ -158,6 +167,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<Mfm :text="getNoteSummary(notification.note)" :isBlock="true" :plain="true" :nowrap="true" :author="notification.note.user"/>
<i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
</MkA>
+
+ <MkA v-else-if="notification.type === 'scheduledNotePosted'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
+ <i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
+ <Mfm :text="getNoteSummary(notification.note)" :isBlock="true" :plain="true" :nowrap="true" :author="notification.note.user"/>
+ <i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
+ </MkA>
</div>
</div>
</div>
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 3bdc197cc6..11ae6dbd6a 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -77,6 +77,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<input v-show="withHashtags" ref="hashtagsInputEl" v-model="hashtags" :class="$style.hashtags" :placeholder="i18n.ts.hashtags" list="hashtags">
<XPostFormAttaches v-model="files" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName" @replaceFile="replaceFile"/>
<MkPollEditor v-if="poll" v-model="poll" @destroyed="poll = null"/>
+ <MkScheduleEditor v-if="scheduleNote" v-model="scheduleNote" @destroyed="scheduleNote = null"/>
<MkNotePreview v-if="showPreview" :class="$style.preview" :text="text" :files="files" :poll="poll ?? undefined" :useCw="useCw" :cw="cw" :user="postAccount ?? $i"/>
<div v-if="showingOptions" style="padding: 8px 16px;">
</div>
@@ -90,6 +91,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<button v-if="postFormActions.length > 0" v-tooltip="i18n.ts.plugins" class="_button" :class="$style.footerButton" @click="showActions"><i class="ti ti-plug"></i></button>
<button v-tooltip="i18n.ts.emoji" :class="['_button', $style.footerButton]" @click="insertEmoji"><i class="ti ti-mood-happy"></i></button>
<button v-if="showAddMfmFunction" v-tooltip="i18n.ts.addMfmFunction" :class="['_button', $style.footerButton]" @click="insertMfmFunction"><i class="ti ti-palette"></i></button>
+ <button v-tooltip="i18n.ts.otherSettings" :class="['_button', $style.footerButton]" @click="showOtherMenu"><i class="ti ti-dots"></i></button>
</div>
<div :class="$style.footerRight">
<button v-tooltip="i18n.ts.previewNoteText" class="_button" :class="[$style.footerButton, { [$style.previewButtonActive]: showPreview }]" @click="showPreview = !showPreview"><i class="ti ti-eye"></i></button>
@@ -110,6 +112,7 @@ import * as Misskey from 'misskey-js';
import insertTextAtCursor from 'insert-text-at-cursor';
import { toASCII } from 'punycode/';
import { host, url } from '@@/js/config.js';
+import type { MenuItem } from '@/types/menu.js';
import MkNoteSimple from '@/components/MkNoteSimple.vue';
import MkNotePreview from '@/components/MkNotePreview.vue';
import XPostFormAttaches from '@/components/MkPostFormAttaches.vue';
@@ -134,6 +137,7 @@ import { claimAchievement } from '@/scripts/achievements.js';
import { emojiPicker } from '@/scripts/emoji-picker.js';
import { mfmFunctionPicker } from '@/scripts/mfm-function-picker.js';
import type { PostFormProps } from '@/types/post-form.js';
+import MkScheduleEditor from '@/components/MkScheduleEditor.vue';
const $i = signinRequired();
@@ -195,6 +199,9 @@ const imeText = ref('');
const showingOptions = ref(false);
const textAreaReadOnly = ref(false);
const justEndedComposition = ref(false);
+const scheduleNote = ref<{
+ scheduledAt: number | null;
+} | null>(null);
const draftKey = computed((): string => {
let key = props.channel ? `channel:${props.channel.id}` : '';
@@ -367,6 +374,7 @@ function watchForDraft() {
watch(localOnly, () => saveDraft());
watch(quoteId, () => saveDraft());
watch(reactionAcceptance, () => saveDraft());
+ watch(scheduleNote, () => saveDraft());
}
function MFMWindow() {
@@ -575,6 +583,7 @@ function clear() {
files.value = [];
poll.value = null;
quoteId.value = null;
+ scheduleNote.value = null;
}
function onKeydown(ev: KeyboardEvent) {
@@ -732,6 +741,7 @@ function saveDraft() {
visibleUserIds: visibility.value === 'specified' ? visibleUsers.value.map(x => x.id) : undefined,
quoteId: quoteId.value,
reactionAcceptance: reactionAcceptance.value,
+ scheduleNote: scheduleNote.value,
},
};
@@ -839,6 +849,7 @@ async function post(ev?: MouseEvent) {
visibleUserIds: visibility.value === 'specified' ? visibleUsers.value.map(u => u.id) : undefined,
reactionAcceptance: reactionAcceptance.value,
editId: props.editId ? props.editId : undefined,
+ scheduleNote: scheduleNote.value ?? undefined,
};
if (withHashtags.value && hashtags.value && hashtags.value.trim() !== '') {
@@ -875,7 +886,7 @@ async function post(ev?: MouseEvent) {
}
posting.value = true;
- misskeyApi(postData.editId ? 'notes/edit' : 'notes/create', postData, token).then(() => {
+ misskeyApi(postData.editId ? 'notes/edit' : (postData.scheduleNote ? 'notes/schedule/create' : 'notes/create'), postData, token).then(() => {
if (props.freezeAfterPosted) {
posted.value = true;
} else {
@@ -1026,6 +1037,42 @@ function openAccountMenu(ev: MouseEvent) {
}, ev);
}
+function toggleScheduleNote() {
+ if (scheduleNote.value) {
+ scheduleNote.value = null;
+ } else {
+ scheduleNote.value = {
+ scheduledAt: null,
+ };
+ }
+}
+
+function showOtherMenu(ev: MouseEvent) {
+ const menuItems: MenuItem[] = [];
+
+ if ($i.policies.scheduleNoteMax > 0) {
+ menuItems.push({
+ type: 'button',
+ text: i18n.ts.schedulePost,
+ icon: 'ti ti-calendar-time',
+ action: toggleScheduleNote,
+ }, {
+ type: 'button',
+ text: i18n.ts.schedulePostList,
+ icon: 'ti ti-calendar-event',
+ action: () => {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkSchedulePostListDialog.vue')), {}, {
+ closed: () => {
+ dispose();
+ },
+ });
+ },
+ });
+ }
+
+ os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
+}
+
onMounted(() => {
if (props.autofocus) {
focus();
@@ -1095,6 +1142,11 @@ onMounted(() => {
}
quoteId.value = init.renote ? init.renote.id : null;
reactionAcceptance.value = init.reactionAcceptance;
+ if (init.isSchedule) {
+ scheduleNote.value = {
+ scheduledAt: new Date(init.createdAt).getTime(),
+ };
+ }
}
nextTick(() => watchForDraft());
diff --git a/packages/frontend/src/components/MkScheduleEditor.vue b/packages/frontend/src/components/MkScheduleEditor.vue
new file mode 100644
index 0000000000..60a60bed28
--- /dev/null
+++ b/packages/frontend/src/components/MkScheduleEditor.vue
@@ -0,0 +1,65 @@
+<!--
+SPDX-FileCopyrightText: syuilo and other misskey contributors
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<div style="padding: 8px 16px;">
+ <section>
+ <MkInput v-model="atDate" small type="date" class="input">
+ <template #label>{{ i18n.ts._poll.deadlineDate }}</template>
+ </MkInput>
+ <MkInput v-model="atTime" small type="time" class="input">
+ <template #label>{{ i18n.ts._poll.deadlineTime }}</template>
+ </MkInput>
+ </section>
+</div>
+</template>
+
+<script lang="ts" setup>
+import { onMounted, ref, watch } from 'vue';
+import MkInput from '@/components/MkInput.vue';
+import { formatDateTimeString } from '@/scripts/format-time-string.js';
+import { addTime } from '@/scripts/time.js';
+import { i18n } from '@/i18n.js';
+
+const props = defineProps<{
+ modelValue: {
+ scheduledAt: number | null;
+ };
+}>();
+
+const emit = defineEmits<{
+ (ev: 'update:modelValue', v: {
+ scheduledAt: number | null;
+ }): void;
+}>();
+
+const atDate = ref(formatDateTimeString(addTime(new Date(), 1, 'day'), 'yyyy-MM-dd'));
+const atTime = ref('00:00');
+
+if (props.modelValue.scheduledAt) {
+ const date = new Date(props.modelValue.scheduledAt);
+ atDate.value = formatDateTimeString(date, 'yyyy-MM-dd');
+ atTime.value = formatDateTimeString(date, 'HH:mm');
+}
+
+function get() {
+ const calcAt = () => {
+ return new Date(`${ atDate.value } ${ atTime.value }`).getTime();
+ };
+
+ return { scheduledAt: calcAt() };
+}
+
+watch([
+ atDate,
+ atTime,
+], () => emit('update:modelValue', get()), {
+ deep: true,
+});
+
+onMounted(() => {
+ emit('update:modelValue', get());
+});
+</script>
diff --git a/packages/frontend/src/components/MkSchedulePostListDialog.vue b/packages/frontend/src/components/MkSchedulePostListDialog.vue
new file mode 100644
index 0000000000..d0716ead79
--- /dev/null
+++ b/packages/frontend/src/components/MkSchedulePostListDialog.vue
@@ -0,0 +1,62 @@
+<!--
+SPDX-FileCopyrightText: syuilo and other misskey contributors
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<MkModalWindow
+ ref="dialogEl"
+ :withOkButton="false"
+ @click="cancel()"
+ @close="cancel()"
+>
+ <template #header>{{ i18n.ts.schedulePostList }}</template>
+ <MkSpacer :marginMin="14" :marginMax="16">
+ <MkPagination ref="paginationEl" :pagination="pagination">
+ <template #empty>
+ <div class="_fullinfo">
+ <img :src="infoImageUrl" class="_ghost"/>
+ <div>{{ i18n.ts.nothing }}</div>
+ </div>
+ </template>
+
+ <template #default="{ items }">
+ <div class="_gaps">
+ <MkNoteSimple v-for="item in items" :key="item.id" :scheduled="true" :note="item.note" @editScheduleNote="listUpdate"/>
+ </div>
+ </template>
+ </MkPagination>
+ </MkSpacer>
+</MkModalWindow>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue';
+import type { Paging } from '@/components/MkPagination.vue';
+import MkModalWindow from '@/components/MkModalWindow.vue';
+import MkPagination from '@/components/MkPagination.vue';
+import MkNoteSimple from '@/components/MkNoteSimple.vue';
+import { i18n } from '@/i18n.js';
+import { infoImageUrl } from '@/instance.js';
+
+const emit = defineEmits<{
+ (ev: 'cancel'): void;
+}>();
+
+const dialogEl = ref();
+const cancel = () => {
+ emit('cancel');
+ dialogEl.value.close();
+};
+
+const paginationEl = ref();
+const pagination: Paging = {
+ endpoint: 'notes/schedule/list',
+ limit: 10,
+ offsetMode: true,
+};
+
+function listUpdate() {
+ paginationEl.value.reload();
+}
+</script>
diff --git a/packages/frontend/src/components/SkNote.vue b/packages/frontend/src/components/SkNote.vue
index 3f376f8287..528e86646b 100644
--- a/packages/frontend/src/components/SkNote.vue
+++ b/packages/frontend/src/components/SkNote.vue
@@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:class="[$style.root, { [$style.showActionsOnlyHover]: defaultStore.state.showNoteActionsOnlyHover, [$style.skipRender]: defaultStore.state.skipNoteRender }]"
:tabindex="isDeleted ? '-1' : '0'"
>
- <SkNoteSub v-if="appearNote.reply && !renoteCollapsed && !inReplyToCollapsed" :note="appearNote.reply" :class="$style.replyTo"/>
+ <SkNoteSub v-if="appearNote.reply" v-show="!renoteCollapsed && !inReplyToCollapsed" :note="appearNote.reply" :class="$style.replyTo"/>
<div v-if="appearNote.reply && inReplyToCollapsed && !renoteCollapsed" :class="$style.collapsedInReplyTo">
<div :class="$style.collapsedInReplyToLine"></div>
<MkAvatar :class="$style.collapsedInReplyToAvatar" :user="appearNote.reply.user" link preview/>