Compare commits

...

4 Commits

Author SHA1 Message Date
98d68a535b feat: add pagination on data table 2025-03-25 23:58:55 +01:00
130473d3e4 fix: fix conflicts 2025-03-25 22:43:07 +01:00
99f3be65bc feat: adding header 2025-03-25 21:08:14 +01:00
cc6341adb2 feat: functionnal sidebar 2025-03-25 20:52:21 +01:00
22 changed files with 2579 additions and 158 deletions

View File

@ -1,7 +1,13 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack'],
});
return config;
},
};
export default nextConfig;

View File

@ -26,6 +26,7 @@
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@svgr/webpack": "^8.1.0",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",

1948
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

9
public/favicon.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.3 MiB

129
src/app/admin/home/page.tsx Normal file
View File

@ -0,0 +1,129 @@
"use client"
import Table from "#/components/table/table"
import { ColumnDef } from "@tanstack/react-table"
export default function HomePage () {
type Payment = {
id: string
amount: number
status: "pending" | "processing" | "success" | "failed"
email: string
}
const data: Payment[] = [
{
id: "728ed52f",
amount: 100,
status: "pending",
email: "m@example.com",
},
{
id: "728ed521",
amount: 200,
status: "pending",
email: "j@example.com",
},
{
id: "728ed528",
amount: 300,
status: "processing",
email: "f@example.com",
},
{
id: "728ed52g",
amount: 600,
status: "success",
email: "h@example.com",
},
{
id: "728ed520",
amount: 50,
status: "failed",
email: "k@example.com",
},
{
id: "728ed529",
amount: 200,
status: "pending",
email: "l@example.com",
},
{
id: "728ed526",
amount: 150,
status: "processing",
email: "d@example.com",
},
{
id: "728ed523",
amount: 100,
status: "success",
email: "o@example.com",
},
{
id: "728ed52y",
amount: 100,
status: "failed",
email: "v@example.com",
},
// ...
]
const columns: ColumnDef<Payment>[] = [
{
id: "select",
header: ({ table }) => (
<input checked={
table.getIsAllPageRowsSelected() ||
(table.getIsSomePageRowsSelected() && undefined)
} onChange={(value) => table.toggleAllPageRowsSelected(!!value)} type="checkbox" name="" id="" />
),
cell: ({ row }) => (
<input checked={row.getIsSelected()} onChange={(value) => row.toggleSelected(!!value)} type="checkbox" name="" id="" />
),
},
{
accessorKey: "status",
header: "Status",
},
{
accessorKey: "email",
header: ({ column }) => {
return (
<p>Email</p>
)
},
},
{
accessorKey: "amount",
header: () => <div className="">Amount</div>,
cell: ({ row }) => {
const amount = parseFloat(row.getValue("amount"))
const formatted = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
}).format(amount)
return <div className="font-medium">{formatted}</div>
},
},
]
return(
<>
<Table
columns={columns}
data={data}
pageSize={5}
/>
</>
)
}

43
src/app/admin/layout.tsx Normal file
View File

@ -0,0 +1,43 @@
import { ReactNode } from "react";
import "../../assets/css/admin.css"
import Sidebar from "../components/sidebar";
import Header from "../components/adminHeader";
export default function Dashboard({ children }: { children: ReactNode }) {
return (
<div className="r-flex-between">
<Sidebar />
<main className="flex-grow-1 min-w-0 pt-md-1 pt-sm-5">
<Header/>
<div className="p-4">
{children}
</div>
</main>
</div >
)
}
/*
<div className="sidebar r-m-0 d-flex flex-column pt-[16px] max-w-[90px] h-[100vh] relative ">
<div className="logo r-flex-center pt-[13px] px-[20px] ">
<icons.Logo aria-label="Logo" className="scale-95" />
</div>
<div className="nav-menu r-column-center h-max pt-[160px] r-gap-40 ">
<Link href="#" className="nav-item r-flex-center ">
<icons.HomeIcon aria-label="Home" className="nav-home scale-100" />
</Link>
<Link href="#" className="nav-item border-none r-flex-center ">
<icons.CompaniesIcon aria-label="Companies" className="scale-100 " width={24} height={24} />
</Link>
<Link href="#" className="nav-item r-flex-center ">
<icons.UserGroup aria-label="Admins" className="scale-100" width={24} height={24} />
</Link>
</div>
</div>
<div className="logout absolute bottom-[60px] left-[22px]">
<icons.Logout aria-label="Logout" />
</div>
*/

