feat: add infinite scroll pagination
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
"@tanstack/vue-query": "^5.92.9",
|
||||
"@toycode/markdown-it-class": "^1.2.4",
|
||||
"@vscode/markdown-it-katex": "^1.1.2",
|
||||
"@vueuse/components": "^14.2.1",
|
||||
"@vueuse/core": "^13.6.0",
|
||||
"@vueuse/router": "^13.6.0",
|
||||
"date-fns": "^4.1.0",
|
||||
@@ -69,7 +70,7 @@
|
||||
"autoprefixer": "^10.4.24",
|
||||
"daisyui": "^5.5.18",
|
||||
"dotenv": "^17.2.3",
|
||||
"eslint": "^.57.1",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier-vue": "^5.0.0",
|
||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||
|
||||
40
pnpm-lock.yaml
generated
40
pnpm-lock.yaml
generated
@@ -29,6 +29,9 @@ importers:
|
||||
'@vscode/markdown-it-katex':
|
||||
specifier: ^1.1.2
|
||||
version: 1.1.2
|
||||
'@vueuse/components':
|
||||
specifier: ^14.2.1
|
||||
version: 14.2.1(vue@3.5.18(typescript@5.9.3))
|
||||
'@vueuse/core':
|
||||
specifier: ^13.6.0
|
||||
version: 13.6.0(vue@3.5.18(typescript@5.9.3))
|
||||
@@ -2072,14 +2075,27 @@ packages:
|
||||
'@vue/shared@3.5.28':
|
||||
resolution: {integrity: sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==}
|
||||
|
||||
'@vueuse/components@14.2.1':
|
||||
resolution: {integrity: sha512-wB0SvwJ22mNm1hWCMI1wTWz4x55nDTugT5RIg/KCwlWc1vITWL6ry5VTU3SQzsMD2XcazJK8Be1siIsrBb/Vcw==}
|
||||
peerDependencies:
|
||||
vue: ^3.5.0
|
||||
|
||||
'@vueuse/core@13.6.0':
|
||||
resolution: {integrity: sha512-DJbD5fV86muVmBgS9QQPddVX7d9hWYswzlf4bIyUD2dj8GC46R1uNClZhVAmsdVts4xb2jwp1PbpuiA50Qee1A==}
|
||||
peerDependencies:
|
||||
vue: ^3.5.0
|
||||
|
||||
'@vueuse/core@14.2.1':
|
||||
resolution: {integrity: sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==}
|
||||
peerDependencies:
|
||||
vue: ^3.5.0
|
||||
|
||||
'@vueuse/metadata@13.6.0':
|
||||
resolution: {integrity: sha512-rnIH7JvU7NjrpexTsl2Iwv0V0yAx9cw7+clymjKuLSXG0QMcLD0LDgdNmXic+qL0SGvgSVPEpM9IDO/wqo1vkQ==}
|
||||
|
||||
'@vueuse/metadata@14.2.1':
|
||||
resolution: {integrity: sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw==}
|
||||
|
||||
'@vueuse/router@13.6.0':
|
||||
resolution: {integrity: sha512-iXRwR4K7nz4PReW0QudhnM9NtYGvN4KrskFgF9G7NouM43big3bpSNRRocJKFWK7iu97ww5y82B3QA2zz3S/vw==}
|
||||
peerDependencies:
|
||||
@@ -2091,6 +2107,11 @@ packages:
|
||||
peerDependencies:
|
||||
vue: ^3.5.0
|
||||
|
||||
'@vueuse/shared@14.2.1':
|
||||
resolution: {integrity: sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==}
|
||||
peerDependencies:
|
||||
vue: ^3.5.0
|
||||
|
||||
abab@1.0.4:
|
||||
resolution: {integrity: sha512-I+Wi+qiE2kUXyrRhNsWv6XsjUTBJjSoVSctKNBfLG5zG/Xe7Rjbxf13+vqYHNTwHaFU+FtSlVxOCTiMEVtPv0A==}
|
||||
deprecated: Use your platform's native atob() and btoa() methods instead
|
||||
@@ -8099,6 +8120,12 @@ snapshots:
|
||||
|
||||
'@vue/shared@3.5.28': {}
|
||||
|
||||
'@vueuse/components@14.2.1(vue@3.5.18(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@vueuse/core': 14.2.1(vue@3.5.18(typescript@5.9.3))
|
||||
'@vueuse/shared': 14.2.1(vue@3.5.18(typescript@5.9.3))
|
||||
vue: 3.5.18(typescript@5.9.3)
|
||||
|
||||
'@vueuse/core@13.6.0(vue@3.5.18(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@types/web-bluetooth': 0.0.21
|
||||
@@ -8106,8 +8133,17 @@ snapshots:
|
||||
'@vueuse/shared': 13.6.0(vue@3.5.18(typescript@5.9.3))
|
||||
vue: 3.5.18(typescript@5.9.3)
|
||||
|
||||
'@vueuse/core@14.2.1(vue@3.5.18(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@types/web-bluetooth': 0.0.21
|
||||
'@vueuse/metadata': 14.2.1
|
||||
'@vueuse/shared': 14.2.1(vue@3.5.18(typescript@5.9.3))
|
||||
vue: 3.5.18(typescript@5.9.3)
|
||||
|
||||
'@vueuse/metadata@13.6.0': {}
|
||||
|
||||
'@vueuse/metadata@14.2.1': {}
|
||||
|
||||
'@vueuse/router@13.6.0(vue-router@4.5.1(vue@3.5.18(typescript@5.9.3)))(vue@3.5.18(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@vueuse/shared': 13.6.0(vue@3.5.18(typescript@5.9.3))
|
||||
@@ -8118,6 +8154,10 @@ snapshots:
|
||||
dependencies:
|
||||
vue: 3.5.18(typescript@5.9.3)
|
||||
|
||||
'@vueuse/shared@14.2.1(vue@3.5.18(typescript@5.9.3))':
|
||||
dependencies:
|
||||
vue: 3.5.18(typescript@5.9.3)
|
||||
|
||||
abab@1.0.4: {}
|
||||
|
||||
acorn-globals@3.1.0:
|
||||
|
||||
@@ -2,24 +2,39 @@
|
||||
import BackButton from "@/components/BackButton.vue"
|
||||
import { Author, getAka } from "@/modules/atproto/getAka"
|
||||
import { PublicNoteListItem } from "@/modules/note/models/Note"
|
||||
import { computedAsync, useAsyncState } from "@vueuse/core"
|
||||
import { computedAsync } from "@vueuse/core"
|
||||
import { computed, ref } from "vue"
|
||||
import { vInfiniteScroll } from "@vueuse/components"
|
||||
|
||||
const { state, isLoading } = useAsyncState<{
|
||||
notes: PublicNoteListItem[]
|
||||
}>(
|
||||
async () => {
|
||||
const response = await fetch("https://api.litenote.li212.fr/notes")
|
||||
return response.json()
|
||||
},
|
||||
{ notes: [] },
|
||||
)
|
||||
const isLoading = ref(false)
|
||||
const notes = ref<PublicNoteListItem[]>([])
|
||||
const cursor = ref<string | null | undefined>(null)
|
||||
const canLoadMore = computed(() => cursor.value !== undefined)
|
||||
|
||||
const onLoadMore = async () => {
|
||||
isLoading.value = true
|
||||
const noteAPI = new URL("/notes", "https://api.litenote.li212.fr")
|
||||
|
||||
if (cursor.value) {
|
||||
noteAPI.searchParams.set("cursor", cursor.value)
|
||||
}
|
||||
|
||||
const response = await fetch(noteAPI)
|
||||
|
||||
const data: { notes: PublicNoteListItem[]; cursor: string | undefined } =
|
||||
await response.json()
|
||||
|
||||
notes.value.push(...data.notes)
|
||||
cursor.value = data.cursor
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
const aka = computedAsync<Map<string, Author>>(async () => {
|
||||
if (state.value.notes.length === 0) {
|
||||
if (notes.value.length === 0) {
|
||||
return new Map()
|
||||
}
|
||||
|
||||
return getAka(new Set(state.value.notes.map((n) => n.did)))
|
||||
return getAka(new Set(notes.value.map((n) => n.did)))
|
||||
}, new Map())
|
||||
|
||||
const getAlias = (did: string) =>
|
||||
@@ -31,8 +46,11 @@ const getAlias = (did: string) =>
|
||||
<h1>Remanso notes</h1>
|
||||
<div v-if="isLoading"></div>
|
||||
<div v-else>
|
||||
<ul class="list rounded-box shadow-sm">
|
||||
<li v-for="note in state.notes" class="list-row">
|
||||
<ul
|
||||
class="list rounded-box shadow-sm"
|
||||
v-infinite-scroll="[onLoadMore, { canLoadMore: () => canLoadMore }]"
|
||||
>
|
||||
<li v-for="note in notes" class="list-row">
|
||||
<div class="list-col">
|
||||
<router-link
|
||||
:to="{
|
||||
|
||||
Reference in New Issue
Block a user