Files
CutList/CutList.Web/Components/Shared/Pager.razor
AJ Isaacs 8ed10939d4 feat: Add reusable Pager component for list pagination
Shared Blazor component with page windowing, ellipsis for large
page counts, and "Showing X-Y of Z" summary text.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 13:45:41 -05:00

110 lines
3.2 KiB
Plaintext
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.
@if (TotalCount == 0)
{
return;
}
@{
var totalPages = (int)Math.Ceiling((double)TotalCount / PageSize);
var start = (CurrentPage - 1) * PageSize + 1;
var end = Math.Min(CurrentPage * PageSize, TotalCount);
}
<div class="d-flex justify-content-between align-items-center mt-3">
<small class="text-muted">Showing @start@end of @TotalCount</small>
@if (totalPages > 1)
{
<nav>
<ul class="pagination pagination-sm mb-0">
<li class="page-item @(CurrentPage == 1 ? "disabled" : "")">
<button class="page-link" @onclick="() => SetPage(CurrentPage - 1)" disabled="@(CurrentPage == 1)">Previous</button>
</li>
@foreach (var page in GetPageWindow(totalPages))
{
@if (page == -1)
{
<li class="page-item disabled">
<span class="page-link">&hellip;</span>
</li>
}
else
{
<li class="page-item @(page == CurrentPage ? "active" : "")">
<button class="page-link" @onclick="() => SetPage(page)">@(page)</button>
</li>
}
}
<li class="page-item @(CurrentPage == totalPages ? "disabled" : "")">
<button class="page-link" @onclick="() => SetPage(CurrentPage + 1)" disabled="@(CurrentPage == totalPages)">Next</button>
</li>
</ul>
</nav>
}
</div>
@code {
[Parameter, EditorRequired]
public int TotalCount { get; set; }
[Parameter]
public int PageSize { get; set; } = 25;
[Parameter]
public int CurrentPage { get; set; } = 1;
[Parameter]
public EventCallback<int> CurrentPageChanged { get; set; }
private async Task SetPage(int page)
{
if (page < 1 || page > (int)Math.Ceiling((double)TotalCount / PageSize))
return;
if (page == CurrentPage)
return;
CurrentPage = page;
await CurrentPageChanged.InvokeAsync(page);
}
private IEnumerable<int> GetPageWindow(int totalPages)
{
const int maxVisible = 7;
if (totalPages <= maxVisible)
{
for (var i = 1; i <= totalPages; i++)
yield return i;
yield break;
}
// Always show first page
yield return 1;
var windowStart = Math.Max(2, CurrentPage - 2);
var windowEnd = Math.Min(totalPages - 1, CurrentPage + 2);
// Adjust window to show 5 middle pages when possible
if (windowEnd - windowStart < 4)
{
if (windowStart == 2)
windowEnd = Math.Min(totalPages - 1, windowStart + 4);
else
windowStart = Math.Max(2, windowEnd - 4);
}
if (windowStart > 2)
yield return -1; // ellipsis
for (var i = windowStart; i <= windowEnd; i++)
yield return i;
if (windowEnd < totalPages - 1)
yield return -1; // ellipsis
// Always show last page
yield return totalPages;
}
}