File size: 5,181 Bytes
3418204
 
f6d34ff
3418204
 
 
 
 
 
 
 
 
121df90
3418204
 
 
 
 
 
 
f6d34ff
3418204
 
 
 
 
 
 
 
 
f6d34ff
3418204
f6d34ff
3418204
 
f6d34ff
3418204
f6d34ff
3418204
 
 
 
 
 
f6d34ff
3418204
 
 
 
 
 
 
 
 
 
 
f6d34ff
3418204
f6d34ff
3418204
 
f6d34ff
3418204
f6d34ff
3418204
 
 
 
 
 
 
 
 
 
 
 
 
 
f6d34ff
 
3418204
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
@* Partial/Pagination.razor - Reusable pagination component *@

<div class="flex flex-wrap items-center justify-between gap-3 border-t border-slate-100 bg-slate-50/60 px-5 py-3">
    <div class="text-xs text-slate-500">
        @if (TotalCount == 0)
        {
            <span>No results</span>
        }
        else
        {
            var from = (CurrentPage - 1) * PageSize + 1;
            var to = Math.Min(CurrentPage * PageSize, TotalCount);
            <span>Showing <span class="font-semibold text-slate-700">@from-@to</span> of <span class="font-semibold text-slate-700">@TotalCount</span> results</span>
        }
    </div>

    <div class="flex items-center gap-3">
        <div class="flex items-center gap-2 text-xs text-slate-500">
            <span>Rows per page</span>
            <select value="@PageSize" @onchange="HandlePageSizeChange"
                    class="rounded-lg border border-slate-200 bg-white px-2 py-1 text-xs text-slate-700 focus:outline-none focus:ring-2 focus:ring-violet-600 transition-all">
                <option value="5">5</option>
                <option value="10">10</option>
                <option value="20">20</option>
                <option value="50">50</option>
            </select>
        </div>

        <div class="flex items-center gap-1">
            <button @onclick="() => GoToPage(1)" disabled="@(CurrentPage <= 1)"
                    class="inline-flex h-8 w-8 items-center justify-center rounded-lg text-slate-400 transition-all hover:bg-white hover:text-slate-700 disabled:cursor-not-allowed disabled:opacity-40"
                    title="First page">
                <i data-lucide="chevrons-left" class="h-3.5 w-3.5"></i>
            </button>
            <button @onclick="() => GoToPage(CurrentPage - 1)" disabled="@(CurrentPage <= 1)"
                    class="inline-flex h-8 w-8 items-center justify-center rounded-lg text-slate-400 transition-all hover:bg-white hover:text-slate-700 disabled:cursor-not-allowed disabled:opacity-40"
                    title="Previous page">
                <i data-lucide="chevron-left" class="h-3.5 w-3.5"></i>
            </button>

            @foreach (var p in GetVisiblePages())
            {
                if (p == -1)
                {
                    <span class="inline-flex h-8 w-8 items-center justify-center text-xs text-slate-400">...</span>
                }
                else
                {
                    <button @onclick="() => GoToPage(p)"
                            class="@GetPageButtonClass(p)">
                        @p
                    </button>
                }
            }

            <button @onclick="() => GoToPage(CurrentPage + 1)" disabled="@(CurrentPage >= TotalPages)"
                    class="inline-flex h-8 w-8 items-center justify-center rounded-lg text-slate-400 transition-all hover:bg-white hover:text-slate-700 disabled:cursor-not-allowed disabled:opacity-40"
                    title="Next page">
                <i data-lucide="chevron-right" class="h-3.5 w-3.5"></i>
            </button>
            <button @onclick="() => GoToPage(TotalPages)" disabled="@(CurrentPage >= TotalPages)"
                    class="inline-flex h-8 w-8 items-center justify-center rounded-lg text-slate-400 transition-all hover:bg-white hover:text-slate-700 disabled:cursor-not-allowed disabled:opacity-40"
                    title="Last page">
                <i data-lucide="chevrons-right" class="h-3.5 w-3.5"></i>
            </button>
        </div>
    </div>
</div>

@code {
    [Parameter] public int CurrentPage { get; set; } = 1;
    [Parameter] public int TotalPages { get; set; } = 1;
    [Parameter] public int PageSize { get; set; } = 10;
    [Parameter] public int TotalCount { get; set; }
    [Parameter] public EventCallback<int> OnPageChanged { get; set; }
    [Parameter] public EventCallback<int> OnPageSizeChanged { get; set; }

    private string GetPageButtonClass(int p) => p == CurrentPage
        ? "inline-flex h-8 w-8 items-center justify-center rounded-lg text-xs font-semibold transition-all bg-violet-600 text-white shadow-sm"
        : "inline-flex h-8 w-8 items-center justify-center rounded-lg text-xs font-semibold transition-all text-slate-600 hover:bg-white";

    private async Task GoToPage(int p)
    {
        if (p < 1 || p > TotalPages || p == CurrentPage) return;
        await OnPageChanged.InvokeAsync(p);
    }

    private async Task HandlePageSizeChange(ChangeEventArgs e)
    {
        if (int.TryParse(e.Value?.ToString(), out var size) && size != PageSize)
        {
            await OnPageSizeChanged.InvokeAsync(size);
        }
    }

    private IEnumerable<int> GetVisiblePages()
    {
        if (TotalPages <= 7)
        {
            return Enumerable.Range(1, TotalPages);
        }

        var pages = new List<int> { 1 };

        int start = Math.Max(2, CurrentPage - 1);
        int end = Math.Min(TotalPages - 1, CurrentPage + 1);

        if (start > 2) pages.Add(-1);
        for (int i = start; i <= end; i++) pages.Add(i);
        if (end < TotalPages - 1) pages.Add(-1);

        pages.Add(TotalPages);
        return pages;
    }
}