master
mahdi 3 years ago
parent 0dbcf47d32
commit cf2e2d8854
  1. 15
      package-lock.json
  2. 1
      package.json
  3. 4
      src/App.js
  4. 294
      src/components/ReactTable/Table.js
  5. 58
      src/components/ReactTable/index.js
  6. 35
      src/components/ReactTable/shared/Button.js
  7. 17
      src/components/ReactTable/shared/Icons.js
  8. 3
      src/components/ReactTable/shared/Utils.js
  9. 305
      src/components/ReactTable2/Table.js
  10. 90
      src/components/ReactTable2/index.js
  11. 35
      src/components/ReactTable2/shared/Button.js
  12. 17
      src/components/ReactTable2/shared/Icons.js
  13. 3
      src/components/ReactTable2/shared/Utils.js
  14. 5
      yarn.lock

15
package-lock.json generated

@ -11,6 +11,7 @@
"@fortawesome/free-brands-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.16",
"@heroicons/react": "^1.0.5",
"@reduxjs/toolkit": "^1.7.1",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
@ -2148,6 +2149,14 @@
"react": ">=16.x"
}
},
"node_modules/@heroicons/react": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@heroicons/react/-/react-1.0.5.tgz",
"integrity": "sha512-UDMyLM2KavIu2vlWfMspapw9yii7aoLwzI2Hudx4fyoPwfKfxU8r3cL8dEBXOjcLG0/oOONZzbT14M1HoNtEcg==",
"peerDependencies": {
"react": ">= 16"
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz",
@ -18327,6 +18336,12 @@
"prop-types": "^15.7.2"
}
},
"@heroicons/react": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@heroicons/react/-/react-1.0.5.tgz",
"integrity": "sha512-UDMyLM2KavIu2vlWfMspapw9yii7aoLwzI2Hudx4fyoPwfKfxU8r3cL8dEBXOjcLG0/oOONZzbT14M1HoNtEcg==",
"requires": {}
},
"@humanwhocodes/config-array": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz",

@ -6,6 +6,7 @@
"@fortawesome/free-brands-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.16",
"@heroicons/react": "^1.0.5",
"@reduxjs/toolkit": "^1.7.1",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",

