mirror of
https://github.com/zyycn/codex-proxy-rs.git
synced 2026-11-06 08:06:19 +00:00
fix(frontend): prevent pagination overflow on narrow screens
Adapt visible page buttons to the pagination container width while preserving the existing button styles. Hide the total count on narrow containers and keep the page-size selector on the left with navigation on the right. Retain the total count and full pager on wider layouts. Validation: browser layout checks across 320–1280px widths and up to 1380 pages, pagination interactions and disabled states, frontend typecheck, targeted ESLint, and diff whitespace checks passed. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { BaseTablePagination } from './pagination'
|
||||
import type { BaseTablePagination, PagerItem } from './pagination'
|
||||
import { ChevronLeft, ChevronRight } from '@lucide/vue'
|
||||
|
||||
import { computed } from 'vue'
|
||||
@@ -26,6 +26,29 @@ const totalPages = computed(() => getTotalPages(props.pagination))
|
||||
const currentPage = computed(() => getCurrentPage(props.pagination, totalPages.value))
|
||||
const pageSizeOptions = computed(() => getPageSizeOptions(props.pagination))
|
||||
const pagerItems = computed(() => getPagerItems(totalPages.value, currentPage.value))
|
||||
const adjacentPagerItems = computed(() => {
|
||||
const count = Math.min(3, totalPages.value)
|
||||
const start = Math.max(1, Math.min(currentPage.value - 1, totalPages.value - count + 1))
|
||||
return Array.from({ length: count }, (_, index) => start + index)
|
||||
})
|
||||
const compactPagerItems = computed<PagerItem[]>(() => {
|
||||
const total = totalPages.value
|
||||
const current = currentPage.value
|
||||
if (total <= 5)
|
||||
return Array.from({ length: total }, (_, index) => index + 1)
|
||||
if (current <= 3)
|
||||
return [1, 2, 3, 'ellipsis', total]
|
||||
if (current >= total - 2)
|
||||
return [1, 'ellipsis', total - 2, total - 1, total]
|
||||
return [1, 'ellipsis', current, 'ellipsis', total]
|
||||
})
|
||||
|
||||
const pagerVisibilityClasses = [
|
||||
'flex @min-[19.5rem]/pagination:hidden',
|
||||
'hidden @min-[19.5rem]/pagination:flex @min-[24.5rem]/pagination:hidden',
|
||||
'hidden @min-[24.5rem]/pagination:flex @min-[29.5rem]/pagination:hidden',
|
||||
'hidden @min-[29.5rem]/pagination:flex',
|
||||
]
|
||||
|
||||
const pageSizeModel = computed({
|
||||
get: () => String(props.pagination.pageSize),
|
||||
@@ -61,25 +84,25 @@ function paginationPageClass(page: number) {
|
||||
|
||||
<template>
|
||||
<footer
|
||||
class="mt-2 flex min-h-10 shrink-0 flex-wrap items-center justify-between gap-3 px-0 py-1"
|
||||
class="@container/pagination mt-2 min-h-10 min-w-0 shrink-0 px-0 py-1"
|
||||
>
|
||||
<div
|
||||
class="flex min-w-0 items-center gap-2.5 text-cp-sm font-emphasis text-cp-text-secondary"
|
||||
>
|
||||
<span class="whitespace-nowrap">共 {{ pagination.total }} 条</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="grid min-w-0 grid-cols-[auto_minmax(0,1fr)] items-center gap-2 @min-[36rem]/pagination:grid-cols-[minmax(0,1fr)_auto_auto] @min-[36rem]/pagination:gap-3">
|
||||
<span class="hidden min-w-0 truncate text-cp-sm font-emphasis text-cp-text-secondary @min-[36rem]/pagination:block">
|
||||
共 {{ pagination.total }} 条
|
||||
</span>
|
||||
<BaseSelect
|
||||
v-model="pageSizeModel"
|
||||
aria-label="每页条数"
|
||||
:options="pageSizeOptions"
|
||||
:disabled="loading"
|
||||
size="sm"
|
||||
class="w-28"
|
||||
class="w-28 shrink-0"
|
||||
/>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<nav
|
||||
aria-label="分页"
|
||||
class="flex shrink-0 items-center justify-self-end gap-2"
|
||||
>
|
||||
<BaseIconButton
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
@@ -90,24 +113,31 @@ function paginationPageClass(page: number) {
|
||||
<ChevronLeft class="size-4" />
|
||||
</BaseIconButton>
|
||||
|
||||
<template v-for="(item, index) in pagerItems" :key="`${item}-${index}`">
|
||||
<span
|
||||
v-if="item === 'ellipsis'"
|
||||
class="inline-flex size-8 items-center justify-center text-xs font-bold text-cp-text-quaternary"
|
||||
>
|
||||
…
|
||||
</span>
|
||||
<button
|
||||
v-else
|
||||
type="button"
|
||||
:class="paginationPageClass(item)"
|
||||
:disabled="loading || item === currentPage"
|
||||
:aria-current="item === currentPage ? 'page' : undefined"
|
||||
@click="goToPage(item)"
|
||||
>
|
||||
{{ item }}
|
||||
</button>
|
||||
</template>
|
||||
<div
|
||||
v-for="(items, variant) in [[currentPage], adjacentPagerItems, compactPagerItems, pagerItems]"
|
||||
:key="variant"
|
||||
class="items-center gap-2"
|
||||
:class="pagerVisibilityClasses[variant]"
|
||||
>
|
||||
<template v-for="(item, index) in items" :key="`${item}-${index}`">
|
||||
<span
|
||||
v-if="item === 'ellipsis'"
|
||||
class="inline-flex size-8 items-center justify-center text-xs font-bold text-cp-text-quaternary"
|
||||
>
|
||||
…
|
||||
</span>
|
||||
<button
|
||||
v-else
|
||||
type="button"
|
||||
:class="paginationPageClass(item)"
|
||||
:disabled="loading || item === currentPage"
|
||||
:aria-current="item === currentPage ? 'page' : undefined"
|
||||
@click="goToPage(item)"
|
||||
>
|
||||
{{ item }}
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<BaseIconButton
|
||||
variant="secondary"
|
||||
@@ -118,7 +148,7 @@ function paginationPageClass(page: number) {
|
||||
>
|
||||
<ChevronRight class="size-4" />
|
||||
</BaseIconButton>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user