Files
shopdb-flask/frontend/src/components/PaginationBar.vue

97 lines
2.4 KiB
Vue

<template>
<div class="pagination-bar" v-if="totalPages > 1 || showPerPage">
<div class="pagination-info">
<select
v-if="showPerPage"
:value="perPage"
class="perpage-select"
@change="$emit('update:perPage', Number($event.target.value))"
>
<option v-for="opt in perPageOptions" :key="opt" :value="opt">
{{ opt }} per page
</option>
</select>
</div>
<div class="pagination" v-if="totalPages > 1">
<button :disabled="page === 1" @click="$emit('update:page', page - 1)">
Prev
</button>
<button
v-for="p in visiblePages"
:key="p"
:class="{ active: p === page, ellipsis: p === '...' }"
:disabled="p === '...'"
@click="p !== '...' && $emit('update:page', p)"
>
{{ p }}
</button>
<button :disabled="page === totalPages" @click="$emit('update:page', page + 1)">
Next
</button>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
page: { type: Number, required: true },
totalPages: { type: Number, required: true },
perPage: { type: Number, default: 20 },
showPerPage: { type: Boolean, default: true }
})
defineEmits(['update:page', 'update:perPage'])
// A page size the caller actually uses must be selectable, or the control renders
// blank: NetworkDevicesList defaults to 25, which was in no option, so
// :value="25" matched nothing and the box showed empty - the operator could not
// see the current page size at all. Any size the component is handed is folded
// in rather than silently dropped.
const BASE_PER_PAGE_OPTIONS = [10, 20, 50, 100]
const perPageOptions = computed(() => {
const current = Number(props.perPage)
if (!current || BASE_PER_PAGE_OPTIONS.includes(current)) {
return BASE_PER_PAGE_OPTIONS
}
return [...BASE_PER_PAGE_OPTIONS, current].sort((a, b) => a - b)
})
const visiblePages = computed(() => {
const total = props.totalPages
const current = props.page
const pages = []
if (total <= 7) {
for (let i = 1; i <= total; i++) pages.push(i)
return pages
}
pages.push(1)
if (current > 3) {
pages.push('...')
}
const start = Math.max(2, current - 1)
const end = Math.min(total - 1, current + 1)
for (let i = start; i <= end; i++) {
pages.push(i)
}
if (current < total - 2) {
pages.push('...')
}
pages.push(total)
return pages
})
</script>