Add horizontal scroller option to subtree

This commit is contained in:
Kuba Orlik 2026-08-10 22:15:59 +02:00
parent c7153b0729
commit f87ba31a0c
3 changed files with 146 additions and 9 deletions

View File

@ -1,6 +1,8 @@
.button {
--icon-width: 32px;
--gap: 8px;
border-radius: 0;
border: none;
padding: 8px 16px;
display: inline-flex;
flex-flow: row;

View File

@ -5,6 +5,14 @@
--horizontal-padding: 0px;
padding: var(--vertical-padding) var(--horizontal-padding);
&.subtree--bleed-bleed {
grid-column: bleed;
}
&.subtree--bleed-screen {
grid-column: screen;
}
&.subtree--gap-none {
gap: 0px;
}
@ -45,3 +53,65 @@
--vertical-padding: 96px;
}
}
.subtree--mode-horizontal-scroller {
.horizontal-scroller {
.next-button,
.prev-button {
display: none;
}
}
.horizontal-scroller.has-next .next-button,
.horizontal-scroller.has-prev .prev-button {
display: block;
}
.scroller-wrapper {
display: grid;
--button-width: 60px;
grid-template-columns:
calc(var(--button-width) / 2) calc(var(--button-width) / 2)
1fr calc(var(--button-width) / 2) calc(var(--button-width) / 2);
& > * {
grid-column: 2/5;
grid-row: 1/2;
}
.button-panel {
z-index: 2;
height: 100%;
display: flex;
align-items: center;
pointer-events: none;
&.button-panel--left {
grid-column: 1/3 !important;
grid-row: 1/2;
}
&.button-panel--right {
grid-column: 4/6 !important;
grid-row: 1/2;
}
.button {
font-weight: bold;
width: var(--button-width);
}
}
.horizontal-scroller__element {
width: var(--horizontal-scroller-item-width) !important;
max-width: calc(100cqw - 80px);
flex-shrink: 0;
container-type: inline-size;
flex-flow: column;
}
.horizontal-scroller__markers {
grid-row: 2/3;
}
}
}

View File

@ -5,8 +5,20 @@ import type {
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";
const component_arguments = {
mode: new ComponentArguments.Enum(["column", "horizontal-scroller"]).setExampleValues(
["column"]
),
scroller_mode_item_width: new ComponentArguments.Number().setExampleValues([320]),
scroller_mode_arrows_color: new ComponentArguments.Enum(
getColorVariables()
).setExampleValues(["--color-brand-accent"]),
bleed: new ComponentArguments.Enum(["none", "bleed", "screen"]).setExampleValues([
"none",
]),
gap: new ComponentArguments.Enum([
"none",
"narrow",
@ -40,19 +52,72 @@ export class Subtree extends Component<typeof component_arguments> {
}
async toHTML({
args: { components, gap, padding_vertical },
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})`,
`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}
>
</button>
</div>
<div class="button-panel button-panel--right">
<button
class="button next-button"
type="button"
data-action="horizontal-scroller#scrollRight"
style={button_styles}
>
</button>
</div>
{scroller}
{markers}
</div>
),
elements: components?.map((component) =>
component.render(jdd_context)
),
})}
</div>
);
}
return (
<div
class={[
"subtree",
`subtree--gap-${gap}`,
`subtree--padding-vertical-${padding_vertical}`,
...classes,
]}
>
<div class={cls}>
{components?.map((component) => component.render(jdd_context))}
</div>
);