Add sort for table
This commit is contained in:
parent
65465d813d
commit
d7cd3c56fd
|
@ -1,30 +1,100 @@
|
|||
import "./table.css";
|
||||
import { Search } from "lucide-react";
|
||||
import { ArrowDownUp, Search } from "lucide-react";
|
||||
import { Row, RowProps } from "./Row";
|
||||
import { Fragment, ReactElement } from "react";
|
||||
import { Fragment, ReactElement, useState } from "react";
|
||||
import { classnames } from "../utils/classnames";
|
||||
|
||||
type State = "asc" | "desc" | "";
|
||||
|
||||
type Props = {
|
||||
/**
|
||||
* List of header names
|
||||
* Can be a string array ["id", "actions"]
|
||||
* Or a tuple containing the sort function with the column
|
||||
* index in argument
|
||||
*/
|
||||
headers: string[];
|
||||
headers: string[] | [string, ((state: State) => void)?][];
|
||||
|
||||
/**
|
||||
* Default: -1
|
||||
*/
|
||||
defaultSortIndex?: number;
|
||||
|
||||
className?: string;
|
||||
|
||||
rows: ReactElement<RowProps, typeof Row>[];
|
||||
};
|
||||
|
||||
export function Table({ headers, rows, className = "" }: Props) {
|
||||
const nextState = (state: "asc" | "desc" | "") => {
|
||||
switch (state) {
|
||||
case "":
|
||||
return "desc";
|
||||
case "asc":
|
||||
return "";
|
||||
case "desc":
|
||||
return "asc";
|
||||
}
|
||||
};
|
||||
|
||||
export function Table({
|
||||
headers,
|
||||
rows,
|
||||
defaultSortIndex = -1,
|
||||
className = "",
|
||||
}: Props) {
|
||||
const [sortSelected, setSortSelected] = useState([defaultSortIndex, "asc"]);
|
||||
|
||||
const onFilterSelected = (col: number) => {
|
||||
const [currentCol, currentState] = sortSelected;
|
||||
|
||||
if (col !== currentCol) {
|
||||
setSortSelected([col, "desc"]);
|
||||
return;
|
||||
}
|
||||
|
||||
const nxt = nextState(currentState as State);
|
||||
|
||||
if (nxt === "") {
|
||||
setSortSelected([-1, ""]);
|
||||
} else {
|
||||
setSortSelected([col, nxt]);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`table-container ${className}`}>
|
||||
<table className={"table"}>
|
||||
<thead className="table-thead">
|
||||
<tr className="table-theadTr">
|
||||
{headers.map((col) => (
|
||||
<th className="table-theadTh" key={col}>
|
||||
{col}
|
||||
</th>
|
||||
))}
|
||||
{headers.map((col, index) => {
|
||||
const [name, sort] = Array.isArray(col) ? col : [col];
|
||||
const state = index === sortSelected[0] ? sortSelected[1] : "";
|
||||
const nxt = nextState(state as State);
|
||||
|
||||
return (
|
||||
<th
|
||||
className={classnames(
|
||||
["table-theadTh"],
|
||||
["table-theadTh--clickable", !!sort]
|
||||
)}
|
||||
key={name}
|
||||
onClick={() => {
|
||||
onFilterSelected(index);
|
||||
sort?.(nxt);
|
||||
}}
|
||||
>
|
||||
<div className="table-theadTh-content">
|
||||
<span>{name}</span>
|
||||
{sort && (
|
||||
<ArrowDownUp
|
||||
className={"table-theadTh-icon--" + state}
|
||||
size={"1rem"}
|
||||
></ArrowDownUp>
|
||||
)}
|
||||
</div>
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
padding: 2rem;
|
||||
border-radius: var(--codex-border-radius);
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.table-theadTr {
|
||||
|
@ -36,3 +37,34 @@
|
|||
text-align: left;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.table-theadTh--clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.table-theadTh-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.table-theadTh-content svg {
|
||||
position: relative;
|
||||
top: -2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.table-theadTh-content svg path {
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.35s;
|
||||
}
|
||||
|
||||
.table-theadTh-icon--desc path:nth-child(1),
|
||||
.table-theadTh-icon--desc path:nth-child(2) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.table-theadTh-icon--asc path:nth-child(3),
|
||||
.table-theadTh-icon--asc path:nth-child(4) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,31 @@ export const Scroll: Story = {
|
|||
},
|
||||
};
|
||||
|
||||
export const Sort: Story = {
|
||||
args: {
|
||||
className: "tableSmall",
|
||||
rows: [
|
||||
<Row
|
||||
cells={[
|
||||
<Cell>Ox45678FDGHJKLBSA22</Cell>,
|
||||
<Cell>My file</Cell>,
|
||||
<Cell>1</Cell>,
|
||||
<Cell>Some data</Cell>,
|
||||
]}
|
||||
></Row>,
|
||||
<Row
|
||||
cells={[
|
||||
<Cell>Ox45678FDGHJKLBSA23</Cell>,
|
||||
<Cell>My file</Cell>,
|
||||
<Cell>2</Cell>,
|
||||
<Cell>Some data</Cell>,
|
||||
]}
|
||||
></Row>,
|
||||
],
|
||||
headers: [["id"], ["title"], ["other", () => {}], ["actions"]],
|
||||
},
|
||||
};
|
||||
|
||||
export const Empty: Story = {
|
||||
args: {
|
||||
rows: [],
|
||||
|
|
Loading…
Reference in New Issue