127 lines
4.8 KiB
TypeScript
127 lines
4.8 KiB
TypeScript
import { createMemo, For } from "solid-js";
|
|
import {
|
|
AUTOTABLE_HEADER_COLOR_BLUE,
|
|
AUTOTABLE_HEADER_COLOR_DARK_BLUE,
|
|
AUTOTABLE_HEADER_COLOR_DEFAULT,
|
|
AUTOTABLE_HEADER_COLOR_GRAY,
|
|
AUTOTABLE_HEADER_COLOR_GREEN,
|
|
AUTOTABLE_SIZE_DEFAULT,
|
|
BODY_PADDING_CLS,
|
|
COL_POS_LEFT,
|
|
HEADER_COLOR_CLS,
|
|
HEADER_CONTENT,
|
|
HEADER_INNER_BASE,
|
|
HEADER_INNER_POS,
|
|
HEADER_PADDING_CLS,
|
|
HEADER_TEXT_CLS,
|
|
POS_CLS,
|
|
TBL_BASE,
|
|
TBL_CONTAINER,
|
|
TBL_WRAPPER,
|
|
type AutoTableHeaderColor,
|
|
type AutoTableSize,
|
|
type ColumnPosition,
|
|
} from "./AutoTable.tsx";
|
|
|
|
const PT_ROW_HOVER_CLS: Record<AutoTableHeaderColor, string> = {
|
|
[AUTOTABLE_HEADER_COLOR_DEFAULT]: "[&_tr:hover]:!bg-neutral-200",
|
|
[AUTOTABLE_HEADER_COLOR_BLUE]: "[&_tr:hover]:!bg-sky-100",
|
|
[AUTOTABLE_HEADER_COLOR_GREEN]: "[&_tr:hover]:!bg-green-100",
|
|
[AUTOTABLE_HEADER_COLOR_GRAY]: "[&_tr:hover]:!bg-neutral-200",
|
|
[AUTOTABLE_HEADER_COLOR_DARK_BLUE]: "[&_tr:hover]:!bg-sky-100",
|
|
};
|
|
|
|
export interface PrettyTableColumn {
|
|
displayName: string;
|
|
displayPosition?: ColumnPosition;
|
|
headerClasses?: string;
|
|
}
|
|
|
|
export interface PrettyTableOptions {
|
|
size?: AutoTableSize;
|
|
shadow?: boolean;
|
|
hover?: boolean;
|
|
alternate?: boolean;
|
|
headerBorderY?: boolean;
|
|
surroundingBorder?: boolean;
|
|
borderX?: boolean;
|
|
borderY?: boolean;
|
|
color?: AutoTableHeaderColor;
|
|
tableLayoutAuto?: boolean;
|
|
}
|
|
|
|
export interface PrettyTableProps {
|
|
columns: PrettyTableColumn[];
|
|
// Body rows: <tr>s built with AutoTable's TdLeft/TdRight/TdCenter cells.
|
|
children?: any;
|
|
options?: PrettyTableOptions;
|
|
}
|
|
|
|
export function PrettyTable(props: PrettyTableProps) {
|
|
const opts = createMemo(() => ({
|
|
size: AUTOTABLE_SIZE_DEFAULT,
|
|
shadow: false,
|
|
hover: false,
|
|
alternate: false,
|
|
headerBorderY: false,
|
|
surroundingBorder: false,
|
|
borderX: false,
|
|
borderY: false,
|
|
color: AUTOTABLE_HEADER_COLOR_DEFAULT,
|
|
tableLayoutAuto: false,
|
|
...props.options,
|
|
}));
|
|
|
|
const bodyClass = () => {
|
|
let c = BODY_PADDING_CLS[opts().size];
|
|
if (opts().borderY) c += " [&_td+td]:border-l [&_td+td]:border-neutral-300";
|
|
if (opts().alternate) c += " [&_tr:nth-child(even)]:bg-neutral-100";
|
|
if (opts().borderX) c += " [&_tr:not(:last-child)]:border-b [&_tr:not(:last-child)]:border-neutral-300";
|
|
if (opts().hover) c += " " + PT_ROW_HOVER_CLS[opts().color];
|
|
return c;
|
|
};
|
|
|
|
return (
|
|
<div class={TBL_CONTAINER
|
|
+ (opts().surroundingBorder ? " border border-neutral-300" : "")
|
|
+ (opts().shadow ? " shadow-sm" : "")}>
|
|
<div class={TBL_WRAPPER}>
|
|
<table class={TBL_BASE + (opts().tableLayoutAuto ? "" : " table-fixed")}>
|
|
<thead class="[&_th]:border-b [&_th]:border-neutral-300">
|
|
<tr>
|
|
<For each={props.columns}>
|
|
{(col: PrettyTableColumn, displayIdx: () => number) => {
|
|
const pos = col.displayPosition ?? COL_POS_LEFT;
|
|
const posCls = POS_CLS[pos];
|
|
const headerInnerPosCls = HEADER_INNER_POS[pos];
|
|
return (
|
|
<th
|
|
class={HEADER_PADDING_CLS[opts().size] + " " + HEADER_COLOR_CLS[opts().color]
|
|
+ (posCls ? " " + posCls : "")
|
|
+ (opts().headerBorderY && displayIdx() > 0 ? " border-l border-l-neutral-300" : "")
|
|
+ (col.headerClasses ? " " + col.headerClasses : "")}
|
|
>
|
|
<div class={HEADER_CONTENT}>
|
|
<div class={HEADER_INNER_BASE + (headerInnerPosCls ? " " + headerInnerPosCls : "")}>
|
|
<div class={"grow text-sm " + HEADER_TEXT_CLS[opts().color]}>
|
|
{col.displayName}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</th>
|
|
);
|
|
}}
|
|
</For>
|
|
</tr>
|
|
</thead>
|
|
<tbody class={bodyClass()}>
|
|
{props.children}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default PrettyTable;
|