@ -43,6 +43,8 @@ import SpecifiedDomainRadarChart from "./components/Chart/SpecifiedDomainRadarCh
import Design1 from "./components/ProductSalesAmount/Design1";
import Design2 from "./components/ProductSalesAmount/Design2";
import TableDesign1 from "./components/Table/Design1";
import ReactTable from "./components/ReactTable";
import ReactTable2 from "./components/ReactTable2";
function App() {
return (
@ -86,6 +88,8 @@ function App() {
{/* <Design1 /> */}
{/* <Design2 /> */}
{/* <TableDesign1 /> */}
{/* <ReactTable /> */}
<ReactTable2 />
</div>
</Provider>
);

@ -0,0 +1,294 @@
import React from "react";
import {
useTable,
useGlobalFilter,
useAsyncDebounce,
useSortBy,
usePagination,
} from "react-table"; // new
import {
ChevronDoubleLeftIcon,
ChevronLeftIcon,
ChevronRightIcon,
ChevronDoubleRightIcon,
} from "@heroicons/react/solid";
import { Button, PageButton } from "./shared/Button";
import { classNames } from "./shared/Utils";
import { SortIcon, SortUpIcon, SortDownIcon } from "./shared/Icons";
function GlobalFilter({
preGlobalFilteredRows,
globalFilter,
setGlobalFilter,
}) {
const count = preGlobalFilteredRows.length;
const [value, setValue] = React.useState(globalFilter);
const onChange = useAsyncDebounce((value) => {
setGlobalFilter(value || undefined);
}, 200);
return (
<span>
Search:{" "}
<input
value={value || ""}
onChange={(e) => {
setValue(e.target.value);
onChange(e.target.value);
}}
placeholder={`${count} records...`}
/>
</span>
);
}
// This is a custom filter UI for selecting
export function StatusPill({ value }) {
// const status = value ? value.toLowerCase() : "unknown";
return (
// <span
// className={`p-4 whitespace-nowrap text-base font-light
// ${status ? "text-green-400" : "text-red-400"}`}
// // className={classNames(
// // "px-3 py-1 uppercase leading-wide font-bold text-xs rounded-full shadow-sm",
// // status ? "bg-green-600 text-green-800" : null,
// // status ? "bg-yellow-400 text-yellow-800" : null
// // )}
// >
// {/* {status} */}
// {status ? "فعال" : "غیر فعال"}
// </span>
<span
className={`p-4 whitespace-nowrap text-base font-light
${value ? "text-green-400" : "text-red-400"}`}
>
{value ? "فعال" : "غیر فعال"}
</span>
);
console.log(value);
}
function Table({ columns, data }) {
// Use the state and functions returned from useTable to build your UI
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
//new
page, // Instead of using 'rows', we'll use page,
// which has only the rows for the active page
// The rest of these things are super handy, too ;)
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
state, // new
preGlobalFilteredRows, // new
setGlobalFilter,
} = useTable(
{
columns,
data,
},
useGlobalFilter,
useSortBy, // new
usePagination
);
// Render the UI for your table
return (
<>
<div className="sm:flex sm:gap-x-2">
<GlobalFilter
preGlobalFilteredRows={preGlobalFilteredRows}
globalFilter={state.globalFilter}
setGlobalFilter={setGlobalFilter}
/>
{headerGroups.map((headerGroup) =>
headerGroup.headers.map((column) =>
column.Filter ? (
<div className="mt-2 sm:mt-0" key={column.id}>
{column.render("Filter")}
</div>
) : null
)
)}
</div>
{/* table */}
<div className="mt-4 flex flex-col">
<div className="-my-2 overflow-x-auto -mx-4 sm:-mx-6 lg:-mx-8">
<div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
<div className="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
<table
{...getTableProps()}
className="min-w-full divide-y divide-gray-200"
>
<thead className="bg-gray-50">
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
// Add the sorting props to control sorting. For this example
// we can add them into the header props
<th
scope="col"
className="group px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
{...column.getHeaderProps(
column.getSortByToggleProps()
)}
>
<div className="flex items-center justify-between">
{column.render("Header")}
{/* Add a sort direction indicator */}
<span>
{column.isSorted ? (
column.isSortedDesc ? (
<SortDownIcon className="w-4 h-4 text-gray-400" />
) : (
<SortUpIcon className="w-4 h-4 text-gray-400" />
)
) : (
<SortIcon className="w-4 h-4 text-gray-400 opacity-0 group-hover:opacity-100" />
)}
</span>
</div>
</th>
))}
</tr>
))}
</thead>
<tbody
{...getTableBodyProps()}
className="bg-white divide-y divide-gray-200"
>
{page.map((row, i) => {
// new
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<td
{...cell.getCellProps()}
className="px-6 py-4 whitespace-nowrap"
role="cell"
>
{cell.column.Cell.name === "defaultRenderer" ? (
<div className="text-sm text-gray-500">
{cell.render("Cell")}
</div>
) : (
cell.render("Cell")
)}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* Pagination */}
<div className="py-3 flex items-center justify-between">
<div className="flex-1 flex justify-between sm:hidden">
<Button onClick={() => previousPage()} disabled={!canPreviousPage}>
Previous
</Button>
<Button onClick={() => nextPage()} disabled={!canNextPage}>
Next
</Button>
</div>
<div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
{/* pagintaion */}
<div className="flex gap-x-2 items-baseline">
<span className="text-sm text-gray-700">
صفحه <span className="font-medium">{state.pageIndex + 1}</span> از{" "}
<span className="font-medium">{pageOptions.length}</span>
</span>
<label>
<span className="sr-only">ایتم های صفحه</span>
<select
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
value={state.pageSize}
onChange={(e) => {
setPageSize(Number(e.target.value));
}}
>
{[5, 10, 20].map((pageSize) => (
<option key={pageSize} value={pageSize}>
نمایش {pageSize}
</option>
))}
</select>
</label>
</div>
{/* arrows */}
<div>
<nav
className="relative z-0 inline-flex rounded-md shadow-sm -space-x-px"
aria-label="Pagination"
>
<PageButton
className="rounded-r-md"
onClick={() => gotoPage(pageCount - 1)}
disabled={!canNextPage}
>
<span className="sr-only">Last</span>
<ChevronDoubleRightIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</PageButton>
<PageButton onClick={() => nextPage()} disabled={!canNextPage}>
<span className="sr-only">Next</span>
<ChevronRightIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</PageButton>
<PageButton
onClick={() => previousPage()}
disabled={!canPreviousPage}
>
<span className="sr-only">Previous</span>
<ChevronLeftIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</PageButton>
<PageButton
className="rounded-l-md"
onClick={() => gotoPage(0)}
disabled={!canPreviousPage}
>
<span className="sr-only">First</span>
<ChevronDoubleLeftIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</PageButton>
</nav>
</div>
</div>
</div>
</>
);
}
export default Table;

