127 lines
3.3 KiB
TypeScript
127 lines
3.3 KiB
TypeScript
import { TempstreamJSX } from "tempstream";
|
|
import type {
|
|
ComponentToHTMLArgs,
|
|
ExtractStructuredComponentArgumentsParsed,
|
|
JDDContext,
|
|
} from "@sealcode/jdd";
|
|
import { Component, ComponentArguments } from "@sealcode/jdd";
|
|
import { horizontalScroller } from "src/back/routes/common/horizontal-scroller/horizontal-scroller.js";
|
|
import { getColorVariables, getFgColorVariable } from "src/back/colors.js";
|
|
import { icon } from "src/back/icons.js";
|
|
|
|
const component_arguments = {
|
|
mode: new ComponentArguments.Enum(["column", "horizontal-scroller"]).setDefaultValue(
|
|
"column"
|
|
),
|
|
scroller_mode_item_width: new ComponentArguments.Number().setDefaultValue(320),
|
|
scroller_mode_arrows_color: new ComponentArguments.Enum(
|
|
getColorVariables()
|
|
).setDefaultValue("--color-brand-accent"),
|
|
bleed: new ComponentArguments.Enum(["none", "bleed", "screen"]).setDefaultValue(
|
|
"none"
|
|
),
|
|
gap: new ComponentArguments.Enum([
|
|
"none",
|
|
"narrow",
|
|
"medium",
|
|
"wide",
|
|
]).setDefaultValue("medium"),
|
|
padding_vertical: new ComponentArguments.Enum([
|
|
"none",
|
|
"narrow",
|
|
"medium",
|
|
"wide",
|
|
"extra-wide",
|
|
"super-wide",
|
|
]).setDefaultValue("medium"),
|
|
components: new ComponentArguments.List(new ComponentArguments.NestedComponent()),
|
|
} as const;
|
|
|
|
export class Subtree extends Component<typeof component_arguments> {
|
|
getArguments() {
|
|
return component_arguments;
|
|
}
|
|
|
|
getCSSClumps(
|
|
jdd_context: JDDContext,
|
|
args: ExtractStructuredComponentArgumentsParsed<typeof component_arguments>
|
|
) {
|
|
const result = (args.components || [])
|
|
.map((component) => component.getCSSClumps(jdd_context))
|
|
.flat();
|
|
return result;
|
|
}
|
|
|
|
async toHTML({
|
|
args: {
|
|
mode,
|
|
components,
|
|
gap,
|
|
padding_vertical,
|
|
bleed,
|
|
scroller_mode_item_width,
|
|
scroller_mode_arrows_color,
|
|
},
|
|
classes,
|
|
jdd_context,
|
|
}: ComponentToHTMLArgs<typeof component_arguments>): Promise<string> {
|
|
const cls = [
|
|
"subtree",
|
|
`subtree--gap-${gap}`,
|
|
`subtree--padding-vertical-${padding_vertical}`,
|
|
`subtree--mode-${mode}`,
|
|
`subtree--bleed-${bleed}`,
|
|
...classes,
|
|
];
|
|
if (mode == "horizontal-scroller") {
|
|
const button_styles = [
|
|
`background-color: var(${scroller_mode_arrows_color})`,
|
|
`--fg-color: var(${getFgColorVariable(scroller_mode_arrows_color)})`,
|
|
].join(";");
|
|
return (
|
|
<div
|
|
class={cls}
|
|
style={`--horizontal-scroller-item-width: ${scroller_mode_item_width}px;`}
|
|
>
|
|
{horizontalScroller({
|
|
render: async ({ scroller, markers }) => (
|
|
<div class="scroller-wrapper">
|
|
<div class="button-panel button-panel--left">
|
|
<button
|
|
class="button prev-button"
|
|
type="button"
|
|
data-action="horizontal-scroller#scrollLeft"
|
|
style={button_styles}
|
|
>
|
|
{icon("arrow-left")}
|
|
</button>
|
|
</div>
|
|
<div class="button-panel button-panel--right">
|
|
<button
|
|
class="button next-button"
|
|
type="button"
|
|
data-action="horizontal-scroller#scrollRight"
|
|
style={button_styles}
|
|
>
|
|
{icon("arrow-right")}
|
|
</button>
|
|
</div>
|
|
{scroller}
|
|
{markers}
|
|
</div>
|
|
),
|
|
elements: components?.map((component) =>
|
|
component.render(jdd_context)
|
|
),
|
|
})}
|
|
</div>
|
|
);
|
|
}
|
|
return (
|
|
<div class={cls}>
|
|
{components?.map((component) => component.render(jdd_context))}
|
|
</div>
|
|
);
|
|
}
|
|
}
|