Add sort for table

This commit is contained in:
Arnaud 2024-10-16 10:07:52 +02:00
parent 65465d813d
commit d7cd3c56fd
No known key found for this signature in database
GPG Key ID: 69D6CE281FCAE663
3 changed files with 136 additions and 9 deletions

View File

@ -1,30 +1,100 @@
import "./table.css"; import "./table.css";
import { Search } from "lucide-react"; import { ArrowDownUp, Search } from "lucide-react";
import { Row, RowProps } from "./Row"; 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 = { type Props = {
/** /**
* List of header names * 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; className?: string;
rows: ReactElement<RowProps, typeof Row>[]; 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 ( return (
<div className={`table-container ${className}`}> <div className={`table-container ${className}`}>
<table className={"table"}> <table className={"table"}>
<thead className="table-thead"> <thead className="table-thead">
<tr className="table-theadTr"> <tr className="table-theadTr">
{headers.map((col) => ( {headers.map((col, index) => {
<th className="table-theadTh" key={col}> const [name, sort] = Array.isArray(col) ? col : [col];
{col} const state = index === sortSelected[0] ? sortSelected[1] : "";
</th> 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> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@ -22,6 +22,7 @@
padding: 2rem; padding: 2rem;
border-radius: var(--codex-border-radius); border-radius: var(--codex-border-radius);
overflow-x: auto; overflow-x: auto;
overflow-y: hidden;
} }
.table-theadTr { .table-theadTr {
@ -36,3 +37,34 @@
text-align: left; text-align: left;
padding: 1rem; 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;
}

View File

@ -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 = { export const Empty: Story = {
args: { args: {
rows: [], rows: [],