Files
CRM_Montzar/apps/web/src/components/ui/UiPagination.vue
T
s.esmaeili 1ae87c97b7 feat(ui): standardize design system, modals, sidebar, and form inputs
- Implement unified design system tokens, 10px radius, and IRANSans typography
- Modernize sidebar with Gemini-style collapsed expander, square 1:1 items, and elevated profile flyout
- Standardize all modal dialogs with 16px padding, fixed header/footer, 16px medium title, and sticky bottom actions
- Refactor DealFormView and CustomFieldsSection with standard UiField, UiInput, and UiSelect components
- Add draggable bottom-left QuickCreate floating action button
2026-09-12 01:33:07 +03:30

143 lines
3.2 KiB
Vue

<script setup lang="ts">
import { computed } from 'vue';
import UiButton from './UiButton.vue';
import UiIcon from '@/components/UiIcon.vue';
const props = withDefaults(
defineProps<{
page: number;
totalPages?: number;
totalItems?: number;
pageSize?: number;
}>(),
{
page: 1,
},
);
const emit = defineEmits<{
'update:page': [page: number];
change: [page: number];
}>();
const effectiveTotalPages = computed(() => {
if (props.totalPages != null) return Math.max(1, props.totalPages);
if (props.totalItems != null && props.pageSize != null && props.pageSize > 0) {
return Math.max(1, Math.ceil(props.totalItems / props.pageSize));
}
return 1;
});
function goTo(p: number) {
if (p < 1 || p > effectiveTotalPages.value || p === props.page) return;
emit('update:page', p);
emit('change', p);
}
</script>
<template>
<nav v-if="effectiveTotalPages > 1 || totalItems !== undefined" class="ui-pagination" aria-label="صفحه‌بندی">
<div class="pagination-info">
<span v-if="totalItems !== undefined">
مجموع: <strong>{{ totalItems }}</strong> مورد
</span>
<span v-if="effectiveTotalPages > 1" class="page-count">
(صفحه {{ page }} از {{ effectiveTotalPages }})
</span>
</div>
<div v-if="effectiveTotalPages > 1" class="pagination-controls">
<UiButton
variant="ghost"
size="sm"
:disabled="page <= 1"
title="صفحه اول"
@click="goTo(1)"
>
<UiIcon name="chevrons-right" :size="14" />
</UiButton>
<UiButton
variant="ghost"
size="sm"
:disabled="page <= 1"
title="صفحه قبل"
@click="goTo(page - 1)"
>
<UiIcon name="chevron-right" :size="14" />
قبلی
</UiButton>
<span class="current-indicator">
{{ page }} / {{ effectiveTotalPages }}
</span>
<UiButton
variant="ghost"
size="sm"
:disabled="page >= effectiveTotalPages"
title="صفحه بعد"
@click="goTo(page + 1)"
>
بعدی
<UiIcon name="chevron-left" :size="14" />
</UiButton>
<UiButton
variant="ghost"
size="sm"
:disabled="page >= effectiveTotalPages"
title="صفحه آخر"
@click="goTo(effectiveTotalPages)"
>
<UiIcon name="chevrons-left" :size="14" />
</UiButton>
</div>
</nav>
</template>
<style scoped>
.ui-pagination {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: var(--sp-3);
padding-top: var(--sp-4);
width: 100%;
}
.pagination-info {
font-size: var(--fs-sm);
color: var(--muted);
display: flex;
align-items: center;
gap: var(--sp-2);
}
.page-count {
color: var(--muted-light);
}
.pagination-controls {
display: inline-flex;
align-items: center;
gap: var(--sp-1);
}
.current-indicator {
padding: 0 var(--sp-2);
font-size: var(--fs-xs);
font-weight: var(--fw-bold);
color: var(--ink-secondary);
}
@media (max-width: 900px) {
.ui-pagination {
flex-direction: column;
align-items: center;
gap: var(--sp-3);
}
}
</style>