@ -0,0 +1,58 @@
import React from "react";
import Table, { AvatarCell, SelectColumnFilter, StatusPill } from "./Table"; // new
const getData = () => {
const data = [
{
name: "مایکروویر سامسونگ مدل ",
status: true,
date: "1400 / 09 / 21",
price: 20000,
},
{
name: "مایکروویر سامسونگ مدل ",
status: false,
date: "1400 / 09 / 21",
price: 20000,
},
];
return [...data, ...data, ...data];
};
function ReactTable() {
const columns = React.useMemo(
() => [
{
Header: "عنوان",
accessor: "name",
},
{
Header: "وضعیت",
accessor: "status",
},
{
Header: "تاریخ",
accessor: "date",
},
{
Header: "مبلغ پرداختی",
accessor: "price",
},
],
[]
);
const data = React.useMemo(() => getData(), []);
return (
<div className="min-h-screen bg-gray-100 text-gray-900">
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 pt-4">
<div className="mt-4">
<Table columns={columns} data={data} />
</div>
</main>
</div>
);
}
export default ReactTable;

@ -0,0 +1,35 @@
import React from 'react'
import { classNames } from './Utils'
export function Button({ children, className, ...rest }) {
return (
<button
type="button"
className={
classNames(
"relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50",
className
)}
{...rest}
>
{children}
</button>
)
}
export function PageButton({ children, className, ...rest }) {
return (
<button
type="button"
className={
classNames(
"relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50",
className
)}
{...rest}
>
{children}
</button>
)
}

@ -0,0 +1,17 @@
export function SortIcon({ className }) {
return (
<svg className={className} stroke="currentColor" fill="currentColor" strokeWidth="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M41 288h238c21.4 0 32.1 25.9 17 41L177 448c-9.4 9.4-24.6 9.4-33.9 0L24 329c-15.1-15.1-4.4-41 17-41zm255-105L177 64c-9.4-9.4-24.6-9.4-33.9 0L24 183c-15.1 15.1-4.4 41 17 41h238c21.4 0 32.1-25.9 17-41z"></path></svg>
)
}
export function SortUpIcon({ className }) {
return (
<svg className={className} stroke="currentColor" fill="currentColor" strokeWidth="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M279 224H41c-21.4 0-32.1-25.9-17-41L143 64c9.4-9.4 24.6-9.4 33.9 0l119 119c15.2 15.1 4.5 41-16.9 41z"></path></svg>
)
}
export function SortDownIcon({ className }) {
return (
<svg className={className} stroke="currentColor" fill="currentColor" strokeWidth="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M41 288h238c21.4 0 32.1 25.9 17 41L177 448c-9.4 9.4-24.6 9.4-33.9 0L24 329c-15.1-15.1-4.4-41 17-41z"></path></svg>
)
}

@ -0,0 +1,3 @@
export function classNames(...classes) {
return classes.filter(Boolean).join(" ");
}