6
src/app/admin/page.tsx Normal file
View File

@ -0,0 +1,6 @@
export default function Admin () {
return(
<>
</>
)
}

View File

@ -0,0 +1,18 @@
import Image from "next/image";
import { icons } from "#/assets/icons"
export default function AdminHeader() {
return (
<>
<nav className="header r-flex-between px-[44px] py-[20px] ">
<p className="name text-[26px]">Bienvenue, <span>Ken B.</span> </p>
<div className="r-flex-between justify-center items-center r-gap-12">
<Image src={icons.notificationsIcon} alt="Notifications" />
<Image src={icons.profilePicture} alt="ProfilePicture" />
<Image src={icons.arrowUp} alt="arrowUp" />
</div>
</nav>
</>
)
}

View File

@ -0,0 +1,21 @@
import Image from "next/image";
import Link from "next/link";
interface ItemProps {
link: string;
iconSrc: string;
label: string;
isActive: boolean;
isNavHome?: boolean;
onClick: () => void;
}
export default function NavItem({ link, iconSrc, label, isActive, isNavHome, onClick }: ItemProps) {
return (
<>
<Link href={link} onClick={onClick} className={`nav-item r-flex-center ${isActive ? "active" : ""}`} >
<Image src={iconSrc} alt={label} className={`scale-100 ${isNavHome ? "nav-home" : ""}`} />
</Link>
</>
);
}

View File

@ -0,0 +1,38 @@
"use client"
import Image from "next/image";
import { icons } from "#/assets/icons"
import NavItem from "./navItem";
import { useState } from "react";
export default function Sidebar() {
const [activeItem, setActiveItem] = useState("home")
const handleNavMenu = (item:string) => {
setActiveItem(item)
console.log("active: ", item);
}
return (
<>
<div className="sidebar r-m-0 d-flex flex-column pt-[25px] max-w-[90px] h-[100vh] relative ">
<div className="logo r-flex-center px-[20px] ">
<Image src={icons.logo} alt="Logo" className="scale-95" />
</div>
<div className="nav-menu r-column-center h-max pt-[160px] r-gap-40 ">
<NavItem link="#" iconSrc={icons.homeIcon} label="Home" isNavHome={true} isActive={activeItem === "home"} onClick={() => handleNavMenu("home") } />
<NavItem link="#" iconSrc={icons.companiesIcon} label="Organizations" isActive={activeItem === "organizations"} onClick={() => handleNavMenu("organizations") } />
<NavItem link="#" iconSrc={icons.userGroup} label="Admins" isActive={activeItem === "admins"} onClick={() => handleNavMenu("admins") } />
</div>
<div className="logout absolute bottom-[40px] left-[28px]">
<button type="button" className="cursor-pointer">
<Image src={icons.logout} alt="Logout" />
</button>
</div>
</div>
</>
)
}

View File

