summaryrefslogtreecommitdiff
path: root/packages/frontend/src
diff options
context:
space:
mode:
authorsyuilo <4439005+syuilo@users.noreply.github.com>2025-06-25 20:26:20 +0900
committersyuilo <4439005+syuilo@users.noreply.github.com>2025-06-25 20:26:20 +0900
commiteee9a5f85310ea7042e42e6bc40ecff3b682d9fd (patch)
tree28bdc85a6824a57c8a39a0feb7af2e051e7485cd /packages/frontend/src
parentBump version to 2025.6.4-alpha.0 (diff)
downloadmisskey-eee9a5f85310ea7042e42e6bc40ecff3b682d9fd.tar.gz
misskey-eee9a5f85310ea7042e42e6bc40ecff3b682d9fd.tar.bz2
misskey-eee9a5f85310ea7042e42e6bc40ecff3b682d9fd.zip
enhance(frontend): ページネーションの並び順を逆にできるように
Diffstat (limited to 'packages/frontend/src')
-rw-r--r--packages/frontend/src/components/MkNoteDraftsDialog.vue12
-rw-r--r--packages/frontend/src/components/MkNotesTimeline.vue4
-rw-r--r--packages/frontend/src/components/MkPagination.vue96
-rw-r--r--packages/frontend/src/composables/use-pagination.ts37
-rw-r--r--packages/frontend/src/pages/my-clips/index.vue2
-rw-r--r--packages/frontend/src/pages/my-lists/list.vue2
-rw-r--r--packages/frontend/src/pages/note.vue19
-rw-r--r--packages/frontend/src/pages/settings/connect.vue2
-rw-r--r--packages/frontend/src/pages/settings/mute-block.vue6
-rw-r--r--packages/frontend/src/pages/settings/security.vue2
-rw-r--r--packages/frontend/src/pages/user/clips.vue2
-rw-r--r--packages/frontend/src/pages/user/files.vue2
-rw-r--r--packages/frontend/src/pages/user/flashs.vue2
-rw-r--r--packages/frontend/src/pages/user/follow-list.vue2
-rw-r--r--packages/frontend/src/pages/user/gallery.vue2
-rw-r--r--packages/frontend/src/pages/user/lists.vue2
-rw-r--r--packages/frontend/src/pages/user/pages.vue2
-rw-r--r--packages/frontend/src/pages/user/reactions.vue2
18 files changed, 121 insertions, 77 deletions
diff --git a/packages/frontend/src/components/MkNoteDraftsDialog.vue b/packages/frontend/src/components/MkNoteDraftsDialog.vue
index b4aff8d16f..eb103a8423 100644
--- a/packages/frontend/src/components/MkNoteDraftsDialog.vue
+++ b/packages/frontend/src/components/MkNoteDraftsDialog.vue
@@ -17,14 +17,14 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header>
{{ i18n.ts.drafts }} ({{ currentDraftsCount }}/{{ $i?.policies.noteDraftLimit }})
</template>
- <div :class="$style.drafts" class="_gaps">
- <MkPagination ref="pagingEl" :pagination="paging">
+ <div class="_spacer">
+ <MkPagination ref="pagingEl" :pagination="paging" withControl>
<template #empty>
<MkResult type="empty" :text="i18n.ts._drafts.noDrafts"/>
</template>
<template #default="{ items }">
- <div class="_spacer _gaps_s">
+ <div class="_gaps_s">
<div
v-for="draft in (items as unknown as Misskey.entities.NoteDraft[])"
:key="draft.id"
@@ -157,12 +157,6 @@ async function deleteDraft(draft: Misskey.entities.NoteDraft) {
</script>
<style lang="scss" module>
-.drafts {
- overflow-x: hidden;
- overflow-x: clip;
- overflow-y: auto;
-}
-
.draft {
padding: 16px;
gap: 16px;
diff --git a/packages/frontend/src/components/MkNotesTimeline.vue b/packages/frontend/src/components/MkNotesTimeline.vue
index a500bab8e6..401cef62bb 100644
--- a/packages/frontend/src/components/MkNotesTimeline.vue
+++ b/packages/frontend/src/components/MkNotesTimeline.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<MkPagination ref="pagingComponent" :pagination="pagination" :disableAutoLoad="disableAutoLoad" :pullToRefresh="pullToRefresh">
+<MkPagination ref="pagingComponent" :pagination="pagination" :disableAutoLoad="disableAutoLoad" :pullToRefresh="pullToRefresh" :withControl="withControl">
<template #empty><MkResult type="empty" :text="i18n.ts.noNotes"/></template>
<template #default="{ items: notes }">
@@ -45,8 +45,10 @@ const props = withDefaults(defineProps<{
noGap?: boolean;
disableAutoLoad?: boolean;
pullToRefresh?: boolean;
+ withControl?: boolean;
}>(), {
pullToRefresh: true,
+ withControl: true,
});
const pagingComponent = useTemplateRef('pagingComponent');
diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue
index aded18f220..d34646ba75 100644
--- a/packages/frontend/src/components/MkPagination.vue
+++ b/packages/frontend/src/components/MkPagination.vue
@@ -5,50 +5,60 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<component :is="prefer.s.enablePullToRefresh && pullToRefresh ? MkPullToRefresh : 'div'" :refresher="() => paginator.reload()" @contextmenu.prevent.stop="onContextmenu">
- <!-- :css="prefer.s.animation" にしたいけどバグる(おそらくvueのバグ) https://github.com/misskey-dev/misskey/issues/16078 -->
- <Transition
- :enterActiveClass="prefer.s.animation ? $style.transition_fade_enterActive : ''"
- :leaveActiveClass="prefer.s.animation ? $style.transition_fade_leaveActive : ''"
- :enterFromClass="prefer.s.animation ? $style.transition_fade_enterFrom : ''"
- :leaveToClass="prefer.s.animation ? $style.transition_fade_leaveTo : ''"
- mode="out-in"
- >
- <MkLoading v-if="paginator.fetching.value"/>
+ <div>
+ <div v-if="props.withControl" :class="$style.control">
+ <MkSelect v-model="order" :class="$style.order" :items="[{ label: i18n.ts._order.newest, value: 'newest' }, { label: i18n.ts._order.oldest, value: 'oldest' }]">
+ </MkSelect>
+ <MkButton iconOnly @click="paginator.reload()"><i class="ti ti-refresh"></i></MkButton>
+ </div>
- <MkError v-else-if="paginator.error.value" @retry="paginator.init()"/>
+ <!-- :css="prefer.s.animation" にしたいけどバグる(おそらくvueのバグ) https://github.com/misskey-dev/misskey/issues/16078 -->
+ <Transition
+ :enterActiveClass="prefer.s.animation ? $style.transition_fade_enterActive : ''"
+ :leaveActiveClass="prefer.s.animation ? $style.transition_fade_leaveActive : ''"
+ :enterFromClass="prefer.s.animation ? $style.transition_fade_enterFrom : ''"
+ :leaveToClass="prefer.s.animation ? $style.transition_fade_leaveTo : ''"
+ mode="out-in"
+ >
+ <MkLoading v-if="paginator.fetching.value"/>
- <div v-else-if="paginator.items.value.length === 0" key="_empty_">
- <slot name="empty"><MkResult type="empty"/></slot>
- </div>
+ <MkError v-else-if="paginator.error.value" @retry="paginator.init()"/>
- <div v-else ref="rootEl" class="_gaps">
- <div v-show="pagination.reversed && paginator.canFetchOlder.value" key="_more_">
- <MkButton v-if="!paginator.fetchingOlder.value" v-appear="(prefer.s.enableInfiniteScroll && !props.disableAutoLoad) ? appearFetchMoreAhead : null" :class="$style.more" :wait="paginator.fetchingOlder.value" primary rounded @click="paginator.fetchNewer">
- {{ i18n.ts.loadMore }}
- </MkButton>
- <MkLoading v-else/>
+ <div v-else-if="paginator.items.value.length === 0" key="_empty_">
+ <slot name="empty"><MkResult type="empty"/></slot>
</div>
- <slot :items="paginator.items.value" :fetching="paginator.fetching.value || paginator.fetchingOlder.value"></slot>
- <div v-show="!pagination.reversed && paginator.canFetchOlder.value" key="_more_">
- <MkButton v-if="!paginator.fetchingOlder.value" v-appear="(prefer.s.enableInfiniteScroll && !props.disableAutoLoad) ? appearFetchMore : null" :class="$style.more" :wait="paginator.fetchingOlder.value" primary rounded @click="paginator.fetchOlder">
- {{ i18n.ts.loadMore }}
- </MkButton>
- <MkLoading v-else/>
+
+ <div v-else key="_root_" class="_gaps">
+ <slot :items="paginator.items.value" :fetching="paginator.fetching.value || paginator.fetchingOlder.value"></slot>
+ <div v-if="order === 'oldest'">
+ <MkButton v-if="!paginator.fetchingNewer.value" :class="$style.more" :wait="paginator.fetchingNewer.value" primary rounded @click="paginator.fetchNewer">
+ {{ i18n.ts.loadMore }}
+ </MkButton>
+ <MkLoading v-else/>
+ </div>
+ <div v-else v-show="paginator.canFetchOlder.value">
+ <MkButton v-if="!paginator.fetchingOlder.value" :class="$style.more" :wait="paginator.fetchingOlder.value" primary rounded @click="paginator.fetchOlder">
+ {{ i18n.ts.loadMore }}
+ </MkButton>
+ <MkLoading v-else/>
+ </div>
</div>
- </div>
- </Transition>
+ </Transition>
+ </div>
</component>
</template>
<script lang="ts" setup generic="T extends PagingCtx">
import { isLink } from '@@/js/is-link.js';
-import type { PagingCtx } from '@/composables/use-pagination.js';
+import { ref, watch } from 'vue';
import type { UnwrapRef } from 'vue';
+import type { PagingCtx } from '@/composables/use-pagination.js';
import MkButton from '@/components/MkButton.vue';
import { i18n } from '@/i18n.js';
import { prefer } from '@/preferences.js';
import { usePagination } from '@/composables/use-pagination.js';
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
+import MkSelect from '@/components/MkSelect.vue';
import * as os from '@/os.js';
type Paginator = ReturnType<typeof usePagination<T['endpoint']>>;
@@ -58,27 +68,32 @@ const props = withDefaults(defineProps<{
disableAutoLoad?: boolean;
displayLimit?: number;
pullToRefresh?: boolean;
+ withControl?: boolean;
}>(), {
displayLimit: 20,
pullToRefresh: true,
+ withControl: false,
});
+const order = ref<'newest' | 'oldest'>(props.pagination.order ?? 'newest');
+
const paginator: Paginator = usePagination({
ctx: props.pagination,
});
-function appearFetchMoreAhead() {
- paginator.fetchNewer();
-}
-
-function appearFetchMore() {
- paginator.fetchOlder();
-}
+watch(order, (newOrder) => {
+ paginator.updateCtx({
+ ...props.pagination,
+ order: newOrder,
+ initialDirection: newOrder === 'oldest' ? 'newer' : 'older',
+ });
+}, { immediate: false });
function onContextmenu(ev: MouseEvent) {
if (ev.target && isLink(ev.target as HTMLElement)) return;
if (window.getSelection()?.toString() !== '') return;
+ // TODO: 並び順設定
os.contextMenu([{
icon: 'ti ti-refresh',
text: i18n.ts.reload,
@@ -108,6 +123,17 @@ defineExpose({
opacity: 0;
}
+.control {
+ display: flex;
+ align-items: center;
+ margin-bottom: 10px;
+}
+
+.order {
+ flex: 1;
+ margin-right: 8px;
+}
+
.more {
margin-left: auto;
margin-right: auto;
diff --git a/packages/frontend/src/composables/use-pagination.ts b/packages/frontend/src/composables/use-pagination.ts
index 6a9f00bb91..ed891c0b14 100644
--- a/packages/frontend/src/composables/use-pagination.ts
+++ b/packages/frontend/src/composables/use-pagination.ts
@@ -33,8 +33,14 @@ export type PagingCtx<E extends keyof Misskey.Endpoints = keyof Misskey.Endpoint
offsetMode?: boolean;
- baseId?: MisskeyEntity['id'];
- direction?: 'newer' | 'older';
+ initialId?: MisskeyEntity['id'];
+ initialDirection?: 'newer' | 'older';
+
+ // 配列内の要素をどのような順序で並べるか
+ // newest: 新しいものが先頭 (default)
+ // oldest: 古いものが先頭
+ // NOTE: このようなプロパティを用意してこっち側で並びを管理せずに、Setで持っておき参照者側が好きに並び変えるような設計の方がすっきりしそうなものの、Vueのレンダリングのたびに並び替え処理が発生することになったりしそうでパフォーマンス上の懸念がある
+ order?: 'newest' | 'oldest';
// 一部のAPIはさらに遡れる場合でもパフォーマンス上の理由でlimit以下の結果を返す場合があり、その場合はsafe、それ以外はlimitにすることを推奨
canFetchDetection?: 'safe' | 'limit';
@@ -51,6 +57,7 @@ export function usePagination<Endpoint extends keyof Misskey.Endpoints, T extend
const queuedAheadItemsCount = ref(0);
const fetching = ref(true);
const fetchingOlder = ref(false);
+ const fetchingNewer = ref(false);
const canFetchOlder = ref(false);
const error = ref(false);
@@ -82,14 +89,14 @@ export function usePagination<Endpoint extends keyof Misskey.Endpoints, T extend
...params,
limit: props.ctx.limit ?? FIRST_FETCH_LIMIT,
allowPartial: true,
- ...(props.ctx.baseId && props.ctx.direction === 'newer' ? {
- sinceId: props.ctx.baseId,
- } : props.ctx.baseId && props.ctx.direction === 'older' ? {
- untilId: props.ctx.baseId,
+ ...(props.ctx.initialDirection === 'newer' ? {
+ sinceId: props.ctx.initialId ?? '0',
+ } : props.ctx.initialId && props.ctx.initialDirection === 'older' ? {
+ untilId: props.ctx.initialId,
} : {}),
}).then(res => {
// 逆順で返ってくるので
- if (props.ctx.baseId && props.ctx.direction === 'newer') {
+ if (props.ctx.initialId && props.ctx.initialDirection === 'newer') {
res.reverse();
}
@@ -167,6 +174,7 @@ export function usePagination<Endpoint extends keyof Misskey.Endpoints, T extend
async function fetchNewer(options: {
toQueue?: boolean;
} = {}): Promise<void> {
+ fetchingNewer.value = true;
const params = props.ctx.params ? isRef(props.ctx.params) ? props.ctx.params.value : props.ctx.params : {};
await misskeyApi<T[]>(props.ctx.endpoint, {
...params,
@@ -186,8 +194,14 @@ export function usePagination<Endpoint extends keyof Misskey.Endpoints, T extend
}
queuedAheadItemsCount.value = aheadQueue.length;
} else {
- unshiftItems(res.toReversed());
+ if (props.ctx.order === 'oldest') {
+ pushItems(res);
+ } else {
+ unshiftItems(res.toReversed());
+ }
}
+ }).finally(() => {
+ fetchingNewer.value = false;
});
}
@@ -253,6 +267,11 @@ export function usePagination<Endpoint extends keyof Misskey.Endpoints, T extend
}
}
+ function updateCtx(ctx: PagingCtx<Endpoint>) {
+ props.ctx = ctx;
+ reload();
+ }
+
if (props.autoInit !== false) {
onMounted(() => {
init();
@@ -264,6 +283,7 @@ export function usePagination<Endpoint extends keyof Misskey.Endpoints, T extend
queuedAheadItemsCount,
fetching,
fetchingOlder,
+ fetchingNewer,
canFetchOlder,
init,
reload,
@@ -277,5 +297,6 @@ export function usePagination<Endpoint extends keyof Misskey.Endpoints, T extend
enqueue,
releaseQueue,
error,
+ updateCtx,
};
}
diff --git a/packages/frontend/src/pages/my-clips/index.vue b/packages/frontend/src/pages/my-clips/index.vue
index c386ed7239..4477edf505 100644
--- a/packages/frontend/src/pages/my-clips/index.vue
+++ b/packages/frontend/src/pages/my-clips/index.vue
@@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="tab === 'my'" class="_gaps">
<MkButton primary rounded class="add" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
- <MkPagination v-slot="{ items }" ref="pagingComponent" :pagination="pagination" class="_gaps">
+ <MkPagination v-slot="{ items }" ref="pagingComponent" :pagination="pagination" class="_gaps" withControl>
<MkClipPreview v-for="item in items" :key="item.id" :clip="item" :noUserInfo="true"/>
</MkPagination>
</div>
diff --git a/packages/frontend/src/pages/my-lists/list.vue b/packages/frontend/src/pages/my-lists/list.vue
index 06abe3d7fd..e33125ac93 100644
--- a/packages/frontend/src/pages/my-lists/list.vue
+++ b/packages/frontend/src/pages/my-lists/list.vue
@@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps_s">
<MkButton rounded primary style="margin: 0 auto;" @click="addUser()">{{ i18n.ts.addUser }}</MkButton>
- <MkPagination ref="paginationEl" :pagination="membershipsPagination">
+ <MkPagination ref="paginationEl" :pagination="membershipsPagination" withControl>
<template #default="{ items }">
<div class="_gaps_s">
<div v-for="item in items" :key="item.id">
diff --git a/packages/frontend/src/pages/note.vue b/packages/frontend/src/pages/note.vue
index 8a645e417c..ccb62749fa 100644
--- a/packages/frontend/src/pages/note.vue
+++ b/packages/frontend/src/pages/note.vue
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in">
<div v-if="note">
<div v-if="showNext" class="_margin">
- <MkNotesTimeline :pullToRefresh="false" class="" :pagination="showNext === 'channel' ? nextChannelPagination : nextUserPagination" :noGap="true" :disableAutoLoad="true"/>
+ <MkNotesTimeline :withControl="false" :pullToRefresh="false" class="" :pagination="showNext === 'channel' ? nextChannelPagination : nextUserPagination" :noGap="true" :disableAutoLoad="true"/>
</div>
<div class="_margin">
@@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div v-if="showPrev" class="_margin">
- <MkNotesTimeline :pullToRefresh="false" class="" :pagination="showPrev === 'channel' ? prevChannelPagination : prevUserPagination" :noGap="true"/>
+ <MkNotesTimeline :withControl="false" :pullToRefresh="false" class="" :pagination="showPrev === 'channel' ? prevChannelPagination : prevUserPagination" :noGap="true"/>
</div>
</div>
<MkError v-else-if="error" @retry="fetchNote()"/>
@@ -81,8 +81,8 @@ const error = ref();
const prevUserPagination: PagingCtx = {
endpoint: 'users/notes',
limit: 10,
- baseId: props.noteId,
- direction: 'older',
+ initialId: props.noteId,
+ initialDirection: 'older',
params: computed(() => note.value ? ({
userId: note.value.userId,
}) : undefined),
@@ -91,8 +91,8 @@ const prevUserPagination: PagingCtx = {
const nextUserPagination: PagingCtx = {
endpoint: 'users/notes',
limit: 10,
- baseId: props.noteId,
- direction: 'newer',
+ initialId: props.noteId,
+ initialDirection: 'newer',
params: computed(() => note.value ? ({
userId: note.value.userId,
}) : undefined),
@@ -101,19 +101,20 @@ const nextUserPagination: PagingCtx = {
const prevChannelPagination: PagingCtx = {
endpoint: 'channels/timeline',
limit: 10,
+ initialId: props.noteId,
+ initialDirection: 'older',
params: computed(() => note.value ? ({
channelId: note.value.channelId,
- untilId: note.value.id,
}) : undefined),
};
const nextChannelPagination: PagingCtx = {
- reversed: true,
endpoint: 'channels/timeline',
limit: 10,
+ initialId: props.noteId,
+ initialDirection: 'newer',
params: computed(() => note.value ? ({
channelId: note.value.channelId,
- sinceId: note.value.id,
}) : undefined),
};
diff --git a/packages/frontend/src/pages/settings/connect.vue b/packages/frontend/src/pages/settings/connect.vue
index 959442d25f..c2335ae69f 100644
--- a/packages/frontend/src/pages/settings/connect.vue
+++ b/packages/frontend/src/pages/settings/connect.vue
@@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkFolder :defaultOpen="true">
<template #label>{{ i18n.ts.manage }}</template>
- <MkPagination :pagination="pagination">
+ <MkPagination :pagination="pagination" withControl>
<template #default="{items}">
<div class="_gaps">
<FormLink v-for="webhook in items" :key="webhook.id" :to="`/settings/webhook/edit/${webhook.id}`">
diff --git a/packages/frontend/src/pages/settings/mute-block.vue b/packages/frontend/src/pages/settings/mute-block.vue
index 9407845923..755bc79b6a 100644
--- a/packages/frontend/src/pages/settings/mute-block.vue
+++ b/packages/frontend/src/pages/settings/mute-block.vue
@@ -80,7 +80,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #icon><i class="ti ti-repeat-off"></i></template>
<template #label><SearchLabel>{{ i18n.ts.mutedUsers }} ({{ i18n.ts.renote }})</SearchLabel></template>
- <MkPagination :pagination="renoteMutingPagination">
+ <MkPagination :pagination="renoteMutingPagination" withControl>
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
<template #default="{ items }">
@@ -111,7 +111,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #icon><i class="ti ti-eye-off"></i></template>
<template #label>{{ i18n.ts.mutedUsers }}</template>
- <MkPagination :pagination="mutingPagination">
+ <MkPagination :pagination="mutingPagination" withControl>
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
<template #default="{ items }">
@@ -144,7 +144,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #icon><i class="ti ti-ban"></i></template>
<template #label>{{ i18n.ts.blockedUsers }}</template>
- <MkPagination :pagination="blockingPagination">
+ <MkPagination :pagination="blockingPagination" withControl>
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
<template #default="{ items }">
diff --git a/packages/frontend/src/pages/settings/security.vue b/packages/frontend/src/pages/settings/security.vue
index 391118effd..c260ae4541 100644
--- a/packages/frontend/src/pages/settings/security.vue
+++ b/packages/frontend/src/pages/settings/security.vue
@@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<FormSection>
<template #label>{{ i18n.ts.signinHistory }}</template>
- <MkPagination :pagination="pagination" disableAutoLoad>
+ <MkPagination :pagination="pagination" disableAutoLoad withControl>
<template #default="{items}">
<div>
<div v-for="item in items" :key="item.id" v-panel class="timnmucd">
diff --git a/packages/frontend/src/pages/user/clips.vue b/packages/frontend/src/pages/user/clips.vue
index c980c83a26..5b5bc3193f 100644
--- a/packages/frontend/src/pages/user/clips.vue
+++ b/packages/frontend/src/pages/user/clips.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="_spacer" style="--MI_SPACER-w: 700px;">
<div>
- <MkPagination v-slot="{items}" ref="list" :pagination="pagination">
+ <MkPagination v-slot="{items}" :pagination="pagination" withControl>
<MkA v-for="item in items" :key="item.id" :to="`/clips/${item.id}`" :class="$style.item" class="_panel _margin">
<b>{{ item.name }}</b>
<div v-if="item.description" :class="$style.description">{{ item.description }}</div>
diff --git a/packages/frontend/src/pages/user/files.vue b/packages/frontend/src/pages/user/files.vue
index 51ae809aac..339daea257 100644
--- a/packages/frontend/src/pages/user/files.vue
+++ b/packages/frontend/src/pages/user/files.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="_spacer" style="--MI_SPACER-w: 1100px;">
<div :class="$style.root">
- <MkPagination v-slot="{items}" :pagination="pagination">
+ <MkPagination v-slot="{items}" :pagination="pagination" withControl>
<div :class="$style.stream">
<MkNoteMediaGrid v-for="note in items" :note="note" square/>
</div>
diff --git a/packages/frontend/src/pages/user/flashs.vue b/packages/frontend/src/pages/user/flashs.vue
index 16957a5a2b..fc1d4e5968 100644
--- a/packages/frontend/src/pages/user/flashs.vue
+++ b/packages/frontend/src/pages/user/flashs.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="_spacer" style="--MI_SPACER-w: 700px;">
- <MkPagination v-slot="{items}" ref="list" :pagination="pagination">
+ <MkPagination v-slot="{items}" :pagination="pagination" withControl>
<MkFlashPreview v-for="flash in items" :key="flash.id" :flash="flash" class="_margin"/>
</MkPagination>
</div>
diff --git a/packages/frontend/src/pages/user/follow-list.vue b/packages/frontend/src/pages/user/follow-list.vue
index 868767e8f4..2c3eb40f72 100644
--- a/packages/frontend/src/pages/user/follow-list.vue
+++ b/packages/frontend/src/pages/user/follow-list.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div>
- <MkPagination v-slot="{items}" ref="list" :pagination="type === 'following' ? followingPagination : followersPagination">
+ <MkPagination v-slot="{items}" :pagination="type === 'following' ? followingPagination : followersPagination" withControl>
<div :class="$style.users">
<MkUserInfo v-for="user in items.map(x => type === 'following' ? x.followee : x.follower)" :key="user.id" :user="user"/>
</div>
diff --git a/packages/frontend/src/pages/user/gallery.vue b/packages/frontend/src/pages/user/gallery.vue
index 11874bfd87..12a9d2b1ab 100644
--- a/packages/frontend/src/pages/user/gallery.vue
+++ b/packages/frontend/src/pages/user/gallery.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="_spacer" style="--MI_SPACER-w: 700px;">
- <MkPagination v-slot="{items}" :pagination="pagination">
+ <MkPagination v-slot="{items}" :pagination="pagination" withControl>
<div :class="$style.root">
<MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/>
</div>
diff --git a/packages/frontend/src/pages/user/lists.vue b/packages/frontend/src/pages/user/lists.vue
index 18cbf9d017..5792c8faaf 100644
--- a/packages/frontend/src/pages/user/lists.vue
+++ b/packages/frontend/src/pages/user/lists.vue
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkStickyContainer>
<div class="_spacer" style="--MI_SPACER-w: 700px;">
<div>
- <MkPagination v-slot="{items}" ref="pagingComponent" :pagination="pagination" class="lists">
+ <MkPagination v-slot="{items}" ref="pagingComponent" :pagination="pagination" withControl>
<MkA v-for="list in items" :key="list.id" class="_panel" :class="$style.list" :to="`/list/${ list.id }`">
<div>{{ list.name }}</div>
<MkAvatars :userIds="list.userIds"/>
diff --git a/packages/frontend/src/pages/user/pages.vue b/packages/frontend/src/pages/user/pages.vue
index fe6141285e..1037f66b7e 100644
--- a/packages/frontend/src/pages/user/pages.vue
+++ b/packages/frontend/src/pages/user/pages.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="_spacer" style="--MI_SPACER-w: 700px;">
- <MkPagination v-slot="{items}" ref="list" :pagination="pagination">
+ <MkPagination v-slot="{items}" :pagination="pagination" withControl>
<MkPagePreview v-for="page in items" :key="page.id" :page="page" class="_margin"/>
</MkPagination>
</div>
diff --git a/packages/frontend/src/pages/user/reactions.vue b/packages/frontend/src/pages/user/reactions.vue
index 9b7a3bc3bd..28efd1a474 100644
--- a/packages/frontend/src/pages/user/reactions.vue
+++ b/packages/frontend/src/pages/user/reactions.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="_spacer" style="--MI_SPACER-w: 700px;">
- <MkPagination v-slot="{items}" ref="list" :pagination="pagination">
+ <MkPagination v-slot="{items}" :pagination="pagination">
<div v-for="item in items" :key="item.id" :to="`/clips/${item.id}`" class="_panel _margin">
<div :class="$style.header">
<MkAvatar :class="$style.avatar" :user="user"/>