@ -0,0 +1,305 @@
import React from "react";
import {
useTable,
useFilters,
useGlobalFilter,
useAsyncDebounce,
useSortBy,
usePagination,
} from "react-table";
import {
ChevronDoubleLeftIcon,
ChevronLeftIcon,
ChevronRightIcon,
ChevronDoubleRightIcon,
} from "@heroicons/react/solid";
import { Button, PageButton } from "./shared/Button";
import { classNames } from "./shared/Utils";
import { SortIcon, SortUpIcon, SortDownIcon } from "./shared/Icons";
// Define a default UI for filtering
function GlobalFilter({
preGlobalFilteredRows,
globalFilter,
setGlobalFilter,
}) {
const count = preGlobalFilteredRows.length;
const [value, setValue] = React.useState(globalFilter);
const onChange = useAsyncDebounce((value) => {
setGlobalFilter(value || undefined);
}, 200);
return (
<label className="flex gap-x-2 items-baseline">
<span className="text-gray-700">Search: </span>
<input
type="text"
className="rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
value={value || ""}
onChange={(e) => {
setValue(e.target.value);
onChange(e.target.value);
}}
placeholder={`${count} records...`}
/>
</label>
);
}
export function StatusPill({ value }) {
// const status = value ? value.toLowerCase() : "unknown";
return (
<span
className={`p-4 whitespace-nowrap text-base font-light
${value ? "text-green-400" : "text-red-400"}`}
>
{value ? "فعال" : "غیر فعال"}
</span>
);
}
// export function AvatarCell({ value, column, row }) {
// return (
// <div className="flex items-center">
// {/* برای عکس */}
// {/* <div className="flex-shrink-0 h-10 w-10">
// <img
// className="h-10 w-10 rounded-full"
// src={row.original[column.imgAccessor]}
// alt=""
// />
// </div> */}
// {/* اگر بخواهیم در کنار عنوان یک محتوا دیگه ای بنویسیم */}
// {/* <div className="ml-4">
// <div className="text-sm font-medium text-gray-900">{value}</div>
// <div className="text-sm text-gray-500">
// {row.original[column.emailAccessor]}
// </div>
// </div> */}
// </div>
// );
// }
function Table({ columns, data }) {
// Use the state and functions returned from useTable to build your UI
const {
getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
page, // Instead of using 'rows', we'll use page,
// which has only the rows for the active page
// The rest of these things are super handy, too ;)
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
state,
preGlobalFilteredRows,
setGlobalFilter,
} = useTable(
{
columns,
data,
},
useFilters, // useFilters!
useGlobalFilter,
useSortBy,
usePagination // new
);
// Render the UI for your table
return (
<>
<div className="sm:flex sm:gap-x-2">
<GlobalFilter
preGlobalFilteredRows={preGlobalFilteredRows}
globalFilter={state.globalFilter}
setGlobalFilter={setGlobalFilter}
/>
{headerGroups.map((headerGroup) =>
headerGroup.headers.map((column) =>
column.Filter ? (
<div className="mt-2 sm:mt-0" key={column.id}>
{column.render("Filter")}
</div>
) : null
)
)}
</div>
{/* table */}
<div className="mt-4 flex flex-col">
<div className="-my-2 overflow-x-auto -mx-4 sm:-mx-6 lg:-mx-8">
<div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
<div className="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
<table
{...getTableProps()}
className="min-w-full divide-y divide-gray-200"
>
<thead className="bg-gray-50">
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
// Add the sorting props to control sorting. For this example
// we can add them into the header props
<th
scope="col"
className="group px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
{...column.getHeaderProps(
column.getSortByToggleProps()
)}
>
<div className="flex items-center justify-between">
{column.render("Header")}
{/* Add a sort direction indicator */}
<span>
{column.isSorted ? (
column.isSortedDesc ? (
<SortDownIcon className="w-4 h-4 text-gray-400" />
) : (
<SortUpIcon className="w-4 h-4 text-gray-400" />
)
) : (
<SortIcon className="w-4 h-4 text-gray-400 opacity-0 group-hover:opacity-100" />
)}
</span>
</div>
</th>
))}
</tr>
))}
</thead>
<tbody
{...getTableBodyProps()}
className="bg-white divide-y divide-gray-200"
>
{page.map((row, i) => {
// new
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<td
{...cell.getCellProps()}
className="px-6 py-4 whitespace-nowrap"
role="cell"
>
{cell.column.Cell.name === "defaultRenderer" ? (
<div className="text-sm text-gray-500">
{cell.render("Cell")}
</div>
) : (
cell.render("Cell")
)}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* Pagination */}
<div className="py-3 flex items-center justify-between">
<div className="flex-1 flex justify-between sm:hidden">
<Button onClick={() => previousPage()} disabled={!canPreviousPage}>
Previous
</Button>
<Button onClick={() => nextPage()} disabled={!canNextPage}>
Next
</Button>
</div>
<div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
{/* numbers */}
<div className="flex gap-x-2 items-baseline">
<span className="text-sm text-gray-700">
صفحه <span className="font-medium">{state.pageIndex + 1}</span> از
<span className="font-medium">{pageOptions.length}</span>
</span>
<label>
<span className="sr-only">ایتم های موجود در هر صفحه</span>
<select
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
value={state.pageSize}
onChange={(e) => {
setPageSize(Number(e.target.value));
}}
>
{[5, 10, 20].map((pageSize) => (
<option key={pageSize} value={pageSize}>
نمایش {pageSize}
</option>
))}
</select>
</label>
</div>
{/* arrows */}
<div>
<nav
className="relative z-0 inline-flex rounded-md shadow-sm -space-x-px"
aria-label="Pagination"
>
<PageButton
className="rounded-l-md"
onClick={() => gotoPage(0)}
disabled={!canPreviousPage}
>
<span className="sr-only">First</span>
<ChevronDoubleRightIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</PageButton>
<PageButton
onClick={() => previousPage()}
disabled={!canPreviousPage}
>
<span className="sr-only">Previous</span>
<ChevronRightIcon
ChevronLeftIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</PageButton>
<PageButton onClick={() => nextPage()} disabled={!canNextPage}>
<span className="sr-only"> Next</span>
<ChevronLeftIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</PageButton>
<PageButton
className="rounded-r-md"
onClick={() => gotoPage(pageCount - 1)}
disabled={!canNextPage}
>
<span className="sr-only">Last</span>
<ChevronDoubleLeftIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</PageButton>
</nav>
</div>
</div>
</div>
</>
);
}
export default Table;

