strona-czynna/src/back/routes/component-preview/component-input-table.tsx

226 lines
5.8 KiB
TypeScript

import type { Table, TableData } from "@sealcode/jdd";
import { isTableHeader } from "@sealcode/jdd";
import type { StatefulPage } from "@sealcode/sealgen";
import type { BaseContext } from "koa";
import { TempstreamJSX } from "tempstream";
import { makeJDDContext } from "../../jdd-context.js";
import { ComponentInput } from "./component-input.js";
import type { ComponentPreviewActions } from "./component-preview-actions.js";
import type { JDDPageState } from "./jdd-page.js";
import add_column_right_icon from "./table-add-column-right.svg";
import add_row_below_icon from "./table-add-row-below.svg";
import add_column_header_icon from "./table-add-row-header-below.svg";
import delete_column_icon from "./table-delete-column.svg";
import delete_row_icon from "./table-delete-row.svg";
import move_column_right_icon from "./table-move-column-right.svg";
import move_row_down_icon from "./table-move-row-down.svg";
export async function ComponentInputTable<
State extends JDDPageState,
CellType,
HeaderType
>({
state,
arg_path,
ctx,
arg,
value,
page,
}: {
state: State;
ctx: BaseContext;
arg_path: string[];
arg: Table<CellType, HeaderType>;
value: TableData<CellType, HeaderType>;
page: StatefulPage<JDDPageState, typeof ComponentPreviewActions>;
}): Promise<import("stream").Readable> {
if (!value) {
value = await arg.getEmptyValue(makeJDDContext(ctx));
}
return (
<fieldset>
<legend>{arg_path.at(-1)}</legend>
<div>
<table style="position: relative; /* necessary for sticky th*/">
<tbody>
<tr>
<td></td>
{[...Array(arg.getColumnsCount(value)).keys()].map(
(column_index) => (
<th class="sticky sticky--top subdued">
{page.makeActionButton(
state,
{
action: "remove_table_column",
label: "Remove column",
content: /* HTML */ `<img
width="20"
height="20"
src="${delete_column_icon.url}"
/>`,
},
arg_path,
column_index
)}
{column_index >= arg.getColumnsCount(value) - 1
? ""
: page.makeActionButton(
state,
{
action: "move_table_column_right",
label: "Move column to the right",
content: /* HTML */ `<img
width="20"
height="20"
src="${move_column_right_icon.url}"
/>`,
},
arg_path,
column_index
)}
</th>
)
)}
</tr>
{value.rows.map((row, row_index) => (
<tr>
<td class="sticky sticky--left subdued">
<div style="display: flex; flex-flow: column; row-gap: 5px;">
{page.makeActionButton(
state,
{
action: "remove_table_row",
label: "Remove row",
content: /* HTML */ `<img
width="20"
height="20"
src="${delete_row_icon.url}"
/>`,
},
arg_path,
row_index
)}
{page.makeActionButton(
state,
{
action: "move_table_row_down",
label: "Move this row down",
content: /* HTML */ `<img
width="20"
height="20"
src="${move_row_down_icon.url}"
/>`,
},
arg_path,
row_index
)}
</div>
</td>
{isTableHeader(row) ? (
<th colspan={arg.getColumnsCount(value).toString()}>
<ComponentInput
{...{
state,
ctx,
arg_path: [
...arg_path,
"rows",
row_index.toString(),
"header_content",
],
arg: arg.header_type,
value: row.header_content,
page,
}}
/>
</th>
) : (
row.cells.map((cell, cell_index) => (
<td>
<ComponentInput
{...{
ctx,
state,
arg_path: [
...arg_path,
"rows",
row_index.toString(),
"cells",
cell_index.toString(),
],
arg: arg.cell_type,
value: cell,
page,
}}
/>
</td>
))
)}
{row_index == 0 ? (
<td
class="subdued"
rowspan={value.rows.length.toString()}
>
{page.makeActionButton(
state,
{
action: "add_table_column",
label: "Add column",
content: /* HTML */ `<img
width="20"
height="20"
src="${add_column_right_icon.url}"
/>`,
},
arg_path
)}
</td>
) : (
""
)}
</tr>
))}
<tr>
<td
class="subdued"
colspan={(arg.getColumnsCount(value) + 1).toString()}
>
{page.makeActionButton(
state,
{
action: "add_table_row",
label: "Add table row",
content: /* HTML */ `<img
width="20"
height="20"
src="${add_row_below_icon.url}"
/>`,
},
arg_path,
arg.getColumnsCount(value)
)}
{page.makeActionButton(
state,
{
action: "add_table_row",
label: "Add table header",
content: /* HTML */ `<img
width="20"
height="20"
src="${add_column_header_icon.url}"
/>`,
},
arg_path,
arg.getColumnsCount(value),
"header"
)}
</td>
</tr>
</tbody>
</table>
</div>
</fieldset>
);
}