@ -1,29 +1,28 @@
@import "tailwindcss";
:root {
--foreground: #04060F;
--background: #ffffff;
--foreground: #171717;
--primary: #246BFD;
--cinder: #E7E5E4;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
[ data-theme="dark"] {
--foreground: #04060F;
--background: #ffffff;
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
--foreground: #04060F;
--background: #ffffff;
}
}
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
font-family: Inter, sans-serif;
}
.input-form {

View File

@ -1,21 +1,14 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import { Inter } from "next/font/google";
import "./globals.css";
import NextTopLoader from "nextjs-toploader";
import "../assets/css/ruben-ui.css"
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Private Docs",
description: "Un application de gestion de documents",
description: "L'appli de gestion de documents par excellence !",
};
export default function RootLayout({
@ -25,10 +18,12 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<NextTopLoader />
<head>
<link rel="icon" href="/favicon.svg" />
<link rel="favicon.svg" href="/favicon.svg" />
</head>
<body className={inter.className}>
<NextTopLoader color="#246BFD" shadow="0" />
{children}
</body>
</html>

View File

@ -1,103 +1,10 @@
import Image from "next/image";
import Link from "next/link";
export default function Home() {
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={180}
height={38}
priority
/>
<ol className="list-inside list-decimal text-sm/6 text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
<li className="mb-2 tracking-[-.01em]">
Get started by editing{" "}
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-[family-name:var(--font-geist-mono)] font-semibold">
src/app/page.tsx
</code>
.
</li>
<li className="tracking-[-.01em]">
Save and see your changes instantly.
</li>
</ol>
<div className="flex gap-4 items-center flex-col sm:flex-row">
<a
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={20}
height={20}
/>
Deploy now
</a>
<a
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Read our docs
</a>
</div>
</main>
<footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/file.svg"
alt="File icon"
width={16}
height={16}
/>
Learn
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/window.svg"
alt="Window icon"
width={16}
height={16}
/>
Examples
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/globe.svg"
alt="Globe icon"
width={16}
height={16}
/>
Go to nextjs.org
</a>
</footer>
<Link href="/admin">See the admin page</Link>
</div>
);
}

28
src/assets/css/admin.css Normal file
View File

@ -0,0 +1,28 @@
.sidebar{
border-right: 1px solid var(--cinder);
}
.nav-item .nav-home{
margin-bottom: -10px;
}
.nav-item{
width: 100%;
height: max-content;
}
.nav-item.active{
border-right: 2px solid var(--primary);
}
.nav-item svg{
color: var(--primary)!important;
background-color: var(--primary)!important;
fill: var(--primary)!important;
stroke: var(--primary)!important
}
.nav-home{
margin-top: -11px;
margin-bottom: -11px;
}

160
src/assets/css/ruben-ui.css Normal file
View File

@ -0,0 +1,160 @@
/* Extra Small (XS) */
.r-p-0 {
padding: 0;
}
.r-m-0 {
margin: 0;
}
.r-p-m-0{
padding: 0;
margin: 0;
}
.r-p-0auto {
padding: 0 auto;
}
.r-m-0auto {
margin: 0 auto;
}
.r-flex {
display: flex;
}
.r-flex-center {
display: flex;
justify-content: center;
}
.r-flex-between {
display: flex;
justify-content: space-between;
}
.r-flex-around {
display: flex;
justify-content: space-around;
}
.r-flex-evenly {
display: flex;
justify-content: space-evenly;
}
.r-flex-column {
display: flex;
flex-direction: column;
}
.r-column-center,.r-column-md-row, .r-column-lg-row, .r-column-xl-row {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.r-row-center, .r-row-md-column, .r-row-lg-column, .r-row-xl-column {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.r-gap-2{
gap: 2px;
}
.r-gap-4{
gap: 4px;
}
.r-gap-6{
gap: 6px;
}
.r-gap-8{
gap: 8px;
}
.r-gap-10{
gap: 10px;
}
.r-gap-12{
gap: 12px;
}
.r-gap-14{
gap: 14px;
}
.r-gap-16{
gap: 16px;
}
.r-gap-18{
gap: 18px;
}
.r-gap-20{
gap: 20px;
}
.r-gap-22{
gap: 22px;
}
.r-gap-24{
gap: 24px;
}
.r-gap-32{
gap: 32px;
}
.r-gap-36{
gap: 36px;
}
.r-gap-40{
gap: 40px;
}
.r-gap-42{
gap: 42px;
}
.r-gap-50{
gap: 50px;
}
.r-gap-60{
gap: 60px;
}
.r-gap-70{
gap: 70px;
}
/* Small (SM) */
@media (min-width: 640px) {
/* Styles for small devices and up */
}
/* Medium (MD) */
@media (min-width: 768px) {
.r-column-md-row {
flex-direction: row;
}
.r-row-md-column{
flex-direction: column;
}
}
/* Large (LG) */
@media (min-width: 1024px) {
.r-column-lg-row {
flex-direction: row;
}
.r-row-lg-column{
flex-direction: column;
}
}
/* Extra Large (XL) */
@media (min-width: 1280px) {
.r-column-xl-row {
flex-direction: row;
}
.r-row-xl-column{
flex-direction: column;
}
}
/* 2XL (XXL) */
@media (min-width: 1536px) {
/* Styles for very large screens */
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 582 KiB

View File

@ -1,4 +1,4 @@
<svg width="48" height="49" viewBox="0 0 48 49" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg viewBox="0 0 48 49" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.02 15.34L15.63 19.54C14.73 20.24 14 21.73 14 22.86V30.27C14 32.59 15.89 34.49 18.21 34.49H29.79C32.11 34.49 34 32.59 34 30.28V23C34 21.79 33.19 20.24 32.2 19.55L26.02 15.22C24.62 14.24 22.37 14.29 21.02 15.34Z" stroke="#246BFD" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M24 30.49V27.49" stroke="#246BFD" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 523 B

After

Width:  |  Height:  |  Size: 500 B

View File

@ -0,0 +1,9 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 22H5C3 22 2 21 2 19V11C2 9 3 8 5 8H10V19C10 21 11 22 13 22Z" stroke="#9FA8BC" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.11 4C10.03 4.3 10 4.63 10 5V8H5V6C5 4.9 5.9 4 7 4H10.11Z" stroke="#9FA8BC" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 8V13" stroke="#9FA8BC" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M18 8V13" stroke="#9FA8BC" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M17 17H15C14.45 17 14 17.45 14 18V22H18V18C18 17.45 17.55 17 17 17Z" stroke="#9FA8BC" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 13V17" stroke="#9FA8BC" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 19V5C10 3 11 2 13 2H19C21 2 22 3 22 5V19C22 21 21 22 19 22H13C11 22 10 21 10 19Z" stroke="#9FA8BC" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -14,12 +14,14 @@ import addBlueIcon from "./icon-add.svg"
import archivesIcon from "./archives.svg"
import notificationsIcon from "./notifications.svg"
import timerIcon from "./Line Duotone.svg"
import logo from "./Logo Private Docs@2x.svg"
import logo from "./logo.svg"
import logoutRed from "./logout-red.svg"
import logout from "./logout.svg"
import maximizeIcon from "./maximize-3.svg"
import menuIcon from "./Menu Dots.svg"
import messagesIcon from "./message.svg"
import homeIcon from "./NavItem.svg"
import companiesIcon from "./buildings.svg"
import arrowLeft from "./arrowLeft.svg"
import arrowRight from "./arrowLeft.svg"
import filesIcon from "./ph_files.svg"
@ -55,6 +57,8 @@ export const icons = {
notificationsIcon,
timerIcon,
logo,
companiesIcon,
logout,
logoutRed,
maximizeIcon,
menuIcon,
@ -75,4 +79,92 @@ export const icons = {
shareIcon,
starIcon,
arrowUp
}
}
/*
import AddIcon from "./add.svg";
import CalendarIcon from "./Calendar Mark.svg";
import DocummentTextIcon from "./document-text.svg";
import FolderIcon from "./Document.svg";
import EditIcon from "./edit-2.svg";
import GridIcon from "./element-3-white.svg";
import GridBlueIcon from "./element-3.svg";
import ProfilePicture from "./Ellipse 2.svg";
import EyeIcon from "./eye.svg";
import EyeSlashIcon from "./eye-slash.svg";
import CheckboxchedIcon from "./checked.svg";
import CrossIcon from "./cross.svg";
import AddBlueIcon from "./icon-add.svg";
import ArchivesIcon from "./archives.svg";
import NotificationsIcon from "./notifications.svg";
import TimerIcon from "./Line Duotone.svg";
import Logo from "./logo.svg";
import LogoutRed from "./logout-red.svg";
import Logout from "./logout.svg";
import MaximizeIcon from "./maximize-3.svg";
import MenuIcon from "./Menu Dots.svg";
import MessagesIcon from "./message.svg";
import HomeIcon from "./NavItem.svg";
import CompaniesIcon from "./buildings.svg";
import ArrowLeft from "./arrowLeft.svg";
import ArrowRight from "./arrowLeft.svg";
import FilesIcon from "./ph_files.svg";
import PdfIcon from "./prime_file-pdf.svg";
import WordIcon from "./prime_file-word.svg";
import UserIcon from "./profile.svg";
import UserGroup from "./profile-2user.svg";
import UserGroupBlue from "./profile-2user-blue.svg";
import Rectanagle from "./Rectangle.svg";
import SearchIcon from "./Search.svg";
import SettingsIcon from "./setting-2.svg";
import FilterIcon from "./setting-3.svg";
import ShareIcon from "./share.svg";
import StarIcon from "./star.svg";
import ArrowUp from "./Vector.svg";
export const icons = {
AddIcon,
CalendarIcon,
DocummentTextIcon,
FolderIcon,
EditIcon,
GridIcon,
GridBlueIcon,
ProfilePicture,
EyeIcon,
EyeSlashIcon,
CheckboxchedIcon,
CrossIcon,
AddBlueIcon,
ArchivesIcon,
NotificationsIcon,
TimerIcon,
Logo,
CompaniesIcon,
Logout,
LogoutRed,
MaximizeIcon,
MenuIcon,
MessagesIcon,
HomeIcon,
ArrowLeft,
ArrowRight,
FilesIcon,
PdfIcon,
WordIcon,
UserIcon,
UserGroup,
UserGroupBlue,
Rectanagle,
SearchIcon,
SettingsIcon,
FilterIcon,
ShareIcon,
StarIcon,
ArrowUp
};
*/

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.8999 7.55999C9.2099 3.95999 11.0599 2.48999 15.1099 2.48999H15.2399C19.7099 2.48999 21.4999 4.27999 21.4999 8.74999V15.27C21.4999 19.74 19.7099 21.53 15.2399 21.53H15.1099C11.0899 21.53 9.2399 20.08 8.9099 16.54" stroke="#9FA8BC" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15.0001 12H3.62012" stroke="#9FA8BC" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.85 8.65002L2.5 12L5.85 15.35" stroke="#9FA8BC" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 655 B

View File

@ -10,15 +10,18 @@ import {
getFilteredRowModel,
} from "@tanstack/react-table"
import { useState } from "react";
import { clsx, type ClassValue } from "clsx"
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[]
data: TData[]
data: TData[],
pageSize?: number
}
export default function Table<TData, TValue>({
columns,
data,
pageSize = 10
}: DataTableProps<TData, TValue>) {
const [rowSelection, setRowSelection] = useState({})
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>(
@ -35,26 +38,37 @@ export default function Table<TData, TValue>({
rowSelection,
columnFilters,
},
initialState: {
pagination: {
pageSize: pageSize,
}
},
getFilteredRowModel: getFilteredRowModel(),
onRowSelectionChange: setRowSelection,
onColumnFiltersChange: setColumnFilters,
})
const totalPages = table.getPageCount()
const currentPage = table.getState().pagination.pageIndex + 1
function clsx(arg0: string, arg1: { 'bg-gray-300': boolean; }): string | undefined {
throw new Error("Function not implemented.");
const getPageNumbers = () => {
const pages = []
for (let i = 1; i <= totalPages; i++) {
pages.push(i)
}
return pages
}
return(
<div>
<div className="rounded-md border">
<table>
<thead>
<div className="rounded-lg border border-gray-200">
<table className="w-full overflow-x-auto rounded-lg " style={{ borderTopLeftRadius: '10px', borderTopRightRadius: '10px', }}>
<thead className="h-10">
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
<tr key={headerGroup.id} className="rounded-lg">
{headerGroup.headers.map((header) => {
return(
<th key={header.id}>
<th key={header.id} className="bg-blue-300 p-3 text-start">
{flexRender(
header.column.columnDef.header,
header.getContext()
@ -68,9 +82,9 @@ export default function Table<TData, TValue>({
<tbody>
{table.getRowModel().rows.length ? (
table.getRowModel().rows.map((row) => (
<tr key={row.id} className={clsx('hover:bg-gray-300', { 'bg-gray-300': row.getIsSelected()})}>
<tr key={row.id} className={clsx('hover:bg-gray-300 border-t border-gray-200', { 'bg-gray-300': row.getIsSelected()})}>
{row.getVisibleCells().map((cell) => (
<td key={cell.id}>
<td key={cell.id} className="p-3 text-start">
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
@ -79,7 +93,7 @@ export default function Table<TData, TValue>({
)
: (
<tr>
<td>
<td colSpan={columns.length}>
Aucun résultats
</td>
</tr>
@ -90,13 +104,32 @@ export default function Table<TData, TValue>({
<div className="flex items-center justify-end space-x-2 py-4">
<button
className="border bg-gray-200 shadow-xs hover:bg-gray-300 hover:text-black"
className="border bg-gray-200 shadow-xs hover:bg-gray-300 hover:text-black px-3 py-1 rounded"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
Précédent
</button>
<div className="flex space-x-1">
{getPageNumbers().map((pageNumber) => (
<button
key={pageNumber}
className={clsx(
"px-3 py-1 rounded",
pageNumber === currentPage
? "bg-blue-500 text-white"
: "bg-gray-200 hover:bg-gray-300"
)}
onClick={() => table.setPageIndex(pageNumber - 1)}
>
{pageNumber}
</button>
))}
</div>
<button
className="border bg-gray-200 shadow-xs hover:bg-gray-300 hover:text-black px-3 py-1 rounded"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>