diff --git a/CHANGELOG.md b/CHANGELOG.md index 72cd8fef4..36aa3bbae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - 配列の範囲外・非整数のインデックスへの代入が完全禁止になるので注意 - Enhance: 絵文字ピッカー・オートコンプリートで、完全一致した絵文字を優先的に表示するように - Enhance: Playの説明欄にMFMを使えるように +- Enhance: チャンネルノートの場合は詳細ページからその前後のノートを見れるように - Fix: ネイティブモードの絵文字がモノクロにならないように - Fix: v2023.12.0で追加された「モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能」が管理画面上で正しく表示されていない問題を修正 - Fix: AiScriptの`readline`関数が不正な値を返すことがある問題のv2023.12.0時点での修正がPlay以外に適用されていないのを修正 diff --git a/packages/frontend/src/pages/note.vue b/packages/frontend/src/pages/note.vue index 7e353e629..4c0e9bbb9 100644 --- a/packages/frontend/src/pages/note.vue +++ b/packages/frontend/src/pages/note.vue @@ -11,11 +11,14 @@ SPDX-License-Identifier: AGPL-3.0-only <Transition :name="defaultStore.state.animation ? 'fade' : ''" mode="out-in"> <div v-if="note"> <div v-if="showNext" class="_margin"> - <MkNotes class="" :pagination="nextPagination" :noGap="true" :disableAutoLoad="true"/> + <MkNotes class="" :pagination="showNext === 'channel' ? nextChannelPagination : nextUserPagination" :noGap="true" :disableAutoLoad="true"/> </div> <div class="_margin"> - <MkButton v-if="!showNext" :class="$style.loadNext" @click="showNext = true"><i class="ti ti-chevron-up"></i></MkButton> + <div v-if="!showNext" class="_buttons" :class="$style.loadNext"> + <MkButton v-if="note.channelId" rounded :class="$style.loadButton" @click="showNext = 'channel'"><i class="ti ti-chevron-up"></i> <i class="ti ti-device-tv"></i></MkButton> + <MkButton rounded :class="$style.loadButton" @click="showNext = 'user'"><i class="ti ti-chevron-up"></i> <i class="ti ti-user"></i></MkButton> + </div> <div class="_margin _gaps_s"> <MkRemoteCaution v-if="note.user.host != null" :href="note.url ?? note.uri"/> <MkNoteDetailed :key="note.id" v-model:note="note" :class="$style.note"/> @@ -28,11 +31,14 @@ SPDX-License-Identifier: AGPL-3.0-only </MkA> </div> </div> - <MkButton v-if="!showPrev" :class="$style.loadPrev" @click="showPrev = true"><i class="ti ti-chevron-down"></i></MkButton> + <div v-if="!showPrev" class="_buttons" :class="$style.loadPrev"> + <MkButton v-if="note.channelId" rounded :class="$style.loadButton" @click="showPrev = 'channel'"><i class="ti ti-chevron-down"></i> <i class="ti ti-device-tv"></i></MkButton> + <MkButton rounded :class="$style.loadButton" @click="showPrev = 'user'"><i class="ti ti-chevron-down"></i> <i class="ti ti-user"></i></MkButton> + </div> </div> <div v-if="showPrev" class="_margin"> - <MkNotes class="" :pagination="prevPagination" :noGap="true"/> + <MkNotes class="" :pagination="showPrev === 'channel' ? prevChannelPagination : prevUserPagination" :noGap="true"/> </div> </div> <MkError v-else-if="error" @retry="fetchNote()"/> @@ -46,6 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, watch, ref } from 'vue'; import * as Misskey from 'misskey-js'; +import type { Paging } from '@/components/MkPagination.vue'; import MkNoteDetailed from '@/components/MkNoteDetailed.vue'; import MkNotes from '@/components/MkNotes.vue'; import MkRemoteCaution from '@/components/MkRemoteCaution.vue'; @@ -63,27 +70,46 @@ const props = defineProps<{ const note = ref<null | Misskey.entities.Note>(); const clips = ref<Misskey.entities.Clip[]>(); -const showPrev = ref(false); -const showNext = ref(false); +const showPrev = ref<'user' | 'channel' | false>(false); +const showNext = ref<'user' | 'channel' | false>(false); const error = ref(); -const prevPagination = { - endpoint: 'users/notes' as const, +const prevUserPagination: Paging = { + endpoint: 'users/notes', limit: 10, params: computed(() => note.value ? ({ userId: note.value.userId, untilId: note.value.id, - }) : null), + }) : undefined), }; -const nextPagination = { +const nextUserPagination: Paging = { reversed: true, - endpoint: 'users/notes' as const, + endpoint: 'users/notes', limit: 10, params: computed(() => note.value ? ({ userId: note.value.userId, sinceId: note.value.id, - }) : null), + }) : undefined), +}; + +const prevChannelPagination: Paging = { + endpoint: 'channels/timeline', + limit: 10, + params: computed(() => note.value ? ({ + channelId: note.value.channelId, + untilId: note.value.id, + }) : undefined), +}; + +const nextChannelPagination: Paging = { + reversed: true, + endpoint: 'channels/timeline', + limit: 10, + params: computed(() => note.value ? ({ + channelId: note.value.channelId, + sinceId: note.value.id, + }) : undefined), }; function fetchNote() { @@ -139,9 +165,7 @@ definePageMetadata(computed(() => note.value ? { .loadNext, .loadPrev { - min-width: 0; - margin: 0 auto; - border-radius: 999px; + justify-content: center; } .loadNext { @@ -152,6 +176,10 @@ definePageMetadata(computed(() => note.value ? { margin-top: var(--margin); } +.loadButton { + min-width: 0; +} + .note { border-radius: var(--radius); background: var(--panel);