@ -0,0 +1,90 @@
import React from "react";
import Table, { AvatarCell, SelectColumnFilter, StatusPill } from "./Table"; // new
const getData = () => {
const data = [
{
name: "مایکروویر سامسونگ مدل ",
// email: "jane.cooper@example.com",
status: true,
date: "1400/09/21",
price: 20000,
// imgUrl:
// "https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=4&w=256&h=256&q=60",
},
{
name: "آزمون آنلاین درس علوم تجربی ",
status: false,
date: "1400/09/21",
price: 18000,
},
{
name: "مایکروویر سامسونگ مدل ",
status: true,
date: "1400/09/21",
price: 20000,
},
{
name: "آزمون آنلاین درس علوم تجربی ",
status: false,
date: "1400/09/21",
price: 18000,
},
{
name: "مایکروویر سامسونگ مدل ",
status: true,
date: "1400/09/21",
price: 27000000,
},
{
name: "آزمون آنلاین درس علوم تجربی ",
status: false,
date: "1400/09/21",
price: 1000,
},
];
return [...data, ...data, ...data];
};
const ReactTable2 = () => {
const columns = React.useMemo(
() => [
{
Header: "عنوان",
accessor: "name",
// اگر بخواهیم عکسی در جدول نشان بدیم یا یک محتوایی در کنار عنوان داشته باشیم اول باید اواتار سل رو در فایل تیبل جی اس ان کامنت کنیم و بعد ...
// Cell: AvatarCell,
// imgAccessor: "imgUrl",
// emailAccessor: "email",
},
{
Header: "وضعیت",
accessor: "status",
Cell: StatusPill,
},
{
Header: "تاریخ",
accessor: "date",
},
{
Header: "مبلغ پرداختی",
accessor: "price",
},
],
[]
);
const data = React.useMemo(() => getData(), []);
return (
<div className="min-h-screen bg-gray-100 text-gray-900">
<main className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 pt-4">
<div className="my-6">
<Table columns={columns} data={data} />
</div>
</main>
</div>
);
};
export default ReactTable2;

@ -0,0 +1,35 @@
import React from 'react'
import { classNames } from './Utils'
export function Button({ children, className, ...rest }) {
return (
<button
type="button"
className={
classNames(
"relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50",
className
)}
{...rest}
>
{children}
</button>
)
}
export function PageButton({ children, className, ...rest }) {
return (
<button
type="button"
className={
classNames(
"relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50",
className
)}
{...rest}
>
{children}
</button>
)
}

@ -0,0 +1,17 @@
export function SortIcon({ className }) {
return (
<svg className={className} stroke="currentColor" fill="currentColor" strokeWidth="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M41 288h238c21.4 0 32.1 25.9 17 41L177 448c-9.4 9.4-24.6 9.4-33.9 0L24 329c-15.1-15.1-4.4-41 17-41zm255-105L177 64c-9.4-9.4-24.6-9.4-33.9 0L24 183c-15.1 15.1-4.4 41 17 41h238c21.4 0 32.1-25.9 17-41z"></path></svg>
)
}
export function SortUpIcon({ className }) {
return (
<svg className={className} stroke="currentColor" fill="currentColor" strokeWidth="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M279 224H41c-21.4 0-32.1-25.9-17-41L143 64c9.4-9.4 24.6-9.4 33.9 0l119 119c15.2 15.1 4.5 41-16.9 41z"></path></svg>
)
}
export function SortDownIcon({ className }) {
return (
<svg className={className} stroke="currentColor" fill="currentColor" strokeWidth="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M41 288h238c21.4 0 32.1 25.9 17 41L177 448c-9.4 9.4-24.6 9.4-33.9 0L24 329c-15.1-15.1-4.4-41 17-41z"></path></svg>
)
}

@ -0,0 +1,3 @@
export function classNames(...classes) {
return classes.filter(Boolean).join(" ");
}

@ -1258,6 +1258,11 @@
dependencies:
"prop-types" "^15.7.2"
"@heroicons/react@^1.0.5":
"integrity" "sha512-UDMyLM2KavIu2vlWfMspapw9yii7aoLwzI2Hudx4fyoPwfKfxU8r3cL8dEBXOjcLG0/oOONZzbT14M1HoNtEcg=="
"resolved" "https://registry.npmjs.org/@heroicons/react/-/react-1.0.5.tgz"
"version" "1.0.5"
"@humanwhocodes/config-array@^0.9.2":
"integrity" "sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA=="
"resolved" "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz"

Loading…
Cancel
Save