Files
platform/src/workspaces/components/DataTable/PaginationBar.tsx
T
pastilhas 5ce1a2928e inputs and data views keyed: search, select, tabs, state blocks, data table
The DataTable's pagination carries the only interpolated strings in this area
('Showing page {{current}} of {{total}}', '{{size}} / page'). No plural forms:
nothing here is a count-varying noun, so inventing one would only add a key
nobody uses.

DataTable.test.tsx now renders inside an I18nProvider with the real en-GB
catalog, so it still asserts the English a user sees rather than a dot-path.

Left/right utilities became logical (ms-/me-/ps-/pe-/start-) per D3.
2026-08-23 04:10:33 +00:00

125 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// PaginationBar.tsx
import type { UseDataControlReturn } from 'hooks/useDataControl';
import { useMemo } from 'react';
import { Button } from '@/components/ui/button';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { useTranslation } from '@/components/locales';
type PaginationBarProps<T> = {
dataManager: UseDataControlReturn<T>;
};
export const PaginationBar = <T,>(props: PaginationBarProps<T>) => {
const { t } = useTranslation();
const { currentPage, pageCount, changePage, pageSize, setPageSize } = props.dataManager;
const pageSizeOptions = useMemo(() => [5, 10, 15, 20], []);
const handlePageSizeChange = (value: string) => {
const next = Number(value);
if (!Number.isFinite(next) || next <= 0) return;
setPageSize(next);
changePage(1);
};
const buttonClass =
'h-8 w-8 p-0 hover:bg-background text-muted-foreground disabled:opacity-100 disabled:pointer-events-none';
return (
<div className="bg-muted/50 flex w-full items-center justify-between border-t p-4">
{/* LEFT */}
<div className="flex items-center gap-2 min-[500px]:gap-3 text-sm text-muted-foreground whitespace-nowrap">
<span className="hidden min-[500px]:inline">
{t('dataTable.pagination.showingPage', { current: currentPage, total: pageCount })}
</span>
<span className="min-[500px]:hidden">
{t('dataTable.pagination.showingPageShort', { current: currentPage, total: pageCount })}
</span>
<span className="bg-border h-5 w-px" aria-hidden="true" />
<Select value={String(pageSize)} onValueChange={handlePageSizeChange}>
<SelectTrigger
className="
h-8
w-[80px] min-[500px]:w-[110px]
justify-between
bg-transparent
text-muted-foreground
hover:bg-background
data-[state=open]:bg-muted
"
aria-label={t('dataTable.pagination.rowsPerPage')}
>
<SelectValue className="text-muted-foreground">
<span className="hidden min-[500px]:inline">{t('dataTable.pagination.perPage', { size: pageSize })}</span>
<span className="min-[500px]:hidden">{t('dataTable.pagination.perPageShort', { size: pageSize })}</span>
</SelectValue>
</SelectTrigger>
<SelectContent align="start">
{pageSizeOptions.map((n) => (
<SelectItem
key={n}
value={String(n)}
className="
text-muted-foreground
data-[state=checked]:bg-muted
data-[state=checked]:text-muted-foreground
"
>
<span className="hidden min-[500px]:inline">{t('dataTable.pagination.perPage', { size: n })}</span>
<span className="min-[500px]:hidden">{t('dataTable.pagination.perPageShort', { size: n })}</span>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
{/* RIGHT */}
<div className="flex items-center gap-0.5 min-[500px]:gap-1">
<Button
variant="outline"
size="sm"
className={buttonClass}
onClick={() => changePage(1)}
disabled={currentPage === 1}
aria-label={t('dataTable.pagination.first')}
>
«
</Button>
<Button
variant="outline"
size="sm"
className={buttonClass}
onClick={() => changePage(currentPage - 1)}
disabled={currentPage === 1}
aria-label={t('dataTable.pagination.prev')}
>
‹
</Button>
<Button
variant="outline"
size="sm"
className={buttonClass}
onClick={() => changePage(currentPage + 1)}
disabled={currentPage === pageCount}
aria-label={t('dataTable.pagination.next')}
>
›
</Button>
<Button
variant="outline"
size="sm"
className={buttonClass}
onClick={() => changePage(pageCount)}
disabled={currentPage === pageCount}
aria-label={t('dataTable.pagination.last')}
>
»
</Button>
</div>
</div>
);
};