Sink/components/dashboard/links/Index.vue

131 lines
3.3 KiB
Vue

<script setup>
import { useInfiniteScroll } from '@vueuse/core'
import { Loader } from 'lucide-vue-next'
const links = ref([])
const limit = 24
let cursor = ''
let listComplete = false
let listError = false
const sortBy = ref('created_desc') // created_desc, created_asc, alpha_asc, alpha_desc
async function getLinks() {
try {
const data = await useAPI('/api/link/list', {
query: {
limit,
cursor,
sort: sortBy.value,
},
})
links.value = links.value.concat(data.links).filter(Boolean) // Sometimes cloudflare will return null, filter out
cursor = data.cursor
listComplete = data.list_complete
listError = false
}
catch (error) {
console.error(error)
listError = true
}
}
const { isLoading } = useInfiniteScroll(
document,
getLinks,
{
distance: 150,
interval: 1000,
canLoadMore: () => {
return !listError && !listComplete
},
},
)
function updateLinkList(link, type) {
if (type === 'edit') {
const index = links.value.findIndex(l => l.id === link.id)
links.value[index] = link
}
else if (type === 'delete') {
const index = links.value.findIndex(l => l.id === link.id)
links.value.splice(index, 1)
}
else {
links.value.unshift(link)
}
}
</script>
<template>
<main class="space-y-6">
<div class="flex flex-col gap-6 sm:gap-2 sm:flex-row sm:justify-between">
<DashboardNav class="flex-1">
<DashboardLinksEditor @update:link="updateLinkList" />
</DashboardNav>
<LazyDashboardLinksSearch />
</div>
<div class="flex gap-2 items-center">
<Button
variant="outline"
size="sm"
:class="{ 'bg-primary text-primary-foreground': sortBy === 'created_desc' }"
@click="sortBy = 'created_desc'; links = []; cursor = ''; getLinks()"
>
Newest First
</Button>
<Button
variant="outline"
size="sm"
:class="{ 'bg-primary text-primary-foreground': sortBy === 'created_asc' }"
@click="sortBy = 'created_asc'; links = []; cursor = ''; getLinks()"
>
Oldest First
</Button>
<Button
variant="outline"
size="sm"
:class="{ 'bg-primary text-primary-foreground': sortBy === 'alpha_asc' }"
@click="sortBy = 'alpha_asc'; links = []; cursor = ''; getLinks()"
>
A to Z
</Button>
<Button
variant="outline"
size="sm"
:class="{ 'bg-primary text-primary-foreground': sortBy === 'alpha_desc' }"
@click="sortBy = 'alpha_desc'; links = []; cursor = ''; getLinks()"
>
Z to A
</Button>
</div>
<section class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
<DashboardLinksLink
v-for="link in links"
:key="link.id"
:link="link"
@update:link="updateLinkList"
/>
</section>
<div
v-if="isLoading"
class="flex items-center justify-center"
>
<Loader class="animate-spin" />
</div>
<div
v-if="!isLoading && listComplete"
class="flex items-center justify-center text-sm"
>
No more links
</div>
<div
v-if="listError"
class="flex items-center justify-center text-sm"
>
Loading links failed,
<Button variant="link" @click="getLinks">
Try again
</Button>
</div>
</main>
</template>