import { useState } from 'react';
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from
'lucide-react';
interface TabProps {
id: string;
label: string;
}
const tabs: TabProps[] = [
{ id: 'javascript', label: 'JavaScript' },
{ id: 'react', label: 'React' },
{ id: 'angular', label: 'Angular' }
];
export default function PaginationVisualizer() {
const [activeTab, setActiveTab] = useState('javascript');
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(10);
const totalItems = 95;
const totalPages = [Link](totalItems / itemsPerPage);
const getVisiblePages = () => {
const pages = [];
const maxVisible = 7;
if (totalPages <= maxVisible) {
for (let i = 1; i <= totalPages; i++) {
[Link](i);
}
} else {
if (currentPage <= 4) {
for (let i = 1; i <= 5; i++) [Link](i);
[Link]('...');
[Link](totalPages);
} else if (currentPage >= totalPages - 3) {
[Link](1);
[Link]('...');
for (let i = totalPages - 4; i <= totalPages; i++) [Link](i);
} else {
[Link](1);
[Link]('...');
for (let i = currentPage - 1; i <= currentPage + 1; i++)
[Link](i);
[Link]('...');
[Link](totalPages);
}
}
return pages;
};
const goToPage = (page: number) => {
if (page >= 1 && page <= totalPages) {
setCurrentPage(page);
}
};
const startIndex = (currentPage - 1) * itemsPerPage + 1;
const endIndex = [Link](currentPage * itemsPerPage, totalItems);
return (
<div className="w-full max-w-6xl mx-auto p-6">
<div className="bg-white rounded-lg shadow-lg overflow-hidden">
<div className="bg-gradient-to-r from-blue-600 to-cyan-600 p-6">
<h1 className="text-3xl font-bold text-white mb-2">Pagination
Visualizer</h1>
<p className="text-blue-100">Interactive demonstrations across
JavaScript, React, and Angular</p>
</div>
<div className="border-b border-gray-200">
<div className="flex">
{[Link]((tab) => (
<button
key={[Link]}
onClick={() => setActiveTab([Link])}
className={`px-6 py-4 font-medium transition-colors ${
activeTab === [Link]
? 'text-blue-600 border-b-2 border-blue-600 bg-blue-50'
: 'text-gray-600 hover:text-blue-600 hover:bg-gray-50'
}`}
>
{[Link]}
</button>
))}
</div>
</div>
<div className="p-6">
<div className="mb-8 bg-gray-50 rounded-lg p-6">
<h3 className="text-lg font-semibold text-gray-800 mb-
4">Interactive Controls</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<div className="bg-white p-4 rounded-lg border border-gray-
200">
<label className="block text-sm font-medium text-gray-700
mb-2">
Items per page
</label>
<input
type="number"
min="5"
max="50"
value={itemsPerPage}
onChange={(e) => {
setItemsPerPage(Number([Link]));
setCurrentPage(1);
}}
className="w-full px-3 py-2 border border-gray-300 rounded-
md focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div className="bg-white p-4 rounded-lg border border-gray-
200">
<div className="text-sm font-medium text-gray-700 mb-
1">Total Items</div>
<div className="text-2xl font-bold text-blue-
600">{totalItems}</div>
</div>
<div className="bg-white p-4 rounded-lg border border-gray-
200">
<div className="text-sm font-medium text-gray-700 mb-
1">Total Pages</div>
<div className="text-2xl font-bold text-cyan-
600">{totalPages}</div>
</div>
</div>
<div className="bg-white p-4 rounded-lg border border-gray-
200">
<div className="text-sm font-medium text-gray-700 mb-
2">Current Range</div>
<div className="text-lg font-semibold text-gray-800">
Showing items {startIndex} - {endIndex} of {totalItems}
</div>
</div>
</div>
<div className="mb-8">
<h3 className="text-lg font-semibold text-gray-800 mb-
4">Pagination Component</h3>
<div className="flex items-center justify-center gap-2 flex-
wrap">
<button
onClick={() => goToPage(1)}
disabled={currentPage === 1}
className="p-2 rounded-md border border-gray-300 hover:bg-
gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
title="First page"
>
<ChevronsLeft className="w-5 h-5" />
</button>
<button
onClick={() => goToPage(currentPage - 1)}
disabled={currentPage === 1}
className="p-2 rounded-md border border-gray-300 hover:bg-
gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
title="Previous page"
>
<ChevronLeft className="w-5 h-5" />
</button>
{getVisiblePages().map((page, index) => (
<button
key={index}
onClick={() => typeof page === 'number' &&
goToPage(page)}
disabled={page === '...'}
className={`min-w-[40px] h-10 rounded-md font-medium
transition-colors ${
page === currentPage
? 'bg-blue-600 text-white'
: page === '...'
? 'cursor-default text-gray-400'
: 'border border-gray-300 hover:bg-gray-50 text-gray-700'
}`}
>
{page}
</button>
))}
<button
onClick={() => goToPage(currentPage + 1)}
disabled={currentPage === totalPages}
className="p-2 rounded-md border border-gray-300 hover:bg-
gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
title="Next page"
>
<ChevronRight className="w-5 h-5" />
</button>
<button
onClick={() => goToPage(totalPages)}
disabled={currentPage === totalPages}
className="p-2 rounded-md border border-gray-300 hover:bg-
gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
title="Last page"
>
<ChevronsRight className="w-5 h-5" />
</button>
</div>
</div>
<div className="bg-gray-900 rounded-lg p-6 overflow-x-auto">
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold text-white">Code
Implementation</h3>
<span className="text-sm
text-gray-400">{activeTab}</span>
</div>
{activeTab === 'javascript' && <JavaScriptCode />}
{activeTab === 'react' && <ReactCode />}
{activeTab === 'angular' && <AngularCode />}
</div>
</div>
</div>
</div>
);
}
function JavaScriptCode() {
return (
<pre className="text-sm text-gray-100 overflow-x-auto">
<code>{`class Pagination {
constructor(totalItems, itemsPerPage = 10) {
[Link] = totalItems;
[Link] = itemsPerPage;
[Link] = 1;
}
get totalPages() {
return [Link]([Link] / [Link]);
}
get startIndex() {
return ([Link] - 1) * [Link];
}
get endIndex() {
return [Link](
[Link] * [Link],
[Link]
);
}
goToPage(page) {
if (page >= 1 && page <= [Link]) {
[Link] = page;
return true;
}
return false;
}
nextPage() {
return [Link]([Link] + 1);
}
prevPage() {
return [Link]([Link] - 1);
}
getVisiblePages(maxVisible = 7) {
const pages = [];
if ([Link] <= maxVisible) {
for (let i = 1; i <= [Link]; i++) {
[Link](i);
}
} else {
if ([Link] <= 4) {
for (let i = 1; i <= 5; i++) [Link](i);
[Link]('...');
[Link]([Link]);
} else if ([Link] >= [Link] - 3) {
[Link](1);
[Link]('...');
for (let i = [Link] - 4; i <= [Link]; i++) {
[Link](i);
}
} else {
[Link](1);
[Link]('...');
[Link]([Link] - 1);
[Link]([Link]);
[Link]([Link] + 1);
[Link]('...');
[Link]([Link]);
}
}
return pages;
}
paginateArray(array) {
return [Link]([Link], [Link]);
}
}
const pagination = new Pagination(95, 10);
[Link]([Link]());
[Link]();`}</code>
</pre>
);
}
function ReactCode() {
return (
<pre className="text-sm text-gray-100 overflow-x-auto">
<code>{`import { useState, useMemo } from 'react';
function usePagination(totalItems, initialItemsPerPage = 10) {
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(initialItemsPerPage);
const totalPages = useMemo(
() => [Link](totalItems / itemsPerPage),
[totalItems, itemsPerPage]
);
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = [Link](currentPage * itemsPerPage, totalItems);
const goToPage = (page) => {
if (page >= 1 && page <= totalPages) {
setCurrentPage(page);
}
};
const nextPage = () => goToPage(currentPage + 1);
const prevPage = () => goToPage(currentPage - 1);
const firstPage = () => goToPage(1);
const lastPage = () => goToPage(totalPages);
const getVisiblePages = (maxVisible = 7) => {
const pages = [];
if (totalPages <= maxVisible) {
for (let i = 1; i <= totalPages; i++) {
[Link](i);
}
} else {
if (currentPage <= 4) {
for (let i = 1; i <= 5; i++) [Link](i);
[Link]('...');
[Link](totalPages);
} else if (currentPage >= totalPages - 3) {
[Link](1);
[Link]('...');
for (let i = totalPages - 4; i <= totalPages; i++) {
[Link](i);
}
} else {
[Link](1);
[Link]('...');
[Link](currentPage - 1);
[Link](currentPage);
[Link](currentPage + 1);
[Link]('...');
[Link](totalPages);
}
}
return pages;
};
const paginateArray = (array) => {
return [Link](startIndex, endIndex);
};
return {
currentPage,
itemsPerPage,
totalPages,
startIndex,
endIndex,
setItemsPerPage,
goToPage,
nextPage,
prevPage,
firstPage,
lastPage,
getVisiblePages,
paginateArray
};
}
function MyComponent() {
const data = [Link]({ length: 95 }, (_, i) => i + 1);
const pagination = usePagination([Link], 10);
const paginatedData = [Link](data);
return (
<div>
{[Link](item => <div key={item}>{item}</div>)}
</div>
);
}`}</code>
</pre>
);
}
function AngularCode() {
return (
<pre className="text-sm text-gray-100 overflow-x-auto">
<code>{`// [Link]
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class PaginationService {
private currentPageSubject = new BehaviorSubject<number>(1);
currentPage$ = [Link]();
constructor() {}
getTotalPages(totalItems: number, itemsPerPage: number): number {
return [Link](totalItems / itemsPerPage);
}
getStartIndex(currentPage: number, itemsPerPage: number): number {
return (currentPage - 1) * itemsPerPage;
}
getEndIndex(
currentPage: number,
itemsPerPage: number,
totalItems: number
): number {
return [Link](currentPage * itemsPerPage, totalItems);
}
goToPage(page: number, totalPages: number): void {
if (page >= 1 && page <= totalPages) {
[Link](page);
}
}
getVisiblePages(
currentPage: number,
totalPages: number,
maxVisible: number = 7
): (number | string)[] {
const pages: (number | string)[] = [];
if (totalPages <= maxVisible) {
for (let i = 1; i <= totalPages; i++) {
[Link](i);
}
} else {
if (currentPage <= 4) {
for (let i = 1; i <= 5; i++) [Link](i);
[Link]('...');
[Link](totalPages);
} else if (currentPage >= totalPages - 3) {
[Link](1);
[Link]('...');
for (let i = totalPages - 4; i <= totalPages; i++) {
[Link](i);
}
} else {
[Link](1);
[Link]('...');
[Link](currentPage - 1);
[Link](currentPage);
[Link](currentPage + 1);
[Link]('...');
[Link](totalPages);
}
}
return pages;
}
paginateArray<T>(array: T[], currentPage: number, itemsPerPage:
number): T[] {
const start = [Link](currentPage, itemsPerPage);
const end = [Link](currentPage, itemsPerPage,
[Link]);
return [Link](start, end);
}
}
// [Link]
import { Component } from '@angular/core';
import { PaginationService } from './[Link]';
@Component({
selector: 'app-pagination',
template: \`
<div>
<div *ngFor="let item of paginatedData">{{ item }}</div>
<button (click)="goToPage(currentPage - 1)">Previous</button>
<button (click)="goToPage(currentPage + 1)">Next</button>
</div>
\`
})
export class PaginationComponent {
data = [Link]({ length: 95 }, (_, i) => i + 1);
currentPage = 1;
itemsPerPage = 10;
paginatedData: number[] = [];
constructor(private paginationService: PaginationService) {
[Link]();
}
goToPage(page: number): void {
const totalPages = [Link](
[Link],
[Link]
);
[Link](page, totalPages);
[Link] = page;
[Link]();
}
updatePaginatedData(): void {
[Link] = [Link](
[Link],
[Link],
[Link]
);
}
}`}</code>
</pre>
);
}
"lucide-react": "^0.344.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"