Refonte front (packages/web) : coquille applicative partagée (sidebar desktop + barre d'onglets mobile + PageHeader, langue/push/logout centralisés) pilotée par route.meta.layout ; design system (BaseButton/BaseBadge/SegmentedControl/EmptyState/ SkeletonRow, anneau de focus, icônes @lucide/vue) ; tri/filtre/recherche/pagination côté client via useListControls (+ synchro URL) sur sessions/worktrees/groupes ; section « À traiter », palette de commandes ⌘K, toasts. Aucune modif serveur/protocole/DB. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
48 lines
1.7 KiB
Vue
48 lines
1.7 KiB
Vue
<template>
|
|
<div v-if="pageCount > 1 || pageSize !== defaultSize" class="flex flex-wrap items-center justify-between gap-2 text-xs text-zinc-500">
|
|
<div class="flex items-center gap-2">
|
|
<label class="flex items-center gap-1.5">
|
|
{{ t('pagination.perPage') }}
|
|
<select class="input w-auto py-1" :value="pageSize" @change="onSize">
|
|
<option v-for="opt in pageSizeOptions" :key="opt" :value="opt">{{ opt === 0 ? t('pagination.all') : opt }}</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<div v-if="pageCount > 1" class="flex items-center gap-2">
|
|
<BaseButton variant="ghost" size="sm" :icon="ChevronLeft" :disabled="page <= 1" @click="emit('update:page', page - 1)">
|
|
{{ t('pagination.prev') }}
|
|
</BaseButton>
|
|
<span>{{ t('pagination.pageOf', { page, pageCount }) }}</span>
|
|
<BaseButton variant="ghost" size="sm" :disabled="page >= pageCount" @click="emit('update:page', page + 1)">
|
|
{{ t('pagination.next') }}
|
|
<ChevronRight :size="15" />
|
|
</BaseButton>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useI18n } from 'vue-i18n';
|
|
import { ChevronLeft, ChevronRight } from '@lucide/vue';
|
|
import BaseButton from './ui/BaseButton.vue';
|
|
|
|
const { t } = useI18n();
|
|
|
|
withDefaults(
|
|
defineProps<{
|
|
page: number;
|
|
pageCount: number;
|
|
pageSize: number;
|
|
pageSizeOptions?: number[];
|
|
defaultSize?: number;
|
|
}>(),
|
|
{ pageSizeOptions: () => [25, 50, 100, 0], defaultSize: 25 },
|
|
);
|
|
|
|
const emit = defineEmits<{ 'update:page': [number]; 'update:pageSize': [number] }>();
|
|
|
|
function onSize(e: Event): void {
|
|
emit('update:pageSize', Number((e.target as HTMLSelectElement).value));
|
|
}
|
|
</script>
|