restructure project, add claudemd

This commit is contained in:
2026-07-08 16:36:17 -04:00
parent a7964f9410
commit 2a5fbffaa2
315 changed files with 81075 additions and 0 deletions

126
web/kit/PrettyTable.tsx Normal file
View File

@@ -0,0 +1,126 @@
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;