From 6031795a4b124ea33a3f49e515af362764f428a1 Mon Sep 17 00:00:00 2001 From: Kuba Orlik Date: Mon, 10 Aug 2026 17:35:03 +0200 Subject: [PATCH] Add Subtree and related components --- src/back/jdd-components/buttons/buttons.css | 31 ++++++++++++++ .../jdd-components/buttons/buttons.jdd.tsx | 40 +++++++++++++++++++ .../empty-space/empty-space.jdd.tsx | 22 ++++++++++ src/back/jdd-components/heading/heading.css | 26 ++++++++++++ .../jdd-components/heading/heading.jdd.tsx | 32 +++++++++++++++ src/back/jdd-components/subtree/subtree.css | 20 ++++++++++ .../jdd-components/subtree/subtree.jdd.tsx | 40 +++++++++++++++++++ src/back/jdd-components/tekst/tekst.css | 8 ++++ src/back/jdd-components/tekst/tekst.jdd.tsx | 12 +++++- 9 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 src/back/jdd-components/buttons/buttons.css create mode 100644 src/back/jdd-components/buttons/buttons.jdd.tsx create mode 100644 src/back/jdd-components/empty-space/empty-space.jdd.tsx create mode 100644 src/back/jdd-components/heading/heading.css create mode 100644 src/back/jdd-components/heading/heading.jdd.tsx create mode 100644 src/back/jdd-components/subtree/subtree.css create mode 100644 src/back/jdd-components/subtree/subtree.jdd.tsx diff --git a/src/back/jdd-components/buttons/buttons.css b/src/back/jdd-components/buttons/buttons.css new file mode 100644 index 0000000..8b2029e --- /dev/null +++ b/src/back/jdd-components/buttons/buttons.css @@ -0,0 +1,31 @@ +.buttons { + display: flex; + + &.buttons--mode-row { + flex-flow: row wrap; + } + + &.buttons--mode-column { + flex-flow: column; + } + + &.buttons--gap-none { + gap: 0; + } + + &.buttons--gap-narrow { + gap: 8px; + } + + &.buttons--gap-medium { + gap: 16px; + } + + &.buttons--gap-wide { + gap: 24px; + } + + .button { + margin: 0; + } +} diff --git a/src/back/jdd-components/buttons/buttons.jdd.tsx b/src/back/jdd-components/buttons/buttons.jdd.tsx new file mode 100644 index 0000000..6672541 --- /dev/null +++ b/src/back/jdd-components/buttons/buttons.jdd.tsx @@ -0,0 +1,40 @@ +import { TempstreamJSX } from "tempstream"; +import type { ComponentToHTMLArgs } from "@sealcode/jdd"; +import { Component, ComponentArguments, insert_nbsp } from "@sealcode/jdd"; +import { button, button_variants } from "src/back/elements/button.js"; + +const component_arguments = { + mode: new ComponentArguments.Enum(["column", "row"]), + gap: new ComponentArguments.Enum(["none", "narrow", "medium", "wide"]), + buttons: new ComponentArguments.List( + new ComponentArguments.Structured({ + variant: new ComponentArguments.Enum(button_variants), + text: new ComponentArguments.ShortText(), + href: new ComponentArguments.ShortText(), + }) + ), +} as const; + +export class Buttons extends Component { + getArguments() { + return component_arguments; + } + + async toHTML({ + args: { buttons, mode, gap }, + classes, + }: ComponentToHTMLArgs): Promise { + return ( +
+ {buttons.map((b) => button({ ...b, text: insert_nbsp(b.text) }))} +
+ ); + } +} diff --git a/src/back/jdd-components/empty-space/empty-space.jdd.tsx b/src/back/jdd-components/empty-space/empty-space.jdd.tsx new file mode 100644 index 0000000..d3b1e4d --- /dev/null +++ b/src/back/jdd-components/empty-space/empty-space.jdd.tsx @@ -0,0 +1,22 @@ +import { TempstreamJSX } from "tempstream"; +import type { ComponentToHTMLArgs } from "@sealcode/jdd"; +import { Component, ComponentArguments } from "@sealcode/jdd"; + +const component_arguments = { + size: new ComponentArguments.Number(), +} as const; + +export class EmptySpace extends Component { + getArguments() { + return component_arguments; + } + + async toHTML({ + args: { size }, + classes, + }: ComponentToHTMLArgs): Promise { + return ( +
+ ); + } +} diff --git a/src/back/jdd-components/heading/heading.css b/src/back/jdd-components/heading/heading.css new file mode 100644 index 0000000..beb2f30 --- /dev/null +++ b/src/back/jdd-components/heading/heading.css @@ -0,0 +1,26 @@ +.heading { + & > * { + margin-top: 0; + margin-bottom: 0; + } + + &.heading--font-size-tiny > * { + font-size: 20px; + } + + &.heading--font-size-small > * { + font-size: 24px; + } + + &.heading--font-size-medium > * { + font-size: 32px; + } + + &.heading--font-size-large > * { + font-size: 48px; + } + + &.heading--font-size-extra_large > * { + font-size: 64px; + } +} diff --git a/src/back/jdd-components/heading/heading.jdd.tsx b/src/back/jdd-components/heading/heading.jdd.tsx new file mode 100644 index 0000000..59f7d58 --- /dev/null +++ b/src/back/jdd-components/heading/heading.jdd.tsx @@ -0,0 +1,32 @@ +import { TempstreamJSX } from "tempstream"; +import type { ComponentToHTMLArgs } from "@sealcode/jdd"; +import { Component, ComponentArguments, insert_nbsp } from "@sealcode/jdd"; + +const component_arguments = { + title: new ComponentArguments.ShortText(), + level: new ComponentArguments.Enum(["h1", "h2", "h3", "h4", "h5", "h6"]), + font_size: new ComponentArguments.Enum([ + "tiny", + "small", + "medium", + "large", + "extra_large", + ]), +} as const; + +export class Heading extends Component { + getArguments() { + return component_arguments; + } + + async toHTML({ + args: { title, level, font_size }, + classes, + }: ComponentToHTMLArgs): Promise { + return ( +
+ {`<${level}>${insert_nbsp(title)}`} +
+ ); + } +} diff --git a/src/back/jdd-components/subtree/subtree.css b/src/back/jdd-components/subtree/subtree.css new file mode 100644 index 0000000..dce8269 --- /dev/null +++ b/src/back/jdd-components/subtree/subtree.css @@ -0,0 +1,20 @@ +.subtree { + display: flex; + flex-flow: column; + + &.subtree--gap-none { + gap: 0px; + } + + &.subtree--gap-narrow { + gap: 8px; + } + + &.subtree--gap-medium { + gap: 16px; + } + + &.subtree--gap-wide { + gap: 24px; + } +} diff --git a/src/back/jdd-components/subtree/subtree.jdd.tsx b/src/back/jdd-components/subtree/subtree.jdd.tsx new file mode 100644 index 0000000..64ff246 --- /dev/null +++ b/src/back/jdd-components/subtree/subtree.jdd.tsx @@ -0,0 +1,40 @@ +import { TempstreamJSX } from "tempstream"; +import type { + ComponentToHTMLArgs, + ExtractStructuredComponentArgumentsParsed, + JDDContext, +} from "@sealcode/jdd"; +import { Component, ComponentArguments } from "@sealcode/jdd"; + +const component_arguments = { + gap: new ComponentArguments.Enum(["none", "narrow", "medium", "wide"]), + components: new ComponentArguments.List(new ComponentArguments.NestedComponent()), +} as const; + +export class Subtree extends Component { + getArguments() { + return component_arguments; + } + + getCSSClumps( + jdd_context: JDDContext, + args: ExtractStructuredComponentArgumentsParsed + ) { + const result = (args.components || []) + .map((component) => component.getCSSClumps(jdd_context)) + .flat(); + return result; + } + + async toHTML({ + args: { components, gap }, + classes, + jdd_context, + }: ComponentToHTMLArgs): Promise { + return ( +
+ {components?.map((component) => component.render(jdd_context))} +
+ ); + } +} diff --git a/src/back/jdd-components/tekst/tekst.css b/src/back/jdd-components/tekst/tekst.css index da51923..77abfb3 100644 --- a/src/back/jdd-components/tekst/tekst.css +++ b/src/back/jdd-components/tekst/tekst.css @@ -3,6 +3,14 @@ font-size: 16px; line-height: 24px; + &.tekst--size-small { + font-size: 14px; + } + + &.tekst--size-large { + font-size: 20px; + } + p { margin: 0; } diff --git a/src/back/jdd-components/tekst/tekst.jdd.tsx b/src/back/jdd-components/tekst/tekst.jdd.tsx index 0b3ea0a..48036e1 100644 --- a/src/back/jdd-components/tekst/tekst.jdd.tsx +++ b/src/back/jdd-components/tekst/tekst.jdd.tsx @@ -9,6 +9,9 @@ import { Component, ComponentArguments } from "@sealcode/jdd"; const component_arguments = { color: new ComponentArguments.Enum(["transparent", "normal", "accent", "accent2"]), + size: new ComponentArguments.Enum(["small", "normal", "large"]).setExampleValues([ + "normal", + ]), content: new ComponentArguments.Markdown(), side_content: new ComponentArguments.NestedComponent(), } as const; @@ -34,7 +37,7 @@ export class Tekst extends Component { } toHTML({ - args: { color, content, side_content }, + args: { color, content, side_content, size }, classes, jdd_context, index, @@ -42,7 +45,12 @@ export class Tekst extends Component { const { render_markdown, language } = jdd_context; return (
{side_content.isEmpty() ? (