This commit is contained in:
syuilo 2025-05-03 19:58:19 +09:00
parent 6ca9cfb24d
commit 74cc831332
6 changed files with 71 additions and 69 deletions

View File

@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
<template #default="{ items: notes }"> <template #default="{ items: notes }">
<div :class="[$style.root, { [$style.noGap]: noGap, '_gaps': !noGap, [$style.reverse]: pagination.reversed }]"> <div :class="[$style.root, { [$style.noGap]: noGap, '_gaps': !noGap }]">
<template v-for="(note, i) in notes" :key="note.id"> <template v-for="(note, i) in notes" :key="note.id">
<div v-if="note._shouldInsertAd_" :class="[$style.noteWithAd, { '_gaps': !noGap }]" :data-scroll-anchor="note.id"> <div v-if="note._shouldInsertAd_" :class="[$style.noteWithAd, { '_gaps': !noGap }]" :data-scroll-anchor="note.id">
<MkNote :class="$style.note" :note="note" :withHardMute="true"/> <MkNote :class="$style.note" :note="note" :withHardMute="true"/>
@ -62,11 +62,6 @@ defineExpose({
</script> </script>
<style lang="scss" module> <style lang="scss" module>
.reverse {
display: flex;
flex-direction: column-reverse;
}
.root { .root {
container-type: inline-size; container-type: inline-size;

View File

@ -27,15 +27,15 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div v-else ref="rootEl" class="_gaps"> <div v-else ref="rootEl" class="_gaps">
<div v-show="pagination.reversed && paginator.canFetchMore.value" key="_more_"> <div v-show="pagination.reversed && paginator.canFetchOlder.value" key="_more_">
<MkButton v-if="!paginator.moreFetching.value" v-appear="(prefer.s.enableInfiniteScroll && !props.disableAutoLoad) ? appearFetchMoreAhead : null" :class="$style.more" :wait="paginator.moreFetching.value" primary rounded @click="paginator.fetchNewer"> <MkButton v-if="!paginator.fetchingOlder.value" v-appear="(prefer.s.enableInfiniteScroll && !props.disableAutoLoad) ? appearFetchMoreAhead : null" :class="$style.more" :wait="paginator.fetchingOlder.value" primary rounded @click="paginator.fetchNewer">
{{ i18n.ts.loadMore }} {{ i18n.ts.loadMore }}
</MkButton> </MkButton>
<MkLoading v-else/> <MkLoading v-else/>
</div> </div>
<slot :items="paginator.items.value" :fetching="paginator.fetching.value || paginator.moreFetching.value"></slot> <slot :items="paginator.items.value" :fetching="paginator.fetching.value || paginator.fetchingOlder.value"></slot>
<div v-show="!pagination.reversed && paginator.canFetchMore.value" key="_more_"> <div v-show="!pagination.reversed && paginator.canFetchOlder.value" key="_more_">
<MkButton v-if="!paginator.moreFetching.value" v-appear="(prefer.s.enableInfiniteScroll && !props.disableAutoLoad) ? appearFetchMore : null" :class="$style.more" :wait="paginator.moreFetching.value" primary rounded @click="paginator.fetchOlder"> <MkButton v-if="!paginator.fetchingOlder.value" v-appear="(prefer.s.enableInfiniteScroll && !props.disableAutoLoad) ? appearFetchMore : null" :class="$style.more" :wait="paginator.fetchingOlder.value" primary rounded @click="paginator.fetchOlder">
{{ i18n.ts.loadMore }} {{ i18n.ts.loadMore }}
</MkButton> </MkButton>
<MkLoading v-else/> <MkLoading v-else/>

View File

@ -44,8 +44,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkNote v-else :class="$style.note" :note="note" :withHardMute="true" :data-scroll-anchor="note.id"/> <MkNote v-else :class="$style.note" :note="note" :withHardMute="true" :data-scroll-anchor="note.id"/>
</template> </template>
</component> </component>
<button v-show="paginator.canFetchMore.value" key="_more_" v-appear="prefer.s.enableInfiniteScroll ? paginator.fetchOlder : null" :disabled="paginator.moreFetching.value" class="_button" :class="$style.more" @click="paginator.fetchOlder"> <button v-show="paginator.canFetchOlder.value" key="_more_" v-appear="prefer.s.enableInfiniteScroll ? paginator.fetchOlder : null" :disabled="paginator.fetchingOlder.value" class="_button" :class="$style.more" @click="paginator.fetchOlder">
<div v-if="!paginator.moreFetching.value">{{ i18n.ts.loadMore }}</div> <div v-if="!paginator.fetchingOlder.value">{{ i18n.ts.loadMore }}</div>
<MkLoading v-else :inline="true"/> <MkLoading v-else :inline="true"/>
</button> </button>
</div> </div>

View File

@ -33,8 +33,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<XNotification v-else :class="$style.item" :notification="notification" :withTime="true" :full="true" :data-scroll-anchor="notification.id"/> <XNotification v-else :class="$style.item" :notification="notification" :withTime="true" :full="true" :data-scroll-anchor="notification.id"/>
</template> </template>
</component> </component>
<button v-show="paginator.canFetchMore.value" key="_more_" v-appear="prefer.s.enableInfiniteScroll ? paginator.fetchOlder : null" :disabled="paginator.moreFetching.value" class="_button" :class="$style.more" @click="paginator.fetchOlder"> <button v-show="paginator.canFetchOlder.value" key="_more_" v-appear="prefer.s.enableInfiniteScroll ? paginator.fetchOlder : null" :disabled="paginator.fetchingOlder.value" class="_button" :class="$style.more" @click="paginator.fetchOlder">
<div v-if="!paginator.moreFetching.value">{{ i18n.ts.loadMore }}</div> <div v-if="!paginator.fetchingOlder.value">{{ i18n.ts.loadMore }}</div>
<MkLoading v-else/> <MkLoading v-else/>
</button> </button>
</div> </div>

View File

@ -6,7 +6,6 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<PageWithHeader :actions="headerActions" :tabs="headerTabs"> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<div class="_spacer" style="--MI_SPACER-w: 800px;"> <div class="_spacer" style="--MI_SPACER-w: 800px;">
<div>
<Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in"> <Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in">
<div v-if="note"> <div v-if="note">
<div v-if="showNext" class="_margin"> <div v-if="showNext" class="_margin">
@ -42,7 +41,6 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkLoading v-else/> <MkLoading v-else/>
</Transition> </Transition>
</div> </div>
</div>
</PageWithHeader> </PageWithHeader>
</template> </template>
@ -83,19 +81,20 @@ const error = ref();
const prevUserPagination: PagingCtx = { const prevUserPagination: PagingCtx = {
endpoint: 'users/notes', endpoint: 'users/notes',
limit: 10, limit: 10,
baseId: props.noteId,
direction: 'older',
params: computed(() => note.value ? ({ params: computed(() => note.value ? ({
userId: note.value.userId, userId: note.value.userId,
untilId: note.value.id,
}) : undefined), }) : undefined),
}; };
const nextUserPagination: PagingCtx = { const nextUserPagination: PagingCtx = {
reversed: true,
endpoint: 'users/notes', endpoint: 'users/notes',
limit: 10, limit: 10,
baseId: props.noteId,
direction: 'newer',
params: computed(() => note.value ? ({ params: computed(() => note.value ? ({
userId: note.value.userId, userId: note.value.userId,
sinceId: note.value.id,
}) : undefined), }) : undefined),
}; };

View File

@ -31,12 +31,10 @@ export type PagingCtx<E extends keyof Misskey.Endpoints = keyof Misskey.Endpoint
*/ */
noPaging?: boolean; noPaging?: boolean;
/**
* items ()
*/
reversed?: boolean;
offsetMode?: boolean; offsetMode?: boolean;
baseId?: MisskeyEntity['id'];
direction?: 'newer' | 'older';
}; };
export function usePagination<T extends MisskeyEntity>(props: { export function usePagination<T extends MisskeyEntity>(props: {
@ -47,8 +45,8 @@ export function usePagination<T extends MisskeyEntity>(props: {
let aheadQueue: T[] = []; let aheadQueue: T[] = [];
const queuedAheadItemsCount = ref(0); const queuedAheadItemsCount = ref(0);
const fetching = ref(true); const fetching = ref(true);
const moreFetching = ref(false); const fetchingOlder = ref(false);
const canFetchMore = ref(false); const canFetchOlder = ref(false);
const error = ref(false); const error = ref(false);
// パラメータに何らかの変更があった際、再読込したいチャンネル等のIDが変わったなど // パラメータに何らかの変更があった際、再読込したいチャンネル等のIDが変わったなど
@ -73,11 +71,22 @@ export function usePagination<T extends MisskeyEntity>(props: {
queuedAheadItemsCount.value = 0; queuedAheadItemsCount.value = 0;
fetching.value = true; fetching.value = true;
const params = props.ctx.params ? isRef(props.ctx.params) ? props.ctx.params.value : props.ctx.params : {}; const params = props.ctx.params ? isRef(props.ctx.params) ? props.ctx.params.value : props.ctx.params : {};
await misskeyApi<T[]>(props.ctx.endpoint, { await misskeyApi<T[]>(props.ctx.endpoint, {
...params, ...params,
limit: props.ctx.limit ?? FIRST_FETCH_LIMIT, limit: props.ctx.limit ?? FIRST_FETCH_LIMIT,
allowPartial: true, allowPartial: true,
...(props.ctx.baseId && props.ctx.direction === 'newer' ? {
sinceId: props.ctx.baseId,
} : props.ctx.baseId && props.ctx.direction === 'older' ? {
untilId: props.ctx.baseId,
} : {}),
}).then(res => { }).then(res => {
// 逆順で返ってくるので
if (props.ctx.baseId && props.ctx.direction === 'newer') {
res.reverse();
}
for (let i = 0; i < res.length; i++) { for (let i = 0; i < res.length; i++) {
const item = res[i]; const item = res[i];
if (i === 3) item._shouldInsertAd_ = true; if (i === 3) item._shouldInsertAd_ = true;
@ -85,11 +94,10 @@ export function usePagination<T extends MisskeyEntity>(props: {
if (res.length === 0 || props.ctx.noPaging) { if (res.length === 0 || props.ctx.noPaging) {
pushItems(res); pushItems(res);
canFetchMore.value = false; canFetchOlder.value = false;
} else { } else {
if (props.ctx.reversed) moreFetching.value = true;
pushItems(res); pushItems(res);
canFetchMore.value = true; canFetchOlder.value = true;
} }
error.value = false; error.value = false;
@ -105,8 +113,8 @@ export function usePagination<T extends MisskeyEntity>(props: {
} }
async function fetchOlder(): Promise<void> { async function fetchOlder(): Promise<void> {
if (!canFetchMore.value || fetching.value || moreFetching.value || items.value.length === 0) return; if (!canFetchOlder.value || fetching.value || fetchingOlder.value || items.value.length === 0) return;
moreFetching.value = true; fetchingOlder.value = true;
const params = props.ctx.params ? isRef(props.ctx.params) ? props.ctx.params.value : props.ctx.params : {}; const params = props.ctx.params ? isRef(props.ctx.params) ? props.ctx.params.value : props.ctx.params : {};
await misskeyApi<T[]>(props.ctx.endpoint, { await misskeyApi<T[]>(props.ctx.endpoint, {
...params, ...params,
@ -123,16 +131,16 @@ export function usePagination<T extends MisskeyEntity>(props: {
} }
if (res.length === 0) { if (res.length === 0) {
canFetchMore.value = false; canFetchOlder.value = false;
moreFetching.value = false; fetchingOlder.value = false;
} else { } else {
items.value.push(...res); items.value.push(...res);
if (props.useShallowRef) triggerRef(items); if (props.useShallowRef) triggerRef(items);
canFetchMore.value = true; canFetchOlder.value = true;
moreFetching.value = false; fetchingOlder.value = false;
} }
}, err => { }, err => {
moreFetching.value = false; fetchingOlder.value = false;
}); });
} }
@ -163,7 +171,7 @@ export function usePagination<T extends MisskeyEntity>(props: {
} }
function trim() { function trim() {
if (items.value.length >= MAX_ITEMS) canFetchMore.value = true; if (items.value.length >= MAX_ITEMS) canFetchOlder.value = true;
items.value = items.value.slice(0, MAX_ITEMS); items.value = items.value.slice(0, MAX_ITEMS);
} }
@ -225,8 +233,8 @@ export function usePagination<T extends MisskeyEntity>(props: {
items, items,
queuedAheadItemsCount, queuedAheadItemsCount,
fetching, fetching,
moreFetching, fetchingOlder,
canFetchMore, canFetchOlder,
init, init,
reload, reload,
fetchOlder, fetchOlder,