summaryrefslogtreecommitdiff
path: root/packages/frontend/src/pages
diff options
context:
space:
mode:
authorsyuilo <4439005+syuilo@users.noreply.github.com>2025-06-29 15:11:25 +0900
committersyuilo <4439005+syuilo@users.noreply.github.com>2025-06-29 15:11:25 +0900
commitf1deb89e348eb8f1a39b51e33a0ae33d59529feb (patch)
tree2e92a7a21a1bf377719e1b125a9ac44bc14a529e /packages/frontend/src/pages
parentfeat(backend): クリップ内でノートを検索できるように (diff)
downloadmisskey-f1deb89e348eb8f1a39b51e33a0ae33d59529feb.tar.gz
misskey-f1deb89e348eb8f1a39b51e33a0ae33d59529feb.tar.bz2
misskey-f1deb89e348eb8f1a39b51e33a0ae33d59529feb.zip
refactor(frontend): improve pagination implementation
Diffstat (limited to 'packages/frontend/src/pages')
-rw-r--r--packages/frontend/src/pages/about.federation.vue14
-rw-r--r--packages/frontend/src/pages/admin-user.vue21
-rw-r--r--packages/frontend/src/pages/admin/abuses.vue18
-rw-r--r--packages/frontend/src/pages/admin/federation.vue12
-rw-r--r--packages/frontend/src/pages/admin/files.vue15
-rw-r--r--packages/frontend/src/pages/admin/invites.vue23
-rw-r--r--packages/frontend/src/pages/admin/modlog.vue40
-rw-r--r--packages/frontend/src/pages/admin/roles.role.vue12
-rw-r--r--packages/frontend/src/pages/admin/users.vue17
-rw-r--r--packages/frontend/src/pages/announcements.vue29
-rw-r--r--packages/frontend/src/pages/channel.vue21
-rw-r--r--packages/frontend/src/pages/channels.vue42
-rw-r--r--packages/frontend/src/pages/clip.vue13
-rw-r--r--packages/frontend/src/pages/custom-emojis-manager.vue43
-rw-r--r--packages/frontend/src/pages/drive.file.notes.vue11
-rw-r--r--packages/frontend/src/pages/explore.featured.vue17
-rw-r--r--packages/frontend/src/pages/explore.users.vue110
-rw-r--r--packages/frontend/src/pages/favorites.vue9
-rw-r--r--packages/frontend/src/pages/flash/flash-index.vue24
-rw-r--r--packages/frontend/src/pages/follow-requests.vue34
-rw-r--r--packages/frontend/src/pages/gallery/index.vue40
-rw-r--r--packages/frontend/src/pages/gallery/post.vue12
-rw-r--r--packages/frontend/src/pages/instance-info.vue19
-rw-r--r--packages/frontend/src/pages/invite.vue18
-rw-r--r--packages/frontend/src/pages/my-clips/index.vue34
-rw-r--r--packages/frontend/src/pages/my-lists/list.vue19
-rw-r--r--packages/frontend/src/pages/note.vue36
-rw-r--r--packages/frontend/src/pages/notifications.vue17
-rw-r--r--packages/frontend/src/pages/page.vue12
-rw-r--r--packages/frontend/src/pages/pages.vue24
-rw-r--r--packages/frontend/src/pages/reversi/index.vue17
-rw-r--r--packages/frontend/src/pages/role.vue12
-rw-r--r--packages/frontend/src/pages/search.note.vue17
-rw-r--r--packages/frontend/src/pages/search.user.vue15
-rw-r--r--packages/frontend/src/pages/settings/apps.vue18
-rw-r--r--packages/frontend/src/pages/settings/connect.vue10
-rw-r--r--packages/frontend/src/pages/settings/drive-cleaner.vue14
-rw-r--r--packages/frontend/src/pages/settings/mute-block.vue24
-rw-r--r--packages/frontend/src/pages/settings/security.vue10
-rw-r--r--packages/frontend/src/pages/tag.vue16
-rw-r--r--packages/frontend/src/pages/user-tag.vue12
-rw-r--r--packages/frontend/src/pages/user/clips.vue12
-rw-r--r--packages/frontend/src/pages/user/files.vue13
-rw-r--r--packages/frontend/src/pages/user/flashs.vue12
-rw-r--r--packages/frontend/src/pages/user/follow-list.vue19
-rw-r--r--packages/frontend/src/pages/user/gallery.vue12
-rw-r--r--packages/frontend/src/pages/user/index.timeline.vue20
-rw-r--r--packages/frontend/src/pages/user/lists.vue10
-rw-r--r--packages/frontend/src/pages/user/notes.vue20
-rw-r--r--packages/frontend/src/pages/user/pages.vue12
-rw-r--r--packages/frontend/src/pages/user/reactions.vue12
51 files changed, 509 insertions, 554 deletions
diff --git a/packages/frontend/src/pages/about.federation.vue b/packages/frontend/src/pages/about.federation.vue
index 7e5abb4b34..47ec675d57 100644
--- a/packages/frontend/src/pages/about.federation.vue
+++ b/packages/frontend/src/pages/about.federation.vue
@@ -40,7 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</FormSplit>
</div>
- <MkPagination v-slot="{items}" ref="instances" :key="host + state" :pagination="pagination">
+ <MkPagination v-slot="{items}" ref="instances" :key="host + state" :paginator="paginator">
<div :class="$style.items">
<MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Status: ${getStatus(instance)}`" :class="$style.item" :to="`/instance-info/${instance.host}`">
<MkInstanceCardMini :instance="instance"/>
@@ -51,24 +51,22 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, ref } from 'vue';
+import { computed, markRaw, ref } from 'vue';
import MkInput from '@/components/MkInput.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkPagination from '@/components/MkPagination.vue';
-import type { PagingCtx } from '@/composables/use-pagination.js';
import MkInstanceCardMini from '@/components/MkInstanceCardMini.vue';
import FormSplit from '@/components/form/split.vue';
import { i18n } from '@/i18n.js';
+import { Paginator } from '@/utility/paginator.js';
const host = ref('');
const state = ref('federating');
const sort = ref('+pubSub');
-const pagination = {
- endpoint: 'federation/instances' as const,
+const paginator = markRaw(new Paginator('federation/instances', {
limit: 10,
- displayLimit: 50,
offsetMode: true,
- params: computed(() => ({
+ computedParams: computed(() => ({
sort: sort.value,
host: host.value !== '' ? host.value : null,
...(
@@ -81,7 +79,7 @@ const pagination = {
state.value === 'notResponding' ? { notResponding: true } :
{}),
})),
-} as PagingCtx;
+}));
function getStatus(instance) {
if (instance.isSuspended) return 'Suspended';
diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue
index b0862ccaa4..a194b9a94f 100644
--- a/packages/frontend/src/pages/admin-user.vue
+++ b/packages/frontend/src/pages/admin-user.vue
@@ -160,7 +160,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<option value="archived">{{ i18n.ts.archived }}</option>
</MkSelect>
- <MkPagination :pagination="announcementsPagination">
+ <MkPagination :paginator="announcementsPaginator">
<template #default="{ items }">
<div class="_gaps_s">
<div v-for="announcement in items" :key="announcement.id" v-panel :class="$style.announcementItem" @click="editAnnouncement(announcement)">
@@ -179,7 +179,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div v-else-if="tab === 'drive'" class="_gaps">
- <MkFileListForAdmin :pagination="filesPagination" viewMode="grid"/>
+ <MkFileListForAdmin :paginator="filesPaginator" viewMode="grid"/>
</div>
<div v-else-if="tab === 'chart'" class="_gaps_m">
@@ -211,7 +211,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, defineAsyncComponent, watch, ref } from 'vue';
+import { computed, defineAsyncComponent, watch, ref, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import { url } from '@@/js/config.js';
import MkChart from '@/components/MkChart.vue';
@@ -235,6 +235,7 @@ import { i18n } from '@/i18n.js';
import { iAmAdmin, $i, iAmModerator } from '@/i.js';
import MkRolePreview from '@/components/MkRolePreview.vue';
import MkPagination from '@/components/MkPagination.vue';
+import { Paginator } from '@/utility/paginator.js';
const props = withDefaults(defineProps<{
userId: string;
@@ -255,24 +256,22 @@ const silenced = ref(false);
const suspended = ref(false);
const isSystem = ref(false);
const moderationNote = ref('');
-const filesPagination = {
- endpoint: 'admin/drive/files' as const,
+const filesPaginator = markRaw(new Paginator('admin/drive/files', {
limit: 10,
- params: computed(() => ({
+ computedParams: computed(() => ({
userId: props.userId,
})),
-};
+}));
const announcementsStatus = ref<'active' | 'archived'>('active');
-const announcementsPagination = {
- endpoint: 'admin/announcements/list' as const,
+const announcementsPaginator = markRaw(new Paginator('admin/announcements/list', {
limit: 10,
- params: computed(() => ({
+ computedParams: computed(() => ({
userId: props.userId,
status: announcementsStatus.value,
})),
-};
+}));
const expandedRoles = ref([]);
function createFetcher() {
diff --git a/packages/frontend/src/pages/admin/abuses.vue b/packages/frontend/src/pages/admin/abuses.vue
index 4dbb573ceb..ab462229a7 100644
--- a/packages/frontend/src/pages/admin/abuses.vue
+++ b/packages/frontend/src/pages/admin/abuses.vue
@@ -41,13 +41,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInput v-model="searchUsername" style="margin: 0; flex: 1;" type="text" :spellcheck="false">
<span>{{ i18n.ts.username }}</span>
</MkInput>
- <MkInput v-model="searchHost" style="margin: 0; flex: 1;" type="text" :spellcheck="false" :disabled="pagination.params().origin === 'local'">
+ <MkInput v-model="searchHost" style="margin: 0; flex: 1;" type="text" :spellcheck="false" :disabled="paginator.computedParams.value.origin === 'local'">
<span>{{ i18n.ts.host }}</span>
</MkInput>
</div>
-->
- <MkPagination v-slot="{items}" ref="reports" :pagination="pagination">
+ <MkPagination v-slot="{items}" :paginator="paginator">
<div class="_gaps">
<XAbuseReport v-for="report in items" :key="report.id" :report="report" @resolved="resolved"/>
</div>
@@ -58,7 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, useTemplateRef, ref } from 'vue';
+import { computed, ref, markRaw } from 'vue';
import MkSelect from '@/components/MkSelect.vue';
import MkPagination from '@/components/MkPagination.vue';
import XAbuseReport from '@/components/MkAbuseReport.vue';
@@ -66,8 +66,7 @@ import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import MkButton from '@/components/MkButton.vue';
import { store } from '@/store.js';
-
-const reports = useTemplateRef('reports');
+import { Paginator } from '@/utility/paginator.js';
const state = ref('unresolved');
const reporterOrigin = ref('combined');
@@ -75,18 +74,17 @@ const targetUserOrigin = ref('combined');
const searchUsername = ref('');
const searchHost = ref('');
-const pagination = {
- endpoint: 'admin/abuse-user-reports' as const,
+const paginator = markRaw(new Paginator('admin/abuse-user-reports', {
limit: 10,
- params: computed(() => ({
+ computedParams: computed(() => ({
state: state.value,
reporterOrigin: reporterOrigin.value,
targetUserOrigin: targetUserOrigin.value,
})),
-};
+}));
function resolved(reportId) {
- reports.value?.paginator.removeItem(reportId);
+ paginator.removeItem(reportId);
}
const headerActions = computed(() => []);
diff --git a/packages/frontend/src/pages/admin/federation.vue b/packages/frontend/src/pages/admin/federation.vue
index 73b25277b3..ddc3ff7b79 100644
--- a/packages/frontend/src/pages/admin/federation.vue
+++ b/packages/frontend/src/pages/admin/federation.vue
@@ -42,7 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</FormSplit>
</div>
- <MkPagination v-slot="{items}" ref="instances" :key="host + state" :pagination="pagination">
+ <MkPagination v-slot="{items}" :key="host + state" :paginator="paginator">
<div :class="$style.instances">
<MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Status: ${getStatus(instance)}`" :class="$style.instance" :to="`/instance-info/${instance.host}`">
<MkInstanceCardMini :instance="instance"/>
@@ -56,7 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import * as Misskey from 'misskey-js';
-import { computed, ref } from 'vue';
+import { computed, markRaw, ref } from 'vue';
import MkInput from '@/components/MkInput.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkPagination from '@/components/MkPagination.vue';
@@ -64,15 +64,15 @@ import MkInstanceCardMini from '@/components/MkInstanceCardMini.vue';
import FormSplit from '@/components/form/split.vue';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
+import { Paginator } from '@/utility/paginator.js';
const host = ref('');
const state = ref('federating');
const sort = ref('+pubSub');
-const pagination = {
- endpoint: 'federation/instances' as const,
+const paginator = markRaw(new Paginator('federation/instances', {
limit: 10,
offsetMode: true,
- params: computed(() => ({
+ computedParams: computed(() => ({
sort: sort.value,
host: host.value !== '' ? host.value : null,
...(
@@ -85,7 +85,7 @@ const pagination = {
state.value === 'notResponding' ? { notResponding: true } :
{}),
})),
-};
+}));
function getStatus(instance: Misskey.entities.FederationInstance) {
switch (instance.suspensionState) {
diff --git a/packages/frontend/src/pages/admin/files.vue b/packages/frontend/src/pages/admin/files.vue
index 4ea5756284..0f3a90b458 100644
--- a/packages/frontend/src/pages/admin/files.vue
+++ b/packages/frontend/src/pages/admin/files.vue
@@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<option value="local">{{ i18n.ts.local }}</option>
<option value="remote">{{ i18n.ts.remote }}</option>
</MkSelect>
- <MkInput v-model="searchHost" :debounce="true" type="search" style="margin: 0; flex: 1;" :disabled="pagination.params.origin === 'local'">
+ <MkInput v-model="searchHost" :debounce="true" type="search" style="margin: 0; flex: 1;" :disabled="paginator.computedParams.value.origin === 'local'">
<template #label>{{ i18n.ts.host }}</template>
</MkInput>
</div>
@@ -26,14 +26,14 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>MIME type</template>
</MkInput>
</div>
- <MkFileListForAdmin :pagination="pagination" :viewMode="viewMode"/>
+ <MkFileListForAdmin :paginator="paginator" :viewMode="viewMode"/>
</div>
</div>
</PageWithHeader>
</template>
<script lang="ts" setup>
-import { computed, ref } from 'vue';
+import { computed, markRaw, ref } from 'vue';
import * as Misskey from 'misskey-js';
import MkInput from '@/components/MkInput.vue';
import MkSelect from '@/components/MkSelect.vue';
@@ -42,23 +42,22 @@ import * as os from '@/os.js';
import { lookupFile } from '@/utility/admin-lookup.js';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
-import type { PagingCtx } from '@/composables/use-pagination.js';
+import { Paginator } from '@/utility/paginator.js';
const origin = ref<Misskey.entities.AdminDriveFilesRequest['origin']>('local');
const type = ref<string | null>(null);
const searchHost = ref('');
const userId = ref('');
const viewMode = ref<'grid' | 'list'>('grid');
-const pagination = {
- endpoint: 'admin/drive/files' as const,
+const paginator = markRaw(new Paginator('admin/drive/files', {
limit: 10,
- params: computed(() => ({
+ computedParams: computed(() => ({
type: (type.value && type.value !== '') ? type.value : null,
userId: (userId.value && userId.value !== '') ? userId.value : null,
origin: origin.value,
hostname: (searchHost.value && searchHost.value !== '') ? searchHost.value : null,
})),
-} satisfies PagingCtx<'admin/drive/files'>;
+}));
function clear() {
os.confirm({
diff --git a/packages/frontend/src/pages/admin/invites.vue b/packages/frontend/src/pages/admin/invites.vue
index f1584fc864..e1b4890513 100644
--- a/packages/frontend/src/pages/admin/invites.vue
+++ b/packages/frontend/src/pages/admin/invites.vue
@@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInput v-if="!noExpirationDate" v-model="expiresAt" type="datetime-local">
<template #label>{{ i18n.ts.expirationDate }}</template>
</MkInput>
- <MkInput v-model="createCount" type="number" min="1">
+ <MkInput v-model="createCount" type="number" :min="1">
<template #label>{{ i18n.ts.createCount }}</template>
</MkInput>
<MkButton primary rounded @click="createWithOptions">{{ i18n.ts.create }}</MkButton>
@@ -41,7 +41,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<option value="-usedAt">{{ i18n.ts.usedAt }} ({{ i18n.ts.descendingOrder }})</option>
</MkSelect>
</div>
- <MkPagination ref="pagingComponent" :pagination="pagination">
+ <MkPagination :paginator="paginator">
<template #default="{ items }">
<div class="_gaps_s">
<MkInviteCode v-for="item in items" :key="item.id" :invite="(item as any)" :onDeleted="deleted" moderator/>
@@ -54,8 +54,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, ref, useTemplateRef } from 'vue';
-import type { PagingCtx } from '@/composables/use-pagination.js';
+import { computed, markRaw, ref, useTemplateRef } from 'vue';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/utility/misskey-api.js';
@@ -67,21 +66,19 @@ import MkSwitch from '@/components/MkSwitch.vue';
import MkPagination from '@/components/MkPagination.vue';
import MkInviteCode from '@/components/MkInviteCode.vue';
import { definePage } from '@/page.js';
-
-const pagingComponent = useTemplateRef('pagingComponent');
+import { Paginator } from '@/utility/paginator.js';
const type = ref('all');
const sort = ref('+createdAt');
-const pagination: PagingCtx = {
- endpoint: 'admin/invite/list' as const,
+const paginator = markRaw(new Paginator('admin/invite/list', {
limit: 10,
- params: computed(() => ({
+ computedParams: computed(() => ({
type: type.value,
sort: sort.value,
})),
offsetMode: true,
-};
+}));
const expiresAt = ref('');
const noExpirationDate = ref(true);
@@ -100,13 +97,11 @@ async function createWithOptions() {
text: tickets.map(x => x.code).join('\n'),
});
- tickets.forEach(ticket => pagingComponent.value?.paginator.prepend(ticket));
+ tickets.forEach(ticket => paginator.prepend(ticket));
}
function deleted(id: string) {
- if (pagingComponent.value) {
- pagingComponent.value.paginator.removeItem(id);
- }
+ paginator.removeItem(id);
}
const headerActions = computed(() => []);
diff --git a/packages/frontend/src/pages/admin/modlog.vue b/packages/frontend/src/pages/admin/modlog.vue
index 76b313026b..6a6102749e 100644
--- a/packages/frontend/src/pages/admin/modlog.vue
+++ b/packages/frontend/src/pages/admin/modlog.vue
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
<div class="_spacer" style="--MI_SPACER-w: 900px;">
<div class="_gaps">
- <MkPaginationControl v-model:order="order" v-model:date="date" v-model:q="q" canSearch canFilter @reload="paginator.reload()">
+ <MkPaginationControl :paginator="paginator" canFilter>
<MkSelect v-model="type" style="margin: 0; flex: 1;">
<template #label>{{ i18n.ts.type }}</template>
<option :value="null">{{ i18n.ts.all }}</option>
@@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, useTemplateRef, ref, watch } from 'vue';
+import { computed, ref, markRaw, onMounted } from 'vue';
import * as Misskey from 'misskey-js';
import XModLog from './modlog.ModLog.vue';
import MkSelect from '@/components/MkSelect.vue';
@@ -54,37 +54,25 @@ import MkTl from '@/components/MkTl.vue';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import { prefer } from '@/preferences.js';
-import { usePagination } from '@/composables/use-pagination.js';
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
import MkButton from '@/components/MkButton.vue';
import MkPaginationControl from '@/components/MkPaginationControl.vue';
+import { Paginator } from '@/utility/paginator.js';
-const order = ref<'newest' | 'oldest'>('newest');
-const date = ref<number | null>(null);
const type = ref<string | null>(null);
const moderatorId = ref('');
-const q = ref<string | null>(null);
-const paginator = usePagination({
- ctx: {
- endpoint: 'admin/show-moderation-logs',
- limit: 20,
- canFetchDetection: 'limit',
- params: computed(() => ({
- type: type.value,
- userId: moderatorId.value === '' ? null : moderatorId.value,
- search: q.value,
- })),
- },
-});
+const paginator = markRaw(new Paginator('admin/show-moderation-logs', {
+ limit: 20,
+ canFetchDetection: 'limit',
+ canSearch: true,
+ computedParams: computed(() => ({
+ type: type.value,
+ userId: moderatorId.value === '' ? null : moderatorId.value,
+ })),
+}));
-watch([order, date], () => {
- paginator.updateCtxPartial({
- order: order.value,
- initialDirection: order.value === 'oldest' ? 'newer' : 'older',
- initialDate: date.value,
- });
-}, { immediate: false });
+paginator.init();
const timeline = computed(() => {
return paginator.items.value.map(x => ({
@@ -95,7 +83,7 @@ const timeline = computed(() => {
});
function fetchMore() {
- if (order.value === 'oldest') {
+ if (paginator.order.value === 'oldest') {
paginator.fetchNewer();
} else {
paginator.fetchOlder();
diff --git a/packages/frontend/src/pages/admin/roles.role.vue b/packages/frontend/src/pages/admin/roles.role.vue
index 61d72777b8..64b6231398 100644
--- a/packages/frontend/src/pages/admin/roles.role.vue
+++ b/packages/frontend/src/pages/admin/roles.role.vue
@@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps">
<MkButton primary rounded @click="assign"><i class="ti ti-plus"></i> {{ i18n.ts.assign }}</MkButton>
- <MkPagination :pagination="usersPagination">
+ <MkPagination :paginator="usersPaginator">
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
<template #default="{ items }">
@@ -54,7 +54,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, reactive, ref } from 'vue';
+import { computed, markRaw, reactive, ref } from 'vue';
import XEditor from './roles.editor.vue';
import MkFolder from '@/components/MkFolder.vue';
import * as os from '@/os.js';
@@ -66,6 +66,7 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue';
import MkInfo from '@/components/MkInfo.vue';
import MkPagination from '@/components/MkPagination.vue';
import { useRouter } from '@/router.js';
+import { Paginator } from '@/utility/paginator.js';
const router = useRouter();
@@ -73,13 +74,12 @@ const props = defineProps<{
id?: string;
}>();
-const usersPagination = {
- endpoint: 'admin/roles/users' as const,
+const usersPaginator = markRaw(new Paginator('admin/roles/users', {
limit: 20,
- params: computed(() => ({
+ computedParams: computed(() => ({
roleId: props.id,
})),
-};
+}));
const expandedItems = ref([]);
diff --git a/packages/frontend/src/pages/admin/users.vue b/packages/frontend/src/pages/admin/users.vue
index 56cf8876f0..581eb7eb97 100644
--- a/packages/frontend/src/pages/admin/users.vue
+++ b/packages/frontend/src/pages/admin/users.vue
@@ -38,13 +38,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #prefix>@</template>
<template #label>{{ i18n.ts.username }}</template>
</MkInput>
- <MkInput v-model="searchHost" style="flex: 1;" type="text" :spellcheck="false" :disabled="pagination.params.origin === 'local'">
+ <MkInput v-model="searchHost" style="flex: 1;" type="text" :spellcheck="false" :disabled="paginator.computedParams.value.origin === 'local'">
<template #prefix>@</template>
<template #label>{{ i18n.ts.host }}</template>
</MkInput>
</div>
- <MkPagination v-slot="{items}" ref="paginationComponent" :pagination="pagination">
+ <MkPagination v-slot="{items}" :paginator="paginator">
<div :class="$style.users">
<MkA v-for="user in items" :key="user.id" v-tooltip.mfm="`Last posted: ${dateString(user.updatedAt)}`" :class="$style.user" :to="`/admin/user/${user.id}`">
<MkUserCardMini :user="user"/>
@@ -57,7 +57,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, useTemplateRef, ref, watchEffect } from 'vue';
+import { computed, markRaw, ref, watchEffect } from 'vue';
import { defaultMemoryStorage } from '@/memory-storage';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
@@ -69,6 +69,7 @@ import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import MkUserCardMini from '@/components/MkUserCardMini.vue';
import { dateString } from '@/filters/date.js';
+import { Paginator } from '@/utility/paginator.js';
type SearchQuery = {
sort?: string;
@@ -78,7 +79,6 @@ type SearchQuery = {
hostname?: string;
};
-const paginationComponent = useTemplateRef('paginationComponent');
const storedQuery = JSON.parse(defaultMemoryStorage.getItem('admin-users-query') ?? '{}') as SearchQuery;
const sort = ref(storedQuery.sort ?? '+createdAt');
@@ -86,10 +86,9 @@ const state = ref(storedQuery.state ?? 'all');
const origin = ref(storedQuery.origin ?? 'local');
const searchUsername = ref(storedQuery.username ?? '');
const searchHost = ref(storedQuery.hostname ?? '');
-const pagination = {
- endpoint: 'admin/show-users' as const,
+const paginator = markRaw(new Paginator('admin/show-users', {
limit: 10,
- params: computed(() => ({
+ computedParams: computed(() => ({
sort: sort.value,
state: state.value,
origin: origin.value,
@@ -97,7 +96,7 @@ const pagination = {
hostname: searchHost.value,
})),
offsetMode: true,
-};
+}));
function searchUser() {
os.selectUser({ includeSelf: true }).then(user => {
@@ -121,7 +120,7 @@ async function addUser() {
username: username,
password: password,
}).then(res => {
- paginationComponent.value?.paginator.reload();
+ paginator.reload();
});
}
diff --git a/packages/frontend/src/pages/announcements.vue b/packages/frontend/src/pages/announcements.vue
index 2c671c6b34..4c34c3c74b 100644
--- a/packages/frontend/src/pages/announcements.vue
+++ b/packages/frontend/src/pages/announcements.vue
@@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_spacer" style="--MI_SPACER-w: 800px;">
<div class="_gaps">
<MkInfo v-if="$i && $i.hasUnreadAnnouncement && tab === 'current'" warn>{{ i18n.ts.youHaveUnreadAnnouncements }}</MkInfo>
- <MkPagination ref="paginationEl" :key="tab" v-slot="{items}" :pagination="tab === 'current' ? paginationCurrent : paginationPast" class="_gaps">
+ <MkPagination v-slot="{items}" :paginator="paginator" class="_gaps">
<section v-for="announcement in items" :key="announcement.id" class="_panel" :class="$style.announcement">
<div v-if="announcement.forYou" :class="$style.forYou"><i class="ti ti-pin"></i> {{ i18n.ts.forYou }}</div>
<div :class="$style.header">
@@ -44,7 +44,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { ref, computed, useTemplateRef } from 'vue';
+import { ref, computed, markRaw } from 'vue';
import MkPagination from '@/components/MkPagination.vue';
import MkButton from '@/components/MkButton.vue';
import MkInfo from '@/components/MkInfo.vue';
@@ -54,24 +54,14 @@ import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import { $i } from '@/i.js';
import { updateCurrentAccountPartial } from '@/accounts.js';
+import { Paginator } from '@/utility/paginator.js';
-const paginationCurrent = {
- endpoint: 'announcements' as const,
+const paginator = markRaw(new Paginator('announcements', {
limit: 10,
- params: {
- isActive: true,
- },
-};
-
-const paginationPast = {
- endpoint: 'announcements' as const,
- limit: 10,
- params: {
- isActive: false,
- },
-};
-
-const paginationEl = useTemplateRef('paginationEl');
+ computedParams: computed(() => ({
+ isActive: tab.value === 'current',
+ })),
+}));
const tab = ref('current');
@@ -85,8 +75,7 @@ async function read(target) {
if (confirm.canceled) return;
}
- if (!paginationEl.value) return;
- paginationEl.value.paginator.updateItem(target.id, a => ({
+ paginator.updateItem(target.id, a => ({
...a,
isRead: true,
}));
diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue
index 6eb390f743..116aabaee2 100644
--- a/packages/frontend/src/pages/channel.vue
+++ b/packages/frontend/src/pages/channel.vue
@@ -40,7 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkStreamingNotesTimeline :key="channelId" src="channel" :channel="channelId"/>
</div>
<div v-else-if="tab === 'featured'">
- <MkNotesTimeline :pagination="featuredPagination"/>
+ <MkNotesTimeline :paginator="featuredPaginator"/>
</div>
<div v-else-if="tab === 'search'">
<div v-if="notesSearchAvailable" class="_gaps">
@@ -50,7 +50,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInput>
<MkButton primary rounded style="margin-top: 8px;" @click="search()">{{ i18n.ts.search }}</MkButton>
</div>
- <MkNotesTimeline v-if="searchPagination" :key="searchKey" :pagination="searchPagination"/>
+ <MkNotesTimeline v-if="searchPaginator" :key="searchKey" :paginator="searchPaginator"/>
</div>
<div v-else>
<MkInfo warn>{{ i18n.ts.notesSearchNotAvailable }}</MkInfo>
@@ -70,7 +70,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, watch, ref } from 'vue';
+import { computed, watch, ref, markRaw, shallowRef } from 'vue';
import * as Misskey from 'misskey-js';
import { url } from '@@/js/config.js';
import { useInterval } from '@@/js/use-interval.js';
@@ -97,6 +97,7 @@ import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
import { notesSearchAvailable } from '@/utility/check-permissions.js';
import { miLocalStorage } from '@/local-storage.js';
import { useRouter } from '@/router.js';
+import { Paginator } from '@/utility/paginator.js';
const router = useRouter();
@@ -109,14 +110,13 @@ const tab = ref('overview');
const channel = ref<Misskey.entities.Channel | null>(null);
const favorited = ref(false);
const searchQuery = ref('');
-const searchPagination = ref();
+const searchPaginator = shallowRef();
const searchKey = ref('');
-const featuredPagination = computed(() => ({
- endpoint: 'notes/featured' as const,
+const featuredPaginator = markRaw(new Paginator('channels/featured', {
limit: 10,
- params: {
+ computedParams: computed(() => ({
channelId: props.channelId,
- },
+ })),
}));
useInterval(() => {
@@ -190,14 +190,13 @@ async function search() {
if (query == null) return;
- searchPagination.value = {
- endpoint: 'notes/search',
+ searchPaginator.value = markRaw(new Paginator('notes/search', {
limit: 10,
params: {
query: query,
channelId: channel.value.id,
},
- };
+ }));
searchKey.value = query;
}
diff --git a/packages/frontend/src/pages/channels.vue b/packages/frontend/src/pages/channels.vue
index b2b2bc02d2..324e0c573a 100644
--- a/packages/frontend/src/pages/channels.vue
+++ b/packages/frontend/src/pages/channels.vue
@@ -18,27 +18,27 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton large primary gradate rounded @click="search">{{ i18n.ts.search }}</MkButton>
</div>
- <MkFoldableSection v-if="channelPagination">
+ <MkFoldableSection v-if="channelPaginator">
<template #header>{{ i18n.ts.searchResult }}</template>
- <MkChannelList :key="key" :pagination="channelPagination"/>
+ <MkChannelList :key="key" :paginator="channelPaginator"/>
</MkFoldableSection>
</div>
<div v-if="tab === 'featured'">
- <MkPagination v-slot="{items}" :pagination="featuredPagination">
+ <MkPagination v-slot="{items}" :paginator="featuredPaginator">
<div :class="$style.root">
<MkChannelPreview v-for="channel in items" :key="channel.id" :channel="channel"/>
</div>
</MkPagination>
</div>
<div v-else-if="tab === 'favorites'">
- <MkPagination v-slot="{items}" :pagination="favoritesPagination">
+ <MkPagination v-slot="{items}" :paginator="favoritesPaginator">
<div :class="$style.root">
<MkChannelPreview v-for="channel in items" :key="channel.id" :channel="channel"/>
</div>
</MkPagination>
</div>
<div v-else-if="tab === 'following'">
- <MkPagination v-slot="{items}" :pagination="followingPagination">
+ <MkPagination v-slot="{items}" :paginator="followingPaginator">
<div :class="$style.root">
<MkChannelPreview v-for="channel in items" :key="channel.id" :channel="channel"/>
</div>
@@ -46,7 +46,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div v-else-if="tab === 'owned'">
<MkButton class="new" @click="create()"><i class="ti ti-plus"></i></MkButton>
- <MkPagination v-slot="{items}" :pagination="ownedPagination">
+ <MkPagination v-slot="{items}" :paginator="ownedPaginator">
<div :class="$style.root">
<MkChannelPreview v-for="channel in items" :key="channel.id" :channel="channel"/>
</div>
@@ -57,7 +57,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, onMounted, ref } from 'vue';
+import { computed, markRaw, onMounted, ref, shallowRef } from 'vue';
import MkChannelPreview from '@/components/MkChannelPreview.vue';
import MkChannelList from '@/components/MkChannelList.vue';
import MkPagination from '@/components/MkPagination.vue';
@@ -68,6 +68,7 @@ import MkFoldableSection from '@/components/MkFoldableSection.vue';
import { definePage } from '@/page.js';
import { i18n } from '@/i18n.js';
import { useRouter } from '@/router.js';
+import { Paginator } from '@/utility/paginator.js';
const router = useRouter();
@@ -80,31 +81,27 @@ const key = ref('');
const tab = ref('featured');
const searchQuery = ref('');
const searchType = ref('nameAndDescription');
-const channelPagination = ref();
+const channelPaginator = shallowRef();
onMounted(() => {
searchQuery.value = props.query ?? '';
searchType.value = props.type ?? 'nameAndDescription';
});
-const featuredPagination = {
- endpoint: 'channels/featured' as const,
+const featuredPaginator = markRaw(new Paginator('channels/featured', {
limit: 10,
noPaging: true,
-};
-const favoritesPagination = {
- endpoint: 'channels/my-favorites' as const,
+}));
+const favoritesPaginator = markRaw(new Paginator('channels/my-favorites', {
limit: 100,
noPaging: true,
-};
-const followingPagination = {
- endpoint: 'channels/followed' as const,
+}));
+const followingPaginator = markRaw(new Paginator('channels/followed', {
limit: 10,
-};
-const ownedPagination = {
- endpoint: 'channels/owned' as const,
+}));
+const ownedPaginator = markRaw(new Paginator('channels/owned', {
limit: 10,
-};
+}));
async function search() {
const query = searchQuery.value.toString().trim();
@@ -113,14 +110,13 @@ async function search() {
const type = searchType.value.toString().trim();
- channelPagination.value = {
- endpoint: 'channels/search',
+ channelPaginator.value = markRaw(new Paginator('channels/search', {
limit: 10,
params: {
query: searchQuery.value,
type: type,
},
- };
+ }));
key.value = query + type;
}
diff --git a/packages/frontend/src/pages/clip.vue b/packages/frontend/src/pages/clip.vue
index dc043e2ce1..8843812544 100644
--- a/packages/frontend/src/pages/clip.vue
+++ b/packages/frontend/src/pages/clip.vue
@@ -23,14 +23,14 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</div>
- <MkNotesTimeline :pagination="pagination" :detail="true"/>
+ <MkNotesTimeline :paginator="paginator" :detail="true"/>
</div>
</div>
</PageWithHeader>
</template>
<script lang="ts" setup>
-import { computed, watch, provide, ref } from 'vue';
+import { computed, watch, provide, ref, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import { url } from '@@/js/config.js';
import type { MenuItem } from '@/types/menu.js';
@@ -46,6 +46,7 @@ import { isSupportShare } from '@/utility/navigator.js';
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
import { genEmbedCode } from '@/utility/get-embed-code.js';
import { assertServerContext, serverContext } from '@/server-context.js';
+import { Paginator } from '@/utility/paginator.js';
// contextは非ログイン状態の情報しかないためログイン時は利用できない
const CTX_CLIP = !$i && assertServerContext(serverContext, 'clip') ? serverContext.clip : null;
@@ -56,13 +57,13 @@ const props = defineProps<{
const clip = ref<Misskey.entities.Clip | null>(CTX_CLIP);
const favorited = ref(false);
-const pagination = {
- endpoint: 'clips/notes' as const,
+const paginator = markRaw(new Paginator('clips/notes', {
limit: 10,
- params: computed(() => ({
+ canSearch: true,
+ computedParams: computed(() => ({
clipId: props.clipId,
})),
-};
+}));
const isOwned = computed<boolean | null>(() => $i && clip.value && ($i.id === clip.value.userId));
diff --git a/packages/frontend/src/pages/custom-emojis-manager.vue b/packages/frontend/src/pages/custom-emojis-manager.vue
index 36d638b210..1cb07017e9 100644
--- a/packages/frontend/src/pages/custom-emojis-manager.vue
+++ b/packages/frontend/src/pages/custom-emojis-manager.vue
@@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton inline @click="setLicenseBulk">Set License</MkButton>
<MkButton inline danger @click="delBulk">Delete</MkButton>
</div>
- <MkPagination ref="emojisPaginationComponent" :pagination="pagination">
+ <MkPagination ref="emojisPaginationComponent" :paginator="paginator">
<template #empty><span>{{ i18n.ts.noCustomEmojis }}</span></template>
<template #default="{items}">
<div class="ldhfsamy">
@@ -50,7 +50,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>{{ i18n.ts.host }}</template>
</MkInput>
</FormSplit>
- <MkPagination :pagination="remotePagination">
+ <MkPagination :paginator="remotePaginator">
<template #empty><span>{{ i18n.ts.noCustomEmojis }}</span></template>
<template #default="{items}">
<div class="ldhfsamy">
@@ -71,7 +71,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, defineAsyncComponent, ref, useTemplateRef } from 'vue';
+import { computed, defineAsyncComponent, markRaw, ref } from 'vue';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
import MkPagination from '@/components/MkPagination.vue';
@@ -84,8 +84,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
import { getProxiedImageUrl } from '@/utility/media-proxy.js';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
-
-const emojisPaginationComponent = useTemplateRef('emojisPaginationComponent');
+import { Paginator } from '@/utility/paginator.js';
const tab = ref('local');
const query = ref<string | null>(null);
@@ -94,28 +93,26 @@ const host = ref<string | null>(null);
const selectMode = ref(false);
const selectedEmojis = ref<string[]>([]);
-const pagination = {
- endpoint: 'admin/emoji/list' as const,
+const paginator = markRaw(new Paginator('admin/emoji/list', {
limit: 30,
- params: computed(() => ({
+ computedParams: computed(() => ({
query: (query.value && query.value !== '') ? query.value : null,
})),
-};
+}));
-const remotePagination = {
- endpoint: 'admin/emoji/list-remote' as const,
+const remotePaginator = markRaw(new Paginator('admin/emoji/list-remote', {
limit: 30,
- params: computed(() => ({
+ computedParams: computed(() => ({
query: (queryRemote.value && queryRemote.value !== '') ? queryRemote.value : null,
host: (host.value && host.value !== '') ? host.value : null,
})),
-};
+}));
const selectAll = () => {
if (selectedEmojis.value.length > 0) {
selectedEmojis.value = [];
} else {
- selectedEmojis.value = emojisPaginationComponent.value?.paginator.items.value.map(item => item.id);
+ selectedEmojis.value = paginator.items.value.map(item => item.id);
}
};
@@ -132,7 +129,7 @@ const add = async (ev: MouseEvent) => {
}, {
done: result => {
if (result.created) {
- emojisPaginationComponent.value?.paginator.prepend(result.created);
+ paginator.prepend(result.created);
}
},
closed: () => dispose(),
@@ -145,12 +142,12 @@ const edit = async (emoji) => {
}, {
done: result => {
if (result.updated) {
- emojisPaginationComponent.value?.paginator.updateItem(result.updated.id, (oldEmoji) => ({
+ paginator.updateItem(result.updated.id, (oldEmoji) => ({
...oldEmoji,
...result.updated,
}));
} else if (result.deleted) {
- emojisPaginationComponent.value?.paginator.removeItem(emoji.id);
+ paginator.removeItem(emoji.id);
}
},
closed: () => dispose(),
@@ -245,7 +242,7 @@ const setCategoryBulk = async () => {
ids: selectedEmojis.value,
category: result,
});
- emojisPaginationComponent.value?.paginator.reload();
+ paginator.reload();
};
const setLicenseBulk = async () => {
@@ -257,7 +254,7 @@ const setLicenseBulk = async () => {
ids: selectedEmojis.value,
license: result,
});
- emojisPaginationComponent.value?.paginator.reload();
+ paginator.reload();
};
const addTagBulk = async () => {
@@ -269,7 +266,7 @@ const addTagBulk = async () => {
ids: selectedEmojis.value,
aliases: result.split(' '),
});
- emojisPaginationComponent.value?.paginator.reload();
+ paginator.reload();
};
const removeTagBulk = async () => {
@@ -281,7 +278,7 @@ const removeTagBulk = async () => {
ids: selectedEmojis.value,
aliases: result.split(' '),
});
- emojisPaginationComponent.value?.paginator.reload();
+ paginator.reload();
};
const setTagBulk = async () => {
@@ -293,7 +290,7 @@ const setTagBulk = async () => {
ids: selectedEmojis.value,
aliases: result.split(' '),
});
- emojisPaginationComponent.value?.paginator.reload();
+ paginator.reload();
};
const delBulk = async () => {
@@ -305,7 +302,7 @@ const delBulk = async () => {
await os.apiWithDialog('admin/emoji/delete-bulk', {
ids: selectedEmojis.value,
});
- emojisPaginationComponent.value?.paginator.reload();
+ paginator.reload();
};
const headerActions = computed(() => [{
diff --git a/packages/frontend/src/pages/drive.file.notes.vue b/packages/frontend/src/pages/drive.file.notes.vue
index cf45470588..8427017c92 100644
--- a/packages/frontend/src/pages/drive.file.notes.vue
+++ b/packages/frontend/src/pages/drive.file.notes.vue
@@ -6,16 +6,16 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="_gaps">
<MkInfo>{{ i18n.ts._fileViewer.thisPageCanBeSeenFromTheAuthor }}</MkInfo>
- <MkNotesTimeline ref="tlComponent" :pagination="pagination"/>
+ <MkNotesTimeline :paginator="paginator"/>
</div>
</template>
<script lang="ts" setup>
-import { ref, computed } from 'vue';
+import { ref, computed, markRaw } from 'vue';
import { i18n } from '@/i18n.js';
-import type { PagingCtx } from '@/composables/use-pagination.js';
import MkInfo from '@/components/MkInfo.vue';
import MkNotesTimeline from '@/components/MkNotesTimeline.vue';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
fileId: string;
@@ -23,11 +23,10 @@ const props = defineProps<{
const realFileId = computed(() => props.fileId);
-const pagination = ref<PagingCtx>({
- endpoint: 'drive/files/attached-notes',
+const paginator = markRaw(new Paginator('drive/files/attached-notes', {
limit: 10,
params: {
fileId: realFileId.value,
},
-});
+}));
</script>
diff --git a/packages/frontend/src/pages/explore.featured.vue b/packages/frontend/src/pages/explore.featured.vue
index b8eb7eb8d5..abb816a956 100644
--- a/packages/frontend/src/pages/explore.featured.vue
+++ b/packages/frontend/src/pages/explore.featured.vue
@@ -9,30 +9,29 @@ SPDX-License-Identifier: AGPL-3.0-only
<option value="notes">{{ i18n.ts.notes }}</option>
<option value="polls">{{ i18n.ts.poll }}</option>
</MkTab>
- <MkNotesTimeline v-if="tab === 'notes'" :pagination="paginationForNotes"/>
- <MkNotesTimeline v-else-if="tab === 'polls'" :pagination="paginationForPolls"/>
+ <MkNotesTimeline v-if="tab === 'notes'" :paginator="paginatorForNotes"/>
+ <MkNotesTimeline v-else-if="tab === 'polls'" :paginator="paginatorForPolls"/>
</div>
</template>
<script lang="ts" setup>
-import { ref } from 'vue';
+import { markRaw, ref } from 'vue';
import MkNotesTimeline from '@/components/MkNotesTimeline.vue';
import MkTab from '@/components/MkTab.vue';
import { i18n } from '@/i18n.js';
+import { Paginator } from '@/utility/paginator.js';
-const paginationForNotes = {
- endpoint: 'notes/featured' as const,
+const paginatorForNotes = markRaw(new Paginator('notes/featured', {
limit: 10,
-};
+}));
-const paginationForPolls = {
- endpoint: 'notes/polls/recommendation' as const,
+const paginatorForPolls = markRaw(new Paginator('notes/polls/recommendation', {
limit: 10,
offsetMode: true,
params: {
excludeChannels: true,
},
-};
+}));
const tab = ref('notes');
</script>
diff --git a/packages/frontend/src/pages/explore.users.vue b/packages/frontend/src/pages/explore.users.vue
index e723f6a1e9..72f2a6813c 100644
--- a/packages/frontend/src/pages/explore.users.vue
+++ b/packages/frontend/src/pages/explore.users.vue
@@ -13,19 +13,19 @@ SPDX-License-Identifier: AGPL-3.0-only
<template v-if="tag == null">
<MkFoldableSection class="_margin" persistKey="explore-pinned-users">
<template #header><i class="ti ti-bookmark ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.pinnedUsers }}</template>
- <MkUserList :pagination="pinnedUsers"/>
+ <MkUserList :paginator="pinnedUsersPaginator"/>
</MkFoldableSection>
<MkFoldableSection class="_margin" persistKey="explore-popular-users">
<template #header><i class="ti ti-chart-line ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.popularUsers }}</template>
- <MkUserList :pagination="popularUsers"/>
+ <MkUserList :paginator="popularUsersPaginator"/>
</MkFoldableSection>
<MkFoldableSection class="_margin" persistKey="explore-recently-updated-users">
<template #header><i class="ti ti-message ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyUpdatedUsers }}</template>
- <MkUserList :pagination="recentlyUpdatedUsers"/>
+ <MkUserList :paginator="recentlyUpdatedUsersPaginator"/>
</MkFoldableSection>
<MkFoldableSection class="_margin" persistKey="explore-recently-registered-users">
<template #header><i class="ti ti-plus ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyRegisteredUsers }}</template>
- <MkUserList :pagination="recentlyRegisteredUsers"/>
+ <MkUserList :paginator="recentlyRegisteredUsersPaginator"/>
</MkFoldableSection>
</template>
</div>
@@ -41,21 +41,21 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkFoldableSection v-if="tag != null" :key="`${tag}`" class="_margin">
<template #header><i class="ti ti-hash ti-fw" style="margin-right: 0.5em;"></i>{{ tag }}</template>
- <MkUserList :pagination="tagUsers"/>
+ <MkUserList :paginator="tagUsersPaginator"/>
</MkFoldableSection>
<template v-if="tag == null">
<MkFoldableSection class="_margin">
<template #header><i class="ti ti-chart-line ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.popularUsers }}</template>
- <MkUserList :pagination="popularUsersF"/>
+ <MkUserList :paginator="popularUsersFPaginator"/>
</MkFoldableSection>
<MkFoldableSection class="_margin">
<template #header><i class="ti ti-message ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyUpdatedUsers }}</template>
- <MkUserList :pagination="recentlyUpdatedUsersF"/>
+ <MkUserList :paginator="recentlyUpdatedUsersFPaginator"/>
</MkFoldableSection>
<MkFoldableSection class="_margin">
<template #header><i class="ti ti-rocket ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyDiscoveredUsers }}</template>
- <MkUserList :pagination="recentlyRegisteredUsersF"/>
+ <MkUserList :paginator="recentlyRegisteredUsersFPaginator"/>
</MkFoldableSection>
</template>
</div>
@@ -63,7 +63,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { watch, ref, useTemplateRef, computed } from 'vue';
+import { watch, ref, useTemplateRef, computed, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import MkUserList from '@/components/MkUserList.vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
@@ -71,6 +71,7 @@ import MkTab from '@/components/MkTab.vue';
import { misskeyApi } from '@/utility/misskey-api.js';
import { instance } from '@/instance.js';
import { i18n } from '@/i18n.js';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
tag?: string;
@@ -85,8 +86,7 @@ watch(() => props.tag, () => {
if (tagsEl.value) tagsEl.value.toggleContent(props.tag == null);
});
-const tagUsers = computed(() => ({
- endpoint: 'hashtags/users' as const,
+const tagUsersPaginator = markRaw(new Paginator('hashtags/users', {
limit: 30,
params: {
tag: props.tag,
@@ -95,34 +95,66 @@ const tagUsers = computed(() => ({
},
}));
-const pinnedUsers = { endpoint: 'pinned-users', noPaging: true };
-const popularUsers = { endpoint: 'users', limit: 10, noPaging: true, params: {
- state: 'alive',
- origin: 'local',
- sort: '+follower',
-} };
-const recentlyUpdatedUsers = { endpoint: 'users', limit: 10, noPaging: true, params: {
- origin: 'local',
- sort: '+updatedAt',
-} };
-const recentlyRegisteredUsers = { endpoint: 'users', limit: 10, noPaging: true, params: {
- origin: 'local',
- state: 'alive',
- sort: '+createdAt',
-} };
-const popularUsersF = { endpoint: 'users', limit: 10, noPaging: true, params: {
- state: 'alive',
- origin: 'remote',
- sort: '+follower',
-} };
-const recentlyUpdatedUsersF = { endpoint: 'users', limit: 10, noPaging: true, params: {
- origin: 'combined',
- sort: '+updatedAt',
-} };
-const recentlyRegisteredUsersF = { endpoint: 'users', limit: 10, noPaging: true, params: {
- origin: 'combined',
- sort: '+createdAt',
-} };
+const pinnedUsersPaginator = markRaw(new Paginator('pinned-users', {
+ noPaging: true,
+}));
+
+const popularUsersPaginator = markRaw(new Paginator('users', {
+ limit: 10,
+ noPaging: true,
+ params: {
+ state: 'alive',
+ origin: 'local',
+ sort: '+follower',
+ },
+}));
+
+const recentlyUpdatedUsersPaginator = markRaw(new Paginator('users', {
+ limit: 10,
+ noPaging: true,
+ params: {
+ origin: 'local',
+ sort: '+updatedAt',
+ },
+}));
+
+const recentlyRegisteredUsersPaginator = markRaw(new Paginator('users', {
+ limit: 10,
+ noPaging: true,
+ params: {
+ origin: 'local',
+ state: 'alive',
+ sort: '+createdAt',
+ },
+}));
+
+const popularUsersFPaginator = markRaw(new Paginator('users', {
+ limit: 10,
+ noPaging: true,
+ params: {
+ state: 'alive',
+ origin: 'remote',
+ sort: '+follower',
+ },
+}));
+
+const recentlyUpdatedUsersFPaginator = markRaw(new Paginator('users', {
+ limit: 10,
+ noPaging: true,
+ params: {
+ origin: 'combined',
+ sort: '+updatedAt',
+ },
+}));
+
+const recentlyRegisteredUsersFPaginator = markRaw(new Paginator('users', {
+ limit: 10,
+ noPaging: true,
+ params: {
+ origin: 'combined',
+ sort: '+createdAt',
+ },
+}));
misskeyApi('hashtags/list', {
sort: '+attachedLocalUsers',
diff --git a/packages/frontend/src/pages/favorites.vue b/packages/frontend/src/pages/favorites.vue
index b0a18987b4..72dd2b4a16 100644
--- a/packages/frontend/src/pages/favorites.vue
+++ b/packages/frontend/src/pages/favorites.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<PageWithHeader>
<div class="_spacer" style="--MI_SPACER-w: 800px;">
- <MkPagination :pagination="pagination">
+ <MkPagination :paginator="paginator">
<template #empty><MkResult type="empty" :text="i18n.ts.noNotes"/></template>
<template #default="{ items }">
@@ -20,16 +20,17 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
+import { markRaw } from 'vue';
import MkPagination from '@/components/MkPagination.vue';
import MkNote from '@/components/MkNote.vue';
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
+import { Paginator } from '@/utility/paginator.js';
-const pagination = {
- endpoint: 'i/favorites' as const,
+const paginator = markRaw(new Paginator('i/favorites', {
limit: 10,
-};
+}));
definePage(() => ({
title: i18n.ts.favorites,
diff --git a/packages/frontend/src/pages/flash/flash-index.vue b/packages/frontend/src/pages/flash/flash-index.vue
index f3365fcedf..6e25df2df8 100644
--- a/packages/frontend/src/pages/flash/flash-index.vue
+++ b/packages/frontend/src/pages/flash/flash-index.vue
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs" :swipable="true">
<div class="_spacer" style="--MI_SPACER-w: 700px;">
<div v-if="tab === 'featured'">
- <MkPagination v-slot="{items}" :pagination="featuredFlashsPagination">
+ <MkPagination v-slot="{items}" :paginator="featuredFlashsPaginator">
<div class="_gaps_s">
<MkFlashPreview v-for="flash in items" :key="flash.id" :flash="flash"/>
</div>
@@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-else-if="tab === 'my'">
<div class="_gaps">
<MkButton gradate rounded style="margin: 0 auto;" @click="create()"><i class="ti ti-plus"></i></MkButton>
- <MkPagination v-slot="{items}" :pagination="myFlashsPagination">
+ <MkPagination v-slot="{items}" :paginator="myFlashsPaginator">
<div class="_gaps_s">
<MkFlashPreview v-for="flash in items" :key="flash.id" :flash="flash"/>
</div>
@@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div v-else-if="tab === 'liked'">
- <MkPagination v-slot="{items}" :pagination="likedFlashsPagination">
+ <MkPagination v-slot="{items}" :paginator="likedFlashsPaginator">
<div class="_gaps_s">
<MkFlashPreview v-for="like in items" :key="like.flash.id" :flash="like.flash"/>
</div>
@@ -37,31 +37,29 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, ref } from 'vue';
+import { computed, markRaw, ref } from 'vue';
import MkFlashPreview from '@/components/MkFlashPreview.vue';
import MkPagination from '@/components/MkPagination.vue';
import MkButton from '@/components/MkButton.vue';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import { useRouter } from '@/router.js';
+import { Paginator } from '@/utility/paginator.js';
const router = useRouter();
const tab = ref('featured');
-const featuredFlashsPagination = {
- endpoint: 'flash/featured' as const,
+const featuredFlashsPaginator = markRaw(new Paginator('flash/featured', {
limit: 5,
offsetMode: true,
-};
-const myFlashsPagination = {
- endpoint: 'flash/my' as const,
+}));
+const myFlashsPaginator = markRaw(new Paginator('flash/my', {
limit: 5,
-};
-const likedFlashsPagination = {
- endpoint: 'flash/my-likes' as const,
+}));
+const likedFlashsPaginator = markRaw(new Paginator('flash/my-likes', {
limit: 5,
-};
+}));
function create() {
router.push('/play/new');
diff --git a/packages/frontend/src/pages/follow-requests.vue b/packages/frontend/src/pages/follow-requests.vue
index e02abdc393..35e259a571 100644
--- a/packages/frontend/src/pages/follow-requests.vue
+++ b/packages/frontend/src/pages/follow-requests.vue
@@ -5,8 +5,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs" :swipable="true">
- <div class="_spacer" style="--MI_SPACER-w: 800px;">
- <MkPagination ref="paginationComponent" :pagination="pagination">
+ <div :key="tab" class="_spacer" style="--MI_SPACER-w: 800px;">
+ <MkPagination :paginator="paginator">
<template #empty><MkResult type="empty" :text="i18n.ts.noFollowRequests"/></template>
<template #default="{items}">
<div class="mk-follow-requests _gaps">
@@ -35,8 +35,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import * as Misskey from 'misskey-js';
-import { useTemplateRef, computed, ref } from 'vue';
-import type { PagingCtx } from '@/composables/use-pagination.js';
+import { computed, markRaw, ref, watch } from 'vue';
import MkPagination from '@/components/MkPagination.vue';
import MkButton from '@/components/MkButton.vue';
import { userPage, acct } from '@/filters/user.js';
@@ -44,32 +43,35 @@ import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import { $i } from '@/i.js';
+import { Paginator } from '@/utility/paginator.js';
-const paginationComponent = useTemplateRef('paginationComponent');
+const tab = ref($i?.isLocked ? 'list' : 'sent');
+
+let paginator: Paginator<'following/requests/list' | 'following/requests/sent'>;
-const pagination = computed<PagingCtx>(() => tab.value === 'list' ? {
- endpoint: 'following/requests/list',
- limit: 10,
-} : {
- endpoint: 'following/requests/sent',
- limit: 10,
-});
+watch(tab, (newTab) => {
+ if (newTab === 'list') {
+ paginator = markRaw(new Paginator('following/requests/list', { limit: 10 }));
+ } else {
+ paginator = markRaw(new Paginator('following/requests/sent', { limit: 10 }));
+ }
+}, { immediate: true });
function accept(user: Misskey.entities.UserLite) {
os.apiWithDialog('following/requests/accept', { userId: user.id }).then(() => {
- paginationComponent.value?.paginator.reload();
+ paginator.reload();
});
}
function reject(user: Misskey.entities.UserLite) {
os.apiWithDialog('following/requests/reject', { userId: user.id }).then(() => {
- paginationComponent.value?.paginator.reload();
+ paginator.reload();
});
}
function cancel(user: Misskey.entities.UserLite) {
os.apiWithDialog('following/requests/cancel', { userId: user.id }).then(() => {
- paginationComponent.value?.paginator.reload();
+ paginator.reload();
});
}
@@ -91,8 +93,6 @@ const headerTabs = computed(() => [
},
]);
-const tab = ref($i?.isLocked ? 'list' : 'sent');
-
definePage(() => ({
title: i18n.ts.followRequests,
icon: 'ti ti-user-plus',
diff --git a/packages/frontend/src/pages/gallery/index.vue b/packages/frontend/src/pages/gallery/index.vue
index af46a4cb0f..2ed663932b 100644
--- a/packages/frontend/src/pages/gallery/index.vue
+++ b/packages/frontend/src/pages/gallery/index.vue
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="tab === 'explore'">
<MkFoldableSection class="_margin">
<template #header><i class="ti ti-clock"></i>{{ i18n.ts.recentPosts }}</template>
- <MkPagination v-slot="{items}" :pagination="recentPostsPagination" :disableAutoLoad="true">
+ <MkPagination v-slot="{items}" :paginator="recentPostsPaginator">
<div :class="$style.items">
<MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/>
</div>
@@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkFoldableSection>
<MkFoldableSection class="_margin">
<template #header><i class="ti ti-comet"></i>{{ i18n.ts.popularPosts }}</template>
- <MkPagination v-slot="{items}" :pagination="popularPostsPagination" :disableAutoLoad="true">
+ <MkPagination v-slot="{items}" :paginator="popularPostsPaginator">
<div :class="$style.items">
<MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/>
</div>
@@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkFoldableSection>
</div>
<div v-else-if="tab === 'liked'">
- <MkPagination v-slot="{items}" :pagination="likedPostsPagination">
+ <MkPagination v-slot="{items}" :paginator="likedPostsPaginator">
<div :class="$style.items">
<MkGalleryPostPreview v-for="like in items" :key="like.id" :post="like.post" class="post"/>
</div>
@@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div v-else-if="tab === 'my'">
<MkA to="/gallery/new" class="_link" style="margin: 16px;"><i class="ti ti-plus"></i> {{ i18n.ts.postToGallery }}</MkA>
- <MkPagination v-slot="{items}" :pagination="myPostsPagination">
+ <MkPagination v-slot="{items}" :paginator="myPostsPaginator">
<div :class="$style.items">
<MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/>
</div>
@@ -44,13 +44,14 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { watch, ref, computed } from 'vue';
+import { watch, ref, computed, markRaw } from 'vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import MkPagination from '@/components/MkPagination.vue';
import MkGalleryPostPreview from '@/components/MkGalleryPostPreview.vue';
import { definePage } from '@/page.js';
import { i18n } from '@/i18n.js';
import { useRouter } from '@/router.js';
+import { Paginator } from '@/utility/paginator.js';
const router = useRouter();
@@ -59,34 +60,19 @@ const props = defineProps<{
}>();
const tab = ref('explore');
-const tags = ref([]);
const tagsRef = ref();
-const recentPostsPagination = {
- endpoint: 'gallery/posts' as const,
+const recentPostsPaginator = markRaw(new Paginator('gallery/posts', {
limit: 6,
-};
-const popularPostsPagination = {
- endpoint: 'gallery/featured' as const,
+}));
+const popularPostsPaginator = markRaw(new Paginator('gallery/featured', {
noPaging: true,
-};
-const myPostsPagination = {
- endpoint: 'i/gallery/posts' as const,
+}));
+const myPostsPaginator = markRaw(new Paginator('i/gallery/posts', {
limit: 5,
-};
-const likedPostsPagination = {
- endpoint: 'i/gallery/likes' as const,
+}));
+const likedPostsPaginator = markRaw(new Paginator('i/gallery/likes', {
limit: 5,
-};
-
-const tagUsersPagination = computed(() => ({
- endpoint: 'hashtags/users' as const,
- limit: 30,
- params: {
- tag: props.tag,
- origin: 'combined',
- sort: '+follower',
- },
}));
watch(() => props.tag, () => {
diff --git a/packages/frontend/src/pages/gallery/post.vue b/packages/frontend/src/pages/gallery/post.vue
index 3db003d9e2..d02b72dd99 100644
--- a/packages/frontend/src/pages/gallery/post.vue
+++ b/packages/frontend/src/pages/gallery/post.vue
@@ -46,7 +46,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkContainer :max-height="300" :foldable="true" class="other">
<template #icon><i class="ti ti-clock"></i></template>
<template #header>{{ i18n.ts.recentPosts }}</template>
- <MkPagination v-slot="{items}" :pagination="otherPostsPagination">
+ <MkPagination v-slot="{items}" :paginator="otherPostsPaginator">
<div class="sdrarzaf">
<MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/>
</div>
@@ -62,7 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, watch, ref, defineAsyncComponent } from 'vue';
+import { computed, watch, ref, defineAsyncComponent, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import { url } from '@@/js/config.js';
import type { MenuItem } from '@/types/menu.js';
@@ -80,6 +80,7 @@ import { $i } from '@/i.js';
import { isSupportShare } from '@/utility/navigator.js';
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
import { useRouter } from '@/router.js';
+import { Paginator } from '@/utility/paginator.js';
const router = useRouter();
@@ -89,13 +90,12 @@ const props = defineProps<{
const post = ref<Misskey.entities.GalleryPost | null>(null);
const error = ref<any>(null);
-const otherPostsPagination = {
- endpoint: 'users/gallery/posts' as const,
+const otherPostsPaginator = markRaw(new Paginator('users/gallery/posts', {
limit: 6,
- params: computed(() => ({
+ computedParams: computed(() => ({
userId: post.value.user.id,
})),
-};
+}));
function fetchPost() {
post.value = null;
diff --git a/packages/frontend/src/pages/instance-info.vue b/packages/frontend/src/pages/instance-info.vue
index 7c5191276d..14a64f0bd5 100644
--- a/packages/frontend/src/pages/instance-info.vue
+++ b/packages/frontend/src/pages/instance-info.vue
@@ -115,7 +115,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</div>
<div v-else-if="tab === 'users'" class="_gaps_m">
- <MkPagination v-slot="{ items }" :pagination="usersPagination">
+ <MkPagination v-slot="{ items }" :paginator="usersPaginator">
<div :class="$style.users">
<MkA v-for="user in items" :key="user.id" v-tooltip.mfm="`Last posted: ${user.updatedAt ? dateString(user.updatedAt) : 'unknown'}`" :to="`/admin/user/${user.id}`">
<MkUserCardMini :user="user"/>
@@ -132,10 +132,9 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { ref, computed, watch } from 'vue';
+import { ref, computed, watch, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import type { ChartSrc } from '@/components/MkChart.vue';
-import type { PagingCtx } from '@/composables/use-pagination.js';
import MkChart from '@/components/MkChart.vue';
import MkObjectView from '@/components/MkObjectView.vue';
import FormLink from '@/components/form/link.vue';
@@ -156,6 +155,7 @@ import MkPagination from '@/components/MkPagination.vue';
import { getProxiedImageUrlNullable } from '@/utility/media-proxy.js';
import { dateString } from '@/filters/date.js';
import MkTextarea from '@/components/MkTextarea.vue';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
host: string;
@@ -173,8 +173,7 @@ const isMediaSilenced = ref(false);
const faviconUrl = ref<string | null>(null);
const moderationNote = ref('');
-const usersPagination = {
- endpoint: iAmModerator ? 'admin/show-users' : 'users',
+const usersPaginator = iAmModerator ? markRaw(new Paginator('admin/show-users', {
limit: 10,
params: {
sort: '+updatedAt',
@@ -182,7 +181,15 @@ const usersPagination = {
hostname: props.host,
},
offsetMode: true,
-} satisfies PagingCtx<'admin/show-users' | 'users'>;
+})) : markRaw(new Paginator('users', {
+ limit: 10,
+ params: {
+ sort: '+updatedAt',
+ state: 'all',
+ hostname: props.host,
+ },
+ offsetMode: true,
+}));
if (iAmModerator) {
watch(moderationNote, async () => {
diff --git a/packages/frontend/src/pages/invite.vue b/packages/frontend/src/pages/invite.vue
index 98e3190e4b..d69b7984c0 100644
--- a/packages/frontend/src/pages/invite.vue
+++ b/packages/frontend/src/pages/invite.vue
@@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton inline primary rounded :disabled="currentInviteLimit !== null && currentInviteLimit <= 0" @click="create"><i class="ti ti-user-plus"></i> {{ i18n.ts.createInviteCode }}</MkButton>
<div v-if="currentInviteLimit !== null">{{ i18n.tsx.createLimitRemaining({ limit: currentInviteLimit }) }}</div>
- <MkPagination ref="pagingComponent" :pagination="pagination">
+ <MkPagination :paginator="paginator">
<template #default="{ items }">
<div class="_gaps_s">
<MkInviteCode v-for="item in (items as Misskey.entities.InviteCode[])" :key="item.id" :invite="item" :onDeleted="deleted"/>
@@ -27,9 +27,8 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, ref, useTemplateRef } from 'vue';
+import { computed, markRaw, ref } from 'vue';
import * as Misskey from 'misskey-js';
-import type { PagingCtx } from '@/composables/use-pagination.js';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/utility/misskey-api.js';
@@ -39,16 +38,15 @@ import MkInviteCode from '@/components/MkInviteCode.vue';
import { definePage } from '@/page.js';
import { instance } from '@/instance.js';
import { $i } from '@/i.js';
+import { Paginator } from '@/utility/paginator.js';
-const pagingComponent = useTemplateRef('pagingComponent');
const currentInviteLimit = ref<null | number>(null);
const inviteLimit = (($i != null && $i.policies.inviteLimit) || (($i == null && instance.policies.inviteLimit))) as number;
const inviteLimitCycle = (($i != null && $i.policies.inviteLimitCycle) || ($i == null && instance.policies.inviteLimitCycle)) as number;
-const pagination: PagingCtx = {
- endpoint: 'invite/list' as const,
+const paginator = markRaw(new Paginator('invite/list', {
limit: 10,
-};
+}));
const resetCycle = computed<null | string>(() => {
if (!inviteLimitCycle) return null;
@@ -68,14 +66,12 @@ async function create() {
text: ticket.code,
});
- pagingComponent.value?.paginator.prepend(ticket);
+ paginator.prepend(ticket);
update();
}
function deleted(id: string) {
- if (pagingComponent.value) {
- pagingComponent.value.paginator.removeItem(id);
- }
+ paginator.removeItem(id);
update();
}
diff --git a/packages/frontend/src/pages/my-clips/index.vue b/packages/frontend/src/pages/my-clips/index.vue
index 4477edf505..4c664a0951 100644
--- a/packages/frontend/src/pages/my-clips/index.vue
+++ b/packages/frontend/src/pages/my-clips/index.vue
@@ -12,44 +12,38 @@ 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" withControl>
+ <MkPagination v-slot="{ items }" :paginator="paginator" class="_gaps" withControl>
<MkClipPreview v-for="item in items" :key="item.id" :clip="item" :noUserInfo="true"/>
</MkPagination>
</div>
- <div v-else-if="tab === 'favorites'" class="_gaps">
- <MkClipPreview v-for="item in favorites" :key="item.id" :clip="item"/>
+ <div v-else-if="tab === 'favorites'">
+ <MkPagination v-slot="{ items }" :paginator="favoritesPaginator" class="_gaps" withControl>
+ <MkClipPreview v-for="item in items" :key="item.id" :clip="item" :noUserInfo="true"/>
+ </MkPagination>
</div>
</div>
</PageWithHeader>
</template>
<script lang="ts" setup>
-import { watch, ref, useTemplateRef, computed } from 'vue';
+import { watch, ref, computed, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import MkPagination from '@/components/MkPagination.vue';
import MkButton from '@/components/MkButton.vue';
import MkClipPreview from '@/components/MkClipPreview.vue';
import * as os from '@/os.js';
-import { misskeyApi } from '@/utility/misskey-api.js';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import { clipsCache } from '@/cache.js';
-
-const pagination = {
- endpoint: 'clips/list' as const,
- noPaging: true,
- limit: 10,
-};
+import { Paginator } from '@/utility/paginator.js';
const tab = ref('my');
-const favorites = ref<Misskey.entities.Clip[] | null>(null);
-
-const pagingComponent = useTemplateRef('pagingComponent');
+const paginator = markRaw(new Paginator('clips/list', {
+}));
-watch(tab, async () => {
- favorites.value = await misskeyApi('clips/my-favorites');
-});
+const favoritesPaginator = markRaw(new Paginator('clips/my-favorites', {
+}));
async function create() {
const { canceled, result } = await os.form(i18n.ts.createNewClip, {
@@ -76,15 +70,15 @@ async function create() {
clipsCache.delete();
- pagingComponent.value?.paginator.reload();
+ paginator.reload();
}
function onClipCreated() {
- pagingComponent.value?.paginator.reload();
+ paginator.reload();
}
function onClipDeleted() {
- pagingComponent.value?.paginator.reload();
+ paginator.reload();
}
const headerActions = computed(() => []);
diff --git a/packages/frontend/src/pages/my-lists/list.vue b/packages/frontend/src/pages/my-lists/list.vue
index e33125ac93..74ac47c571 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" withControl>
+ <MkPagination :paginator="membershipsPaginator" withControl>
<template #default="{ items }">
<div class="_gaps_s">
<div v-for="item in items" :key="item.id">
@@ -52,7 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, ref, useTemplateRef, watch } from 'vue';
+import { computed, markRaw, ref, watch } from 'vue';
import * as Misskey from 'misskey-js';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os.js';
@@ -69,6 +69,7 @@ import { ensureSignin } from '@/i.js';
import MkPagination from '@/components/MkPagination.vue';
import { mainRouter } from '@/router.js';
import { prefer } from '@/preferences.js';
+import { Paginator } from '@/utility/paginator.js';
const $i = ensureSignin();
@@ -80,17 +81,15 @@ const props = defineProps<{
listId: string;
}>();
-const paginationEl = useTemplateRef('paginationEl');
const list = ref<Misskey.entities.UserList | null>(null);
const isPublic = ref(false);
const name = ref('');
-const membershipsPagination = {
- endpoint: 'users/lists/get-memberships' as const,
+const membershipsPaginator = markRaw(new Paginator('users/lists/get-memberships', {
limit: 30,
- params: computed(() => ({
+ computedParams: computed(() => ({
listId: props.listId,
})),
-};
+}));
function fetchList() {
misskeyApi('users/lists/show', {
@@ -109,7 +108,7 @@ function addUser() {
listId: list.value.id,
userId: user.id,
}).then(() => {
- paginationEl.value?.paginator.reload();
+ membershipsPaginator.reload();
});
});
}
@@ -125,7 +124,7 @@ async function removeUser(item, ev) {
listId: list.value.id,
userId: item.userId,
}).then(() => {
- paginationEl.value?.paginator.removeItem(item.id);
+ membershipsPaginator.removeItem(item.id);
});
},
}], ev.currentTarget ?? ev.target);
@@ -147,7 +146,7 @@ async function showMembershipMenu(item, ev) {
userId: item.userId,
withReplies,
}).then(() => {
- paginationEl.value!.paginator.updateItem(item.id, (old) => ({
+ membershipsPaginator.updateItem(item.id, (old) => ({
...old,
withReplies,
}));
diff --git a/packages/frontend/src/pages/note.vue b/packages/frontend/src/pages/note.vue
index ccb62749fa..b128cf5312 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 :withControl="false" :pullToRefresh="false" class="" :pagination="showNext === 'channel' ? nextChannelPagination : nextUserPagination" :noGap="true" :disableAutoLoad="true"/>
+ <MkNotesTimeline :withControl="false" :pullToRefresh="false" class="" :paginator="showNext === 'channel' ? nextChannelPaginator : nextUserPaginator" :noGap="true"/>
</div>
<div class="_margin">
@@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div v-if="showPrev" class="_margin">
- <MkNotesTimeline :withControl="false" :pullToRefresh="false" class="" :pagination="showPrev === 'channel' ? prevChannelPagination : prevUserPagination" :noGap="true"/>
+ <MkNotesTimeline :withControl="false" :pullToRefresh="false" class="" :paginator="showPrev === 'channel' ? prevChannelPaginator : prevUserPaginator" :noGap="true"/>
</div>
</div>
<MkError v-else-if="error" @retry="fetchNote()"/>
@@ -45,10 +45,9 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, watch, ref } from 'vue';
+import { computed, watch, ref, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import { host } from '@@/js/config.js';
-import type { PagingCtx } from '@/composables/use-pagination.js';
import MkNoteDetailed from '@/components/MkNoteDetailed.vue';
import MkNotesTimeline from '@/components/MkNotesTimeline.vue';
import MkRemoteCaution from '@/components/MkRemoteCaution.vue';
@@ -63,6 +62,7 @@ import { pleaseLogin } from '@/utility/please-login.js';
import { getAppearNote } from '@/utility/get-appear-note.js';
import { serverContext, assertServerContext } from '@/server-context.js';
import { $i } from '@/i.js';
+import { Paginator } from '@/utility/paginator.js';
// contextは非ログイン状態の情報しかないためログイン時は利用できない
const CTX_NOTE = !$i && assertServerContext(serverContext, 'note') ? serverContext.note : null;
@@ -78,45 +78,41 @@ const showPrev = ref<'user' | 'channel' | false>(false);
const showNext = ref<'user' | 'channel' | false>(false);
const error = ref();
-const prevUserPagination: PagingCtx = {
- endpoint: 'users/notes',
+const prevUserPaginator = markRaw(new Paginator('users/notes', {
limit: 10,
initialId: props.noteId,
initialDirection: 'older',
- params: computed(() => note.value ? ({
+ computedParams: computed(() => note.value ? ({
userId: note.value.userId,
}) : undefined),
-};
+}));
-const nextUserPagination: PagingCtx = {
- endpoint: 'users/notes',
+const nextUserPaginator = markRaw(new Paginator('users/notes', {
limit: 10,
initialId: props.noteId,
initialDirection: 'newer',
- params: computed(() => note.value ? ({
+ computedParams: computed(() => note.value ? ({
userId: note.value.userId,
}) : undefined),
-};
+}));
-const prevChannelPagination: PagingCtx = {
- endpoint: 'channels/timeline',
+const prevChannelPaginator = markRaw(new Paginator('channels/timeline', {
limit: 10,
initialId: props.noteId,
initialDirection: 'older',
- params: computed(() => note.value ? ({
+ computedParams: computed(() => note.value ? ({
channelId: note.value.channelId,
}) : undefined),
-};
+}));
-const nextChannelPagination: PagingCtx = {
- endpoint: 'channels/timeline',
+const nextChannelPaginator = markRaw(new Paginator('channels/timeline', {
limit: 10,
initialId: props.noteId,
initialDirection: 'newer',
- params: computed(() => note.value ? ({
+ computedParams: computed(() => note.value ? ({
channelId: note.value.channelId,
}) : undefined),
-};
+}));
function fetchNote() {
showPrev.value = false;
diff --git a/packages/frontend/src/pages/notifications.vue b/packages/frontend/src/pages/notifications.vue
index db911c1202..a8c1fb654c 100644
--- a/packages/frontend/src/pages/notifications.vue
+++ b/packages/frontend/src/pages/notifications.vue
@@ -10,40 +10,39 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkStreamingNotificationsTimeline :class="$style.notifications" :excludeTypes="excludeTypes"/>
</div>
<div v-else-if="tab === 'mentions'">
- <MkNotesTimeline :pagination="mentionsPagination"/>
+ <MkNotesTimeline :paginator="mentionsPaginator"/>
</div>
<div v-else-if="tab === 'directNotes'">
- <MkNotesTimeline :pagination="directNotesPagination"/>
+ <MkNotesTimeline :paginator="directNotesPaginator"/>
</div>
</div>
</PageWithHeader>
</template>
<script lang="ts" setup>
-import { computed, ref } from 'vue';
+import { computed, markRaw, ref } from 'vue';
import { notificationTypes } from '@@/js/const.js';
import MkStreamingNotificationsTimeline from '@/components/MkStreamingNotificationsTimeline.vue';
import MkNotesTimeline from '@/components/MkNotesTimeline.vue';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
+import { Paginator } from '@/utility/paginator.js';
const tab = ref('all');
const includeTypes = ref<string[] | null>(null);
const excludeTypes = computed(() => includeTypes.value ? notificationTypes.filter(t => !includeTypes.value.includes(t)) : null);
-const mentionsPagination = {
- endpoint: 'notes/mentions' as const,
+const mentionsPaginator = markRaw(new Paginator('notes/mentions', {
limit: 10,
-};
+}));
-const directNotesPagination = {
- endpoint: 'notes/mentions' as const,
+const directNotesPaginator = markRaw(new Paginator('notes/mentions', {
limit: 10,
params: {
visibility: 'specified',
},
-};
+}));
function setFilter(ev) {
const typeItems = notificationTypes.map(t => ({
diff --git a/packages/frontend/src/pages/page.vue b/packages/frontend/src/pages/page.vue
index 2cd8718968..99c147c8cf 100644
--- a/packages/frontend/src/pages/page.vue
+++ b/packages/frontend/src/pages/page.vue
@@ -84,7 +84,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkContainer :max-height="300" :foldable="true" class="other">
<template #icon><i class="ti ti-clock"></i></template>
<template #header>{{ i18n.ts.recentPosts }}</template>
- <MkPagination v-slot="{items}" :pagination="otherPostsPagination" :class="$style.relatedPagesRoot" class="_gaps">
+ <MkPagination v-slot="{items}" :paginator="otherPostsPaginator" :class="$style.relatedPagesRoot" class="_gaps">
<MkPagePreview v-for="page in items" :key="page.id" :page="page" :class="$style.relatedPagesItem"/>
</MkPagination>
</MkContainer>
@@ -97,7 +97,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, watch, ref, defineAsyncComponent } from 'vue';
+import { computed, watch, ref, defineAsyncComponent, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import { url } from '@@/js/config.js';
import type { MenuItem } from '@/types/menu.js';
@@ -122,6 +122,7 @@ import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
import { useRouter } from '@/router.js';
import { prefer } from '@/preferences.js';
import { getPluginHandlers } from '@/plugin.js';
+import { Paginator } from '@/utility/paginator.js';
const router = useRouter();
@@ -132,13 +133,12 @@ const props = defineProps<{
const page = ref<Misskey.entities.Page | null>(null);
const error = ref<any>(null);
-const otherPostsPagination = {
- endpoint: 'users/pages' as const,
+const otherPostsPaginator = markRaw(new Paginator('users/pages', {
limit: 6,
- params: computed(() => ({
+ computedParams: computed(() => ({
userId: page.value.user.id,
})),
-};
+}));
const path = computed(() => props.username + '/' + props.pageName);
function fetchPage() {
diff --git a/packages/frontend/src/pages/pages.vue b/packages/frontend/src/pages/pages.vue
index 880c4deb25..780f0836a7 100644
--- a/packages/frontend/src/pages/pages.vue
+++ b/packages/frontend/src/pages/pages.vue
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs" :swipable="true">
<div class="_spacer" style="--MI_SPACER-w: 700px;">
<div v-if="tab === 'featured'">
- <MkPagination v-slot="{items}" :pagination="featuredPagesPagination">
+ <MkPagination v-slot="{items}" :paginator="featuredPagesPaginator">
<div class="_gaps">
<MkPagePreview v-for="page in items" :key="page.id" :page="page"/>
</div>
@@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-else-if="tab === 'my'" class="_gaps">
<MkButton class="new" @click="create()"><i class="ti ti-plus"></i></MkButton>
- <MkPagination v-slot="{items}" :pagination="myPagesPagination">
+ <MkPagination v-slot="{items}" :paginator="myPagesPaginator">
<div class="_gaps">
<MkPagePreview v-for="page in items" :key="page.id" :page="page"/>
</div>
@@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div v-else-if="tab === 'liked'">
- <MkPagination v-slot="{items}" :pagination="likedPagesPagination">
+ <MkPagination v-slot="{items}" :paginator="likedPagesPaginator">
<div class="_gaps">
<MkPagePreview v-for="like in items" :key="like.page.id" :page="like.page"/>
</div>
@@ -35,30 +35,28 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, ref } from 'vue';
+import { computed, markRaw, ref } from 'vue';
import MkPagePreview from '@/components/MkPagePreview.vue';
import MkPagination from '@/components/MkPagination.vue';
import MkButton from '@/components/MkButton.vue';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import { useRouter } from '@/router.js';
+import { Paginator } from '@/utility/paginator.js';
const router = useRouter();
const tab = ref('featured');
-const featuredPagesPagination = {
- endpoint: 'pages/featured' as const,
+const featuredPagesPaginator = markRaw(new Paginator('pages/featured', {
noPaging: true,
-};
-const myPagesPagination = {
- endpoint: 'i/pages' as const,
+}));
+const myPagesPaginator = markRaw(new Paginator('i/pages', {
limit: 5,
-};
-const likedPagesPagination = {
- endpoint: 'i/page-likes' as const,
+}));
+const likedPagesPaginator = markRaw(new Paginator('i/page-likes', {
limit: 5,
-};
+}));
function create() {
router.push('/pages/new');
diff --git a/packages/frontend/src/pages/reversi/index.vue b/packages/frontend/src/pages/reversi/index.vue
index f3252402d7..e4d921b8d2 100644
--- a/packages/frontend/src/pages/reversi/index.vue
+++ b/packages/frontend/src/pages/reversi/index.vue
@@ -31,7 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkFolder v-if="$i" :defaultOpen="true">
<template #label>{{ i18n.ts._reversi.myGames }}</template>
- <MkPagination :pagination="myGamesPagination" :disableAutoLoad="true">
+ <MkPagination :paginator="myGamesPaginator">
<template #default="{ items }">
<div :class="$style.gamePreviews">
<MkA v-for="g in items" :key="g.id" v-panel :class="[$style.gamePreview, !g.isStarted && !g.isEnded && $style.gamePreviewWaiting, g.isStarted && !g.isEnded && $style.gamePreviewActive]" tabindex="-1" :to="`/reversi/g/${g.id}`">
@@ -58,7 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkFolder :defaultOpen="true">
<template #label>{{ i18n.ts._reversi.allGames }}</template>
- <MkPagination :pagination="gamesPagination" :disableAutoLoad="true">
+ <MkPagination :paginator="gamesPaginator">
<template #default="{ items }">
<div :class="$style.gamePreviews">
<MkA v-for="g in items" :key="g.id" v-panel :class="[$style.gamePreview, !g.isStarted && !g.isEnded && $style.gamePreviewWaiting, g.isStarted && !g.isEnded && $style.gamePreviewActive]" tabindex="-1" :to="`/reversi/g/${g.id}`">
@@ -105,7 +105,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { onDeactivated, onMounted, onUnmounted, ref } from 'vue';
+import { markRaw, onDeactivated, onMounted, onUnmounted, ref } from 'vue';
import * as Misskey from 'misskey-js';
import { useInterval } from '@@/js/use-interval.js';
import { misskeyApi } from '@/utility/misskey-api.js';
@@ -120,19 +120,18 @@ import { useRouter } from '@/router.js';
import * as os from '@/os.js';
import { pleaseLogin } from '@/utility/please-login.js';
import * as sound from '@/utility/sound.js';
+import { Paginator } from '@/utility/paginator.js';
-const myGamesPagination = {
- endpoint: 'reversi/games' as const,
+const myGamesPaginator = markRaw(new Paginator('reversi/games', {
limit: 10,
params: {
my: true,
},
-};
+}));
-const gamesPagination = {
- endpoint: 'reversi/games' as const,
+const gamesPaginator = markRaw(new Paginator('reversi/games', {
limit: 10,
-};
+}));
const router = useRouter();
diff --git a/packages/frontend/src/pages/role.vue b/packages/frontend/src/pages/role.vue
index 42639cde9e..619c80edd1 100644
--- a/packages/frontend/src/pages/role.vue
+++ b/packages/frontend/src/pages/role.vue
@@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-else-if="tab === 'users'" class="_spacer" style="--MI_SPACER-w: 1200px;">
<div class="_gaps_s">
<div v-if="role">{{ role.description }}</div>
- <MkUserList v-if="visible" :pagination="users" :extractor="(item) => item.user"/>
+ <MkUserList v-if="visible" :paginator="usersPaginator" :extractor="(item) => item.user"/>
<MkResult v-else-if="!visible" type="empty" :text="i18n.ts.nothing"/>
</div>
</div>
@@ -23,13 +23,14 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, watch, ref } from 'vue';
+import { computed, watch, ref, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import { misskeyApi } from '@/utility/misskey-api.js';
import MkUserList from '@/components/MkUserList.vue';
import { definePage } from '@/page.js';
import { i18n } from '@/i18n.js';
import MkStreamingNotesTimeline from '@/components/MkStreamingNotesTimeline.vue';
+import { Paginator } from '@/utility/paginator.js';
const props = withDefaults(defineProps<{
roleId: string;
@@ -60,12 +61,11 @@ watch(() => props.roleId, () => {
});
}, { immediate: true });
-const users = computed(() => ({
- endpoint: 'roles/users' as const,
+const usersPaginator = markRaw(new Paginator('roles/users', {
limit: 30,
- params: {
+ computedParams: computed(() => ({
roleId: props.roleId,
- },
+ })),
}));
const headerTabs = computed(() => [{
diff --git a/packages/frontend/src/pages/search.note.vue b/packages/frontend/src/pages/search.note.vue
index 352564bc9c..f19c1e7efb 100644
--- a/packages/frontend/src/pages/search.note.vue
+++ b/packages/frontend/src/pages/search.note.vue
@@ -103,19 +103,18 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</div>
- <MkFoldableSection v-if="notePagination">
+ <MkFoldableSection v-if="paginator">
<template #header>{{ i18n.ts.searchResult }}</template>
- <MkNotesTimeline :key="`searchNotes:${key}`" :pagination="notePagination"/>
+ <MkNotesTimeline :key="`searchNotes:${key}`" :paginator="paginator"/>
</MkFoldableSection>
</div>
</template>
<script lang="ts" setup>
-import { computed, ref, shallowRef, toRef } from 'vue';
+import { computed, markRaw, ref, shallowRef, toRef } from 'vue';
+import { host as localHost } from '@@/js/config.js';
import type * as Misskey from 'misskey-js';
-import type { PagingCtx } from '@/composables/use-pagination.js';
import { $i } from '@/i.js';
-import { host as localHost } from '@@/js/config.js';
import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js';
import * as os from '@/os.js';
@@ -128,6 +127,7 @@ import MkInput from '@/components/MkInput.vue';
import MkNotesTimeline from '@/components/MkNotesTimeline.vue';
import MkRadios from '@/components/MkRadios.vue';
import MkUserCardMini from '@/components/MkUserCardMini.vue';
+import { Paginator } from '@/utility/paginator.js';
const props = withDefaults(defineProps<{
query?: string;
@@ -144,7 +144,7 @@ const props = withDefaults(defineProps<{
const router = useRouter();
const key = ref(0);
-const notePagination = ref<PagingCtx<'notes/search'>>();
+const paginator = shallowRef<Paginator<'notes/search'> | null>(null);
const searchQuery = ref(toRef(props, 'query').value);
const hostInput = ref(toRef(props, 'host').value);
@@ -299,13 +299,12 @@ async function search() {
}
}
- notePagination.value = {
- endpoint: 'notes/search',
+ paginator.value = markRaw(new Paginator('notes/search', {
limit: 10,
params: {
...searchParams.value,
},
- };
+ }));
key.value++;
}
diff --git a/packages/frontend/src/pages/search.user.vue b/packages/frontend/src/pages/search.user.vue
index eaec043311..bd67d41a80 100644
--- a/packages/frontend/src/pages/search.user.vue
+++ b/packages/frontend/src/pages/search.user.vue
@@ -17,17 +17,16 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton large primary gradate rounded @click="search">{{ i18n.ts.search }}</MkButton>
</div>
- <MkFoldableSection v-if="userPagination">
+ <MkFoldableSection v-if="paginator">
<template #header>{{ i18n.ts.searchResult }}</template>
- <MkUserList :key="`searchUsers:${key}`" :pagination="userPagination"/>
+ <MkUserList :key="`searchUsers:${key}`" :paginator="paginator"/>
</MkFoldableSection>
</div>
</template>
<script lang="ts" setup>
-import { ref, toRef } from 'vue';
+import { markRaw, ref, shallowRef, toRef } from 'vue';
import type { Endpoints } from 'misskey-js';
-import type { PagingCtx } from '@/composables/use-pagination.js';
import MkUserList from '@/components/MkUserList.vue';
import MkInput from '@/components/MkInput.vue';
import MkRadios from '@/components/MkRadios.vue';
@@ -38,6 +37,7 @@ import * as os from '@/os.js';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import { misskeyApi } from '@/utility/misskey-api.js';
import { useRouter } from '@/router.js';
+import { Paginator } from '@/utility/paginator.js';
const props = withDefaults(defineProps<{
query?: string,
@@ -50,7 +50,7 @@ const props = withDefaults(defineProps<{
const router = useRouter();
const key = ref(0);
-const userPagination = ref<PagingCtx<'users/search'>>();
+const paginator = shallowRef<Paginator<'users/search'> | null>(null);
const searchQuery = ref(toRef(props, 'query').value);
const searchOrigin = ref(toRef(props, 'origin').value);
@@ -112,15 +112,14 @@ async function search() {
}
}
- userPagination.value = {
- endpoint: 'users/search',
+ paginator.value = markRaw(new Paginator('users/search', {
limit: 10,
offsetMode: true,
params: {
query: query,
origin: instance.federation === 'none' ? 'local' : searchOrigin.value,
},
- };
+ }));
key.value++;
}
diff --git a/packages/frontend/src/pages/settings/apps.vue b/packages/frontend/src/pages/settings/apps.vue
index ec45eb3487..5f51a5e079 100644
--- a/packages/frontend/src/pages/settings/apps.vue
+++ b/packages/frontend/src/pages/settings/apps.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="_gaps_m">
- <FormPagination ref="list" :pagination="pagination">
+ <MkPagination :paginator="paginator">
<template #empty><MkResult type="empty"/></template>
<template #default="{items}">
<div class="_gaps">
@@ -44,35 +44,33 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkFolder>
</div>
</template>
- </FormPagination>
+ </MkPagination>
</div>
</template>
<script lang="ts" setup>
-import { ref, computed, useTemplateRef } from 'vue';
+import { ref, computed, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
-import FormPagination from '@/components/MkPagination.vue';
+import MkPagination from '@/components/MkPagination.vue';
import { misskeyApi } from '@/utility/misskey-api.js';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import MkKeyValue from '@/components/MkKeyValue.vue';
import MkButton from '@/components/MkButton.vue';
import MkFolder from '@/components/MkFolder.vue';
+import { Paginator } from '@/utility/paginator.js';
-const list = useTemplateRef('list');
-
-const pagination = {
- endpoint: 'i/apps' as const,
+const paginator = markRaw(new Paginator('i/apps', {
limit: 100,
noPaging: true,
params: {
sort: '+lastUsedAt',
},
-};
+}));
function revoke(token) {
misskeyApi('i/revoke-token', { tokenId: token.id }).then(() => {
- list.value?.paginator.reload();
+ paginator.reload();
});
}
diff --git a/packages/frontend/src/pages/settings/connect.vue b/packages/frontend/src/pages/settings/connect.vue
index c2335ae69f..1e701096c5 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" withControl>
+ <MkPagination :paginator="paginator" withControl>
<template #default="{items}">
<div class="_gaps">
<FormLink v-for="webhook in items" :key="webhook.id" :to="`/settings/webhook/edit/${webhook.id}`">
@@ -61,7 +61,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, ref, defineAsyncComponent } from 'vue';
+import { computed, ref, defineAsyncComponent, markRaw } from 'vue';
import MkPagination from '@/components/MkPagination.vue';
import FormSection from '@/components/form/section.vue';
import FormLink from '@/components/form/link.vue';
@@ -72,14 +72,14 @@ import * as os from '@/os.js';
import { misskeyApi } from '@/utility/misskey-api.js';
import MkButton from '@/components/MkButton.vue';
import MkFolder from '@/components/MkFolder.vue';
+import { Paginator } from '@/utility/paginator.js';
const isDesktop = ref(window.innerWidth >= 1100);
-const pagination = {
- endpoint: 'i/webhooks/list' as const,
+const paginator = markRaw(new Paginator('i/webhooks/list', {
limit: 100,
noPaging: true,
-};
+}));
async function generateToken() {
const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkTokenGenerateWindow.vue').then(x => x.default), {}, {
diff --git a/packages/frontend/src/pages/settings/drive-cleaner.vue b/packages/frontend/src/pages/settings/drive-cleaner.vue
index 6b73560174..24f0fa5153 100644
--- a/packages/frontend/src/pages/settings/drive-cleaner.vue
+++ b/packages/frontend/src/pages/settings/drive-cleaner.vue
@@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<option v-for="x in sortOptions" :key="x.value" :value="x.value">{{ x.displayName }}</option>
</MkSelect>
<div v-if="!fetching">
- <MkPagination v-slot="{items}" :pagination="pagination">
+ <MkPagination v-slot="{items}" :paginator="paginator">
<div class="_gaps">
<div
v-for="file in items" :key="file.id"
@@ -48,9 +48,9 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script setup lang="ts">
-import { computed, ref, watch } from 'vue';
-import type { StyleValue } from 'vue';
+import { computed, markRaw, ref, watch } from 'vue';
import tinycolor from 'tinycolor2';
+import type { StyleValue } from 'vue';
import * as os from '@/os.js';
import { misskeyApi } from '@/utility/misskey-api.js';
import MkPagination from '@/components/MkPagination.vue';
@@ -60,13 +60,13 @@ import bytes from '@/filters/bytes.js';
import { definePage } from '@/page.js';
import MkSelect from '@/components/MkSelect.vue';
import { getDriveFileMenu } from '@/utility/get-drive-file-menu.js';
+import { Paginator } from '@/utility/paginator.js';
const sortMode = ref('+size');
-const pagination = {
- endpoint: 'drive/files' as const,
+const paginator = markRaw(new Paginator('drive/files', {
limit: 10,
- params: computed(() => ({ sort: sortMode.value })),
-};
+ computedParams: computed(() => ({ sort: sortMode.value })),
+}));
const sortOptions = [
{ value: 'sizeDesc', displayName: i18n.ts._drivecleaner.orderBySizeDesc },
diff --git a/packages/frontend/src/pages/settings/mute-block.vue b/packages/frontend/src/pages/settings/mute-block.vue
index 755bc79b6a..3002cd0e89 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" withControl>
+ <MkPagination :paginator="renoteMutingPaginator" 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" withControl>
+ <MkPagination :paginator="mutingPaginator" 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" withControl>
+ <MkPagination :paginator="blockingPaginator" withControl>
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
<template #default="{ items }">
@@ -174,7 +174,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { ref, computed, watch } from 'vue';
+import { ref, computed, watch, markRaw } from 'vue';
import XEmojiMute from './mute-block.emoji-mute.vue';
import XInstanceMute from './mute-block.instance-mute.vue';
import XWordMute from './mute-block.word-mute.vue';
@@ -192,23 +192,21 @@ import MkSwitch from '@/components/MkSwitch.vue';
import { reloadAsk } from '@/utility/reload-ask.js';
import { prefer } from '@/preferences.js';
import MkFeatureBanner from '@/components/MkFeatureBanner.vue';
+import { Paginator } from '@/utility/paginator.js';
const $i = ensureSignin();
-const renoteMutingPagination = {
- endpoint: 'renote-mute/list' as const,
+const renoteMutingPaginator = markRaw(new Paginator('renote-mute/list', {
limit: 10,
-};
+}));
-const mutingPagination = {
- endpoint: 'mute/list' as const,
+const mutingPaginator = markRaw(new Paginator('mute/list', {
limit: 10,
-};
+}));
-const blockingPagination = {
- endpoint: 'blocking/list' as const,
+const blockingPaginator = markRaw(new Paginator('blocking/list', {
limit: 10,
-};
+}));
const expandedRenoteMuteItems = ref([]);
const expandedMuteItems = ref([]);
diff --git a/packages/frontend/src/pages/settings/security.vue b/packages/frontend/src/pages/settings/security.vue
index c260ae4541..2562993be3 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 withControl>
+ <MkPagination :paginator="paginator" withControl>
<template #default="{items}">
<div>
<div v-for="item in items" :key="item.id" v-panel class="timnmucd">
@@ -53,7 +53,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed } from 'vue';
+import { computed, markRaw } from 'vue';
import X2fa from './2fa.vue';
import FormSection from '@/components/form/section.vue';
import FormSlot from '@/components/form/slot.vue';
@@ -64,11 +64,11 @@ import { misskeyApi } from '@/utility/misskey-api.js';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import MkFeatureBanner from '@/components/MkFeatureBanner.vue';
+import { Paginator } from '@/utility/paginator.js';
-const pagination = {
- endpoint: 'i/signin-history' as const,
+const paginator = markRaw(new Paginator('i/signin-history', {
limit: 5,
-};
+}));
async function change() {
const { canceled: canceled2, result: newPassword } = await os.inputText({
diff --git a/packages/frontend/src/pages/tag.vue b/packages/frontend/src/pages/tag.vue
index d1e5db5a5b..b5a4503b68 100644
--- a/packages/frontend/src/pages/tag.vue
+++ b/packages/frontend/src/pages/tag.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
<div class="_spacer" style="--MI_SPACER-w: 800px;">
- <MkNotesTimeline ref="tlComponent" class="" :pagination="pagination"/>
+ <MkNotesTimeline :paginator="paginator"/>
</div>
<template v-if="$i" #footer>
<div :class="$style.footer">
@@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, ref, useTemplateRef } from 'vue';
+import { computed, markRaw, ref } from 'vue';
import MkNotesTimeline from '@/components/MkNotesTimeline.vue';
import MkButton from '@/components/MkButton.vue';
import { definePage } from '@/page.js';
@@ -28,20 +28,18 @@ import { $i } from '@/i.js';
import { store } from '@/store.js';
import * as os from '@/os.js';
import { genEmbedCode } from '@/utility/get-embed-code.js';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
tag: string;
}>();
-const pagination = {
- endpoint: 'notes/search-by-tag' as const,
+const paginator = markRaw(new Paginator('notes/search-by-tag', {
limit: 10,
- params: computed(() => ({
+ computedParams: computed(() => ({
tag: props.tag,
})),
-};
-
-const tlComponent = useTemplateRef('tlComponent');
+}));
async function post() {
store.set('postFormHashtags', props.tag);
@@ -49,7 +47,7 @@ async function post() {
await os.post();
store.set('postFormHashtags', '');
store.set('postFormWithHashtags', false);
- tlComponent.value?.reload();
+ paginator.reload();
}
const headerActions = computed(() => [{
diff --git a/packages/frontend/src/pages/user-tag.vue b/packages/frontend/src/pages/user-tag.vue
index 959d449e40..ec4c854381 100644
--- a/packages/frontend/src/pages/user-tag.vue
+++ b/packages/frontend/src/pages/user-tag.vue
@@ -7,29 +7,29 @@ SPDX-License-Identifier: AGPL-3.0-only
<PageWithHeader>
<div class="_spacer" style="--MI_SPACER-w: 1200px;">
<div class="_gaps_s">
- <MkUserList :pagination="tagUsers"/>
+ <MkUserList :paginator="paginator"/>
</div>
</div>
</PageWithHeader>
</template>
<script lang="ts" setup>
-import { computed } from 'vue';
+import { computed, markRaw } from 'vue';
import MkUserList from '@/components/MkUserList.vue';
import { definePage } from '@/page.js';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
tag: string;
}>();
-const tagUsers = computed(() => ({
- endpoint: 'hashtags/users' as const,
+const paginator = markRaw(new Paginator('hashtags/users', {
limit: 30,
- params: {
+ computedParams: computed(() => ({
tag: props.tag,
origin: 'combined',
sort: '+follower',
- },
+ })),
}));
definePage(() => ({
diff --git a/packages/frontend/src/pages/user/clips.vue b/packages/frontend/src/pages/user/clips.vue
index 5b5bc3193f..57f7bc13a1 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}" :pagination="pagination" withControl>
+ <MkPagination v-slot="{items}" :paginator="paginator" 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>
@@ -17,21 +17,21 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed } from 'vue';
+import { computed, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import MkPagination from '@/components/MkPagination.vue';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
user: Misskey.entities.User;
}>();
-const pagination = {
- endpoint: 'users/clips' as const,
+const paginator = markRaw(new Paginator('users/clips', {
limit: 20,
- params: computed(() => ({
+ computedParams: computed(() => ({
userId: props.user.id,
})),
-};
+}));
</script>
<style lang="scss" module>
diff --git a/packages/frontend/src/pages/user/files.vue b/packages/frontend/src/pages/user/files.vue
index 339daea257..e241dc8931 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" withControl>
+ <MkPagination v-slot="{items}" :paginator="paginator" withControl>
<div :class="$style.stream">
<MkNoteMediaGrid v-for="note in items" :note="note" square/>
</div>
@@ -16,24 +16,23 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed } from 'vue';
+import { computed, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
-
import MkNoteMediaGrid from '@/components/MkNoteMediaGrid.vue';
import MkPagination from '@/components/MkPagination.vue';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
user: Misskey.entities.UserDetailed;
}>();
-const pagination = {
- endpoint: 'users/notes' as const,
+const paginator = markRaw(new Paginator('users/notes', {
limit: 15,
- params: computed(() => ({
+ computedParams: computed(() => ({
userId: props.user.id,
withFiles: true,
})),
-};
+}));
</script>
<style lang="scss" module>
diff --git a/packages/frontend/src/pages/user/flashs.vue b/packages/frontend/src/pages/user/flashs.vue
index fc1d4e5968..034638fd0e 100644
--- a/packages/frontend/src/pages/user/flashs.vue
+++ b/packages/frontend/src/pages/user/flashs.vue
@@ -5,27 +5,27 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="_spacer" style="--MI_SPACER-w: 700px;">
- <MkPagination v-slot="{items}" :pagination="pagination" withControl>
+ <MkPagination v-slot="{items}" :paginator="paginator" withControl>
<MkFlashPreview v-for="flash in items" :key="flash.id" :flash="flash" class="_margin"/>
</MkPagination>
</div>
</template>
<script lang="ts" setup>
-import { computed } from 'vue';
+import { computed, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import MkFlashPreview from '@/components/MkFlashPreview.vue';
import MkPagination from '@/components/MkPagination.vue';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
user: Misskey.entities.User;
}>();
-const pagination = {
- endpoint: 'users/flashs' as const,
+const paginator = markRaw(new Paginator('users/flashs', {
limit: 20,
- params: computed(() => ({
+ computedParams: computed(() => ({
userId: props.user.id,
})),
-};
+}));
</script>
diff --git a/packages/frontend/src/pages/user/follow-list.vue b/packages/frontend/src/pages/user/follow-list.vue
index 2c3eb40f72..6bb1360d42 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}" :pagination="type === 'following' ? followingPagination : followersPagination" withControl>
+ <MkPagination v-slot="{items}" :paginator="type === 'following' ? followingPaginator : followersPaginator" 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>
@@ -14,31 +14,30 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed } from 'vue';
+import { computed, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import MkUserInfo from '@/components/MkUserInfo.vue';
import MkPagination from '@/components/MkPagination.vue';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
user: Misskey.entities.User;
type: 'following' | 'followers';
}>();
-const followingPagination = {
- endpoint: 'users/following' as const,
+const followingPaginator = markRaw(new Paginator('users/following', {
limit: 20,
- params: computed(() => ({
+ computedParams: computed(() => ({
userId: props.user.id,
})),
-};
+}));
-const followersPagination = {
- endpoint: 'users/followers' as const,
+const followersPaginator = markRaw(new Paginator('users/followers', {
limit: 20,
- params: computed(() => ({
+ computedParams: computed(() => ({
userId: props.user.id,
})),
-};
+}));
</script>
<style lang="scss" module>
diff --git a/packages/frontend/src/pages/user/gallery.vue b/packages/frontend/src/pages/user/gallery.vue
index 12a9d2b1ab..cabba34553 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" withControl>
+ <MkPagination v-slot="{items}" :paginator="paginator" withControl>
<div :class="$style.root">
<MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/>
</div>
@@ -14,23 +14,23 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed } from 'vue';
+import { computed, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import MkGalleryPostPreview from '@/components/MkGalleryPostPreview.vue';
import MkPagination from '@/components/MkPagination.vue';
+import { Paginator } from '@/utility/paginator.js';
const props = withDefaults(defineProps<{
user: Misskey.entities.User;
}>(), {
});
-const pagination = {
- endpoint: 'users/gallery/posts' as const,
+const paginator = markRaw(new Paginator('users/gallery/posts', {
limit: 6,
- params: computed(() => ({
+ computedParams: computed(() => ({
userId: props.user.id,
})),
-};
+}));
</script>
<style lang="scss" module>
diff --git a/packages/frontend/src/pages/user/index.timeline.vue b/packages/frontend/src/pages/user/index.timeline.vue
index d8eca07a42..5e9e671252 100644
--- a/packages/frontend/src/pages/user/index.timeline.vue
+++ b/packages/frontend/src/pages/user/index.timeline.vue
@@ -13,16 +13,18 @@ SPDX-License-Identifier: AGPL-3.0-only
<option value="files">{{ i18n.ts.withFiles }}</option>
</MkTab>
</template>
- <MkNotesTimeline :key="tab" :noGap="true" :pagination="pagination" :pullToRefresh="false" :class="$style.tl"/>
+ <MkNotesTimeline v-if="tab === 'featured'" :noGap="true" :paginator="featuredPaginator" :pullToRefresh="false" :class="$style.tl"/>
+ <MkNotesTimeline v-else :noGap="true" :paginator="notesPaginator" :pullToRefresh="false" :class="$style.tl"/>
</MkStickyContainer>
</template>
<script lang="ts" setup>
-import { ref, computed } from 'vue';
+import { ref, computed, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import MkNotesTimeline from '@/components/MkNotesTimeline.vue';
import MkTab from '@/components/MkTab.vue';
import { i18n } from '@/i18n.js';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
user: Misskey.entities.UserDetailed;
@@ -30,23 +32,23 @@ const props = defineProps<{
const tab = ref<string>('all');
-const pagination = computed(() => tab.value === 'featured' ? {
- endpoint: 'users/featured-notes' as const,
+const featuredPaginator = markRaw(new Paginator('users/featured-notes', {
limit: 10,
params: {
userId: props.user.id,
},
-} : {
- endpoint: 'users/notes' as const,
+}));
+
+const notesPaginator = markRaw(new Paginator('users/notes', {
limit: 10,
- params: {
+ computedParams: computed(() => ({
userId: props.user.id,
withRenotes: tab.value === 'all',
withReplies: tab.value === 'all',
withChannelNotes: tab.value === 'all',
withFiles: tab.value === 'files',
- },
-});
+ })),
+}));
</script>
<style lang="scss" module>
diff --git a/packages/frontend/src/pages/user/lists.vue b/packages/frontend/src/pages/user/lists.vue
index 5792c8faaf..6c9204ae22 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" withControl>
+ <MkPagination v-slot="{items}" :paginator="paginator" 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"/>
@@ -19,24 +19,24 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import {} from 'vue';
+import { markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import MkPagination from '@/components/MkPagination.vue';
import MkStickyContainer from '@/components/global/MkStickyContainer.vue';
import MkAvatars from '@/components/MkAvatars.vue';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
user: Misskey.entities.UserDetailed;
}>();
-const pagination = {
- endpoint: 'users/lists/list' as const,
+const paginator = markRaw(new Paginator('users/lists/list', {
noPaging: true,
limit: 10,
params: {
userId: props.user.id,
},
-};
+}));
</script>
<style lang="scss" module>
diff --git a/packages/frontend/src/pages/user/notes.vue b/packages/frontend/src/pages/user/notes.vue
index c97177b6a5..b5e600da92 100644
--- a/packages/frontend/src/pages/user/notes.vue
+++ b/packages/frontend/src/pages/user/notes.vue
@@ -15,18 +15,20 @@ SPDX-License-Identifier: AGPL-3.0-only
<option value="files">{{ i18n.ts.withFiles }}</option>
</MkTab>
</template>
- <MkNotesTimeline :key="tab" :noGap="true" :pagination="pagination" :class="$style.tl"/>
+ <MkNotesTimeline v-if="tab === 'featured'" :noGap="true" :paginator="featuredPaginator" :class="$style.tl"/>
+ <MkNotesTimeline v-else :noGap="true" :paginator="notesPaginator" :class="$style.tl"/>
</MkStickyContainer>
</div>
</div>
</template>
<script lang="ts" setup>
-import { ref, computed } from 'vue';
+import { ref, computed, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import MkNotesTimeline from '@/components/MkNotesTimeline.vue';
import MkTab from '@/components/MkTab.vue';
import { i18n } from '@/i18n.js';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
user: Misskey.entities.UserDetailed;
@@ -34,23 +36,23 @@ const props = defineProps<{
const tab = ref<string>('all');
-const pagination = computed(() => tab.value === 'featured' ? {
- endpoint: 'users/featured-notes' as const,
+const featuredPaginator = markRaw(new Paginator('users/featured-notes', {
limit: 10,
params: {
userId: props.user.id,
},
-} : {
- endpoint: 'users/notes' as const,
+}));
+
+const notesPaginator = markRaw(new Paginator('users/notes', {
limit: 10,
- params: {
+ computedParams: computed(() => ({
userId: props.user.id,
withRenotes: tab.value === 'all',
withReplies: tab.value === 'all',
withChannelNotes: tab.value === 'all',
withFiles: tab.value === 'files',
- },
-});
+ })),
+}));
</script>
<style lang="scss" module>
diff --git a/packages/frontend/src/pages/user/pages.vue b/packages/frontend/src/pages/user/pages.vue
index 1037f66b7e..18ba1c4c50 100644
--- a/packages/frontend/src/pages/user/pages.vue
+++ b/packages/frontend/src/pages/user/pages.vue
@@ -5,27 +5,27 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="_spacer" style="--MI_SPACER-w: 700px;">
- <MkPagination v-slot="{items}" :pagination="pagination" withControl>
+ <MkPagination v-slot="{items}" :paginator="paginator" withControl>
<MkPagePreview v-for="page in items" :key="page.id" :page="page" class="_margin"/>
</MkPagination>
</div>
</template>
<script lang="ts" setup>
-import { computed } from 'vue';
+import { computed, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import MkPagePreview from '@/components/MkPagePreview.vue';
import MkPagination from '@/components/MkPagination.vue';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
user: Misskey.entities.User;
}>();
-const pagination = {
- endpoint: 'users/pages' as const,
+const paginator = markRaw(new Paginator('users/pages', {
limit: 20,
- params: computed(() => ({
+ computedParams: computed(() => ({
userId: props.user.id,
})),
-};
+}));
</script>
diff --git a/packages/frontend/src/pages/user/reactions.vue b/packages/frontend/src/pages/user/reactions.vue
index 28efd1a474..a59de32eab 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}" :pagination="pagination">
+ <MkPagination v-slot="{items}" :paginator="paginator">
<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"/>
@@ -19,23 +19,23 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed } from 'vue';
+import { computed, markRaw } from 'vue';
import * as Misskey from 'misskey-js';
import MkPagination from '@/components/MkPagination.vue';
import MkNote from '@/components/MkNote.vue';
import MkReactionIcon from '@/components/MkReactionIcon.vue';
+import { Paginator } from '@/utility/paginator.js';
const props = defineProps<{
user: Misskey.entities.User;
}>();
-const pagination = {
- endpoint: 'users/reactions' as const,
+const paginator = markRaw(new Paginator('users/reactions', {
limit: 20,
- params: computed(() => ({
+ computedParams: computed(() => ({
userId: props.user.id,
})),
-};
+}));
</script>
<style lang="scss" module>