refactor: pagination component

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/628/head
Ryan Wang 2022-09-29 12:47:03 +08:00
parent c4056c5b72
commit 668c678714
8 changed files with 96 additions and 66 deletions

View File

@ -2,8 +2,8 @@
<Story :init-state="initState" title="Pagination">
<template #default="{ state }">
<VPagination
:page="state.page"
:size="state.size"
v-model:page="state.page"
v-model:size="state.size"
:total="state.total"
></VPagination>
</template>

View File

@ -1,24 +1,32 @@
<script lang="ts" setup>
import { UseOffsetPagination } from "@vueuse/components";
import { IconArrowLeft, IconArrowRight } from "../../icons/icons";
import { ref, toRefs, watch } from "vue";
import { ref, toRefs, watch, watchEffect } from "vue";
import { useOffsetPagination } from "@vueuse/core";
const props = withDefaults(
defineProps<{
page?: number;
size?: number;
total?: number;
sizeOptions?: number[];
}>(),
{
page: 1,
size: 10,
total: 0,
sizeOptions: () => [10],
}
);
const { page, size, total } = toRefs(props);
const page = ref(props.page);
const size = ref(props.size);
const total = ref(props.total);
const key = ref(Math.random());
watch([() => props.page, () => props.size, () => props.total], () => {
page.value = props.page;
size.value = props.size;
total.value = props.total;
});
const emit = defineEmits<{
(event: "update:page", page: number): void;
@ -33,81 +41,97 @@ const onPageChange = ({
currentPage: number;
currentPageSize: number;
}) => {
emit("update:page", currentPage);
emit("update:size", currentPageSize);
emit("change", {
page: currentPage,
size: currentPageSize,
});
};
watch(
() => total?.value,
() => {
key.value = Math.random();
}
);
const {
currentPage,
currentPageSize,
pageCount,
isFirstPage,
isLastPage,
prev,
next,
} = useOffsetPagination({
total: total,
page: page,
pageSize: size,
onPageChange: onPageChange,
onPageSizeChange: onPageChange,
});
</script>
<template>
<UseOffsetPagination
:key="key"
v-slot="{ currentPage, next, prev, pageCount }"
:page="page"
:page-size="size"
:total="total"
@page-change="onPageChange"
@page-size-change="onPageChange"
>
<div class="bg-white flex items-center justify-between">
<div class="flex-1 flex justify-between sm:!hidden items-center">
<span
class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 cursor-pointer"
<div class="bg-white flex items-center justify-between">
<div class="flex-1 flex justify-between sm:!hidden items-center">
<span
class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 cursor-pointer"
@click="prev"
>
<IconArrowLeft />
</span>
<span class="text-sm text-gray-500">
{{ currentPage }} / {{ pageCount }}
</span>
<span
class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 cursor-pointer"
@click="next"
>
<IconArrowRight />
</span>
</div>
<div class="hidden sm:flex-1 sm:flex sm:items-center items-center gap-2">
<nav
aria-label="Pagination"
class="relative z-0 inline-flex rounded-base shadow-sm -space-x-px"
>
<button
class="relative h-8 outline-none inline-flex items-center px-2 py-1.5 rounded-l-base border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer disabled:cursor-not-allowed"
:disabled="isFirstPage"
@click="prev"
>
<IconArrowLeft />
</span>
<span class="text-sm text-gray-500">
{{ currentPage }} / {{ pageCount }}
</span>
<span
class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 cursor-pointer"
</button>
<button
class="relative h-8 outline-none inline-flex items-center px-2 py-1.5 rounded-r-base border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer disabled:cursor-not-allowed"
:disabled="isLastPage"
@click="next"
>
<IconArrowRight />
</span>
</div>
<div class="hidden sm:flex-1 sm:flex sm:items-center">
<nav
aria-label="Pagination"
class="relative z-0 inline-flex rounded-base shadow-sm -space-x-px"
</button>
</nav>
<div class="inline-flex items-center gap-2">
<select
v-model="currentPage"
:disabled="pageCount === 0"
class="h-8 border outline-none rounded-base px-2 text-gray-800 text-sm border-gray-300"
>
<span
class="relative inline-flex items-center px-2 py-2 rounded-l-[4px] border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer"
@click="prev"
<option v-if="pageCount === 0" :value="0">0 / 0</option>
<option v-for="i in pageCount" :key="i" :value="i">
{{ i }} / {{ pageCount }}
</option>
</select>
<span class="text-sm text-gray-500"></span>
</div>
<div class="inline-flex items-center gap-2">
<select
v-model="currentPageSize"
class="h-8 border outline-none rounded-base px-2 text-gray-800 text-sm border-gray-300"
>
<option
v-for="(sizeOption, index) in sizeOptions"
:key="index"
:value="sizeOption"
>
<IconArrowLeft />
</span>
<span
v-for="i in pageCount"
:key="i"
:class="{
'z-10 bg-primary/1 border-primary text-primary':
i === currentPage,
'bg-white border-gray-300 text-gray-500 hover:bg-gray-50':
i !== currentPage,
}"
aria-current="page"
class="relative inline-flex items-center px-4 py-2 border text-sm font-medium cursor-pointer select-none"
@click="currentPage.value = i"
>
{{ i }}
</span>
<span
class="relative inline-flex items-center px-2 py-2 rounded-r-[4px] border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer"
@click="next"
>
<IconArrowRight />
</span>
</nav>
{{ sizeOption }}
</option>
</select>
<span class="text-sm text-gray-500"> / </span>
</div>
</div>
</UseOffsetPagination>
</div>
</template>

View File

@ -690,6 +690,7 @@ onMounted(() => {
:page="attachments.page"
:size="attachments.size"
:total="attachments.total"
:size-options="[60, 120, 200]"
@change="handlePaginationChange"
/>
</div>

View File

@ -165,6 +165,7 @@ await handleFetchAttachments();
:page="attachments.page"
:size="attachments.size"
:total="attachments.total"
:size-options="[60, 120, 200]"
@change="handlePaginationChange"
/>
</div>

View File

@ -428,6 +428,7 @@ function handleSelectUser(user: User | undefined) {
:page="comments.page"
:size="comments.size"
:total="comments.total"
:size-options="[20, 30, 50, 100]"
@change="handlePaginationChange"
/>
</div>

View File

@ -638,6 +638,7 @@ function handleSortItemChange(sortItem?: SortItem) {
:page="singlePages.page"
:size="singlePages.size"
:total="singlePages.total"
:size-options="[20, 30, 50, 100]"
@change="handlePaginationChange"
/>
</div>

View File

@ -928,6 +928,7 @@ function handleContributorChange(user?: User) {
:page="posts.page"
:size="posts.size"
:total="posts.total"
:size-options="[20, 30, 50, 100]"
@change="handlePaginationChange"
/>
</div>

View File

@ -36,7 +36,7 @@ const grantPermissionModal = ref<boolean>(false);
const users = ref<UserList>({
page: 1,
size: 10,
size: 20,
total: 0,
items: [],
first: true,
@ -486,6 +486,7 @@ onMounted(() => {
:page="users.page"
:size="users.size"
:total="users.total"
:size-options="[20, 30, 50, 100]"
@change="handlePaginationChange"
/>
</div>