From c891612006a44519868be37068347399e8e8374f Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Tue, 17 Dec 2024 16:56:07 +0100 Subject: [PATCH 1/3] UI/chore: init typography xxs body --- .../Typography/css/typography-hierarchy/typography-body.css | 6 ++++++ pkgs/webview-ui/app/src/components/Typography/index.tsx | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/typography-body.css b/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/typography-body.css index 57a3e18f3..53014bb37 100644 --- a/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/typography-body.css +++ b/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/typography-body.css @@ -15,3 +15,9 @@ line-height: 132%; letter-spacing: 3%; } + +.fnt-body-xxs { + font-size: 0.6875rem; + line-height: 132%; + letter-spacing: 0.00688rem; +} diff --git a/pkgs/webview-ui/app/src/components/Typography/index.tsx b/pkgs/webview-ui/app/src/components/Typography/index.tsx index 250b88934..fe138cf9f 100644 --- a/pkgs/webview-ui/app/src/components/Typography/index.tsx +++ b/pkgs/webview-ui/app/src/components/Typography/index.tsx @@ -24,6 +24,7 @@ interface SizeForHierarchy { body: { default: string; xs: string; + xxs: string; s: string; }; headline: { @@ -43,10 +44,9 @@ type AllowedSizes = keyof SizeForHierarchy[H]; const sizeHierarchyMap: SizeForHierarchy = { body: { default: cx("fnt-body-default"), - xs: cx("fnt-body-xs"), s: cx("fnt-body-s"), - // m: cx("fnt-body-m"), - // l: cx("fnt-body-l"), + xs: cx("fnt-body-xs"), + xxs: cx("fnt-body-xxs"), }, headline: { default: cx("fnt-headline-default"), From 0a31552661c45d5f69bfd5ba6d374c525186da92 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Tue, 17 Dec 2024 16:58:06 +0100 Subject: [PATCH 2/3] UI: init {InputBase,InputLabel} --- .../app/src/components/inputBase/index.tsx | 146 ++++++++++++++++++ pkgs/webview-ui/app/src/index.tsx | 7 + .../app/src/routes/components/index.tsx | 118 ++++++++++++++ 3 files changed, 271 insertions(+) create mode 100644 pkgs/webview-ui/app/src/components/inputBase/index.tsx create mode 100644 pkgs/webview-ui/app/src/routes/components/index.tsx diff --git a/pkgs/webview-ui/app/src/components/inputBase/index.tsx b/pkgs/webview-ui/app/src/components/inputBase/index.tsx new file mode 100644 index 000000000..7a1ed0d2d --- /dev/null +++ b/pkgs/webview-ui/app/src/components/inputBase/index.tsx @@ -0,0 +1,146 @@ +import cx from "classnames"; +import { createEffect, JSX, splitProps } from "solid-js"; +import Icon, { IconVariant } from "../icon"; +import { Typography } from "../Typography"; + +type Variants = "outlined" | "ghost"; +interface InputBaseProps { + variant?: Variants; + value?: string; + inputProps?: JSX.InputHTMLAttributes; + required?: boolean; + type?: string; + inlineLabel?: JSX.Element; + class?: string; + placeholder?: string; + disabled?: boolean; + readonly?: boolean; + error?: boolean; + icon?: IconVariant; +} + +const variantBorder: Record = { + outlined: "border border-inv-3", + ghost: "", +}; + +const fgStateClasses = cx("aria-disabled:fg-def-4 aria-readonly:fg-def-3"); + +export const InputBase = (props: InputBaseProps) => { + const [, inputProps] = splitProps(props, ["class"]); + + createEffect(() => { + console.log("InputBase", props.value, props.variant); + }); + return ( +
+ {props.icon && ( + + + + )} + +
+ ); +}; + +interface InputLabelProps extends JSX.LabelHTMLAttributes { + description?: string; + required?: boolean; + error?: boolean; + help?: string; +} +export const InputLabel = (props: InputLabelProps) => { + const [labelProps, forwardProps] = splitProps(props, ["class"]); + return ( + + ); +}; diff --git a/pkgs/webview-ui/app/src/index.tsx b/pkgs/webview-ui/app/src/index.tsx index d6014c84b..37849ee84 100644 --- a/pkgs/webview-ui/app/src/index.tsx +++ b/pkgs/webview-ui/app/src/index.tsx @@ -20,6 +20,7 @@ import { ModuleDetails } from "./routes/modules/details"; import { ModuleDetails as AddModule } from "./routes/modules/add"; import { ApiTester } from "./api_test"; import { IconVariant } from "./components/icon"; +import { Components } from "./routes/components"; export const client = new QueryClient(); @@ -157,6 +158,12 @@ export const routes: AppRoute[] = [ hidden: false, component: () => , }, + { + path: "/components", + label: "Components", + hidden: false, + component: () => , + }, ], }, ]; diff --git a/pkgs/webview-ui/app/src/routes/components/index.tsx b/pkgs/webview-ui/app/src/routes/components/index.tsx new file mode 100644 index 000000000..9c49a17e7 --- /dev/null +++ b/pkgs/webview-ui/app/src/routes/components/index.tsx @@ -0,0 +1,118 @@ +import { Button } from "@/src/components/button"; +import { InputBase, InputLabel } from "@/src/components/inputBase"; +import { TextInput } from "@/src/Form/fields"; +import { Header } from "@/src/layout/header"; +import { createForm, required } from "@modular-forms/solid"; + +const disabled = [false, true]; +const readOnly = [false, true]; +const error = [false, true]; + +export const Components = () => { + const [formStore, { Form, Field }] = createForm<{ ef: string }>({}); + return ( + <> +
+ +
+ Input + + Default + Size S + + {disabled.map((disabled) => + readOnly.map((readOnly) => + error.map((hasError) => ( + <> + + {[ + disabled ? "Disabled" : "(default)", + readOnly ? "ReadOnly" : "", + hasError ? "Error" : "", + ] + .filter(Boolean) + .join(" + ")} + + + + )) + ) + )} + Input Ghost + {disabled.map((disabled) => + readOnly.map((readOnly) => + error.map((hasError) => ( + <> + + {[ + disabled ? "Disabled" : "(default)", + readOnly ? "ReadOnly" : "", + hasError ? "Error" : "", + ] + .filter(Boolean) + .join(" + ")} + + + + )) + ) + )} + Input Label + Default + Labeltext + Required + Labeltext + Error + Labeltext + Error + Reuired + + Labeltext + + Icon + Labeltext + Description + Labeltext +
+
+ Form Layout + +
{ + console.log("Nothing"); + }} + > + + {(field, inputProps) => ( + + )} + + +
+ +
+ + ); +}; From f492601d7b1c5144cc6baccf79d81d765c03b523 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Tue, 17 Dec 2024 19:37:07 +0100 Subject: [PATCH 3/3] UI: replace TextInput with simple Layout of InputBase, InputLabel, ErrorMessage --- .../app/src/Form/fields/TextInput.tsx | 76 +++++++++---------- pkgs/webview-ui/app/src/api_test.tsx | 4 +- .../app/src/components/TextInput.tsx | 72 ------------------ .../app/src/components/inputBase/index.tsx | 2 +- .../app/src/routes/clans/create.tsx | 3 +- .../app/src/routes/clans/details.tsx | 9 ++- .../app/src/routes/components/index.tsx | 10 +-- pkgs/webview-ui/app/src/routes/flash/view.tsx | 6 +- .../app/src/routes/machines/create.tsx | 7 +- .../app/src/routes/machines/details.tsx | 60 ++++++++------- .../app/src/routes/modules/details.tsx | 20 +---- 11 files changed, 85 insertions(+), 184 deletions(-) delete mode 100644 pkgs/webview-ui/app/src/components/TextInput.tsx diff --git a/pkgs/webview-ui/app/src/Form/fields/TextInput.tsx b/pkgs/webview-ui/app/src/Form/fields/TextInput.tsx index 96e665eaf..74640f345 100644 --- a/pkgs/webview-ui/app/src/Form/fields/TextInput.tsx +++ b/pkgs/webview-ui/app/src/Form/fields/TextInput.tsx @@ -1,6 +1,8 @@ import { createEffect, Show, type JSX } from "solid-js"; import cx from "classnames"; import { Label } from "../base/label"; +import { InputBase, InputLabel } from "@/src/components/inputBase"; +import { Typography } from "@/src/components/Typography"; interface TextInputProps { value: string; @@ -22,49 +24,39 @@ interface TextInputProps { } export function TextInput(props: TextInputProps) { - const value = () => props.value; - + // createEffect(() => { + // console.log("TextInput", props.error, props.value); + // }); return ( - + + {props.label} + + + {props.error && ( + + {props.error} + + )} + ); } diff --git a/pkgs/webview-ui/app/src/api_test.tsx b/pkgs/webview-ui/app/src/api_test.tsx index 0fc9a6648..299de699f 100644 --- a/pkgs/webview-ui/app/src/api_test.tsx +++ b/pkgs/webview-ui/app/src/api_test.tsx @@ -4,7 +4,7 @@ import { getValues, SubmitHandler, } from "@modular-forms/solid"; -import { TextInput } from "./components/TextInput"; +import { TextInput } from "@/src/Form/fields/TextInput"; import { Button } from "./components/button"; import { callApi } from "./api"; import { API } from "@/api/API"; @@ -68,7 +68,6 @@ export const ApiTester = () => { label={"endpoint"} value={field.value || ""} inputProps={fieldProps} - formStore={formStore} /> )} @@ -78,7 +77,6 @@ export const ApiTester = () => { label={"payload"} value={field.value || ""} inputProps={fieldProps} - formStore={formStore} /> )} diff --git a/pkgs/webview-ui/app/src/components/TextInput.tsx b/pkgs/webview-ui/app/src/components/TextInput.tsx deleted file mode 100644 index 43f24c861..000000000 --- a/pkgs/webview-ui/app/src/components/TextInput.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { FieldValues, FormStore, ResponseData } from "@modular-forms/solid"; -import { Show, type JSX } from "solid-js"; -import cx from "classnames"; - -interface TextInputProps { - formStore: FormStore; - value: string; - inputProps: JSX.InputHTMLAttributes; - label: JSX.Element; - error?: string; - required?: boolean; - type?: string; - inlineLabel?: JSX.Element; - class?: string; - adornment?: { - position: "start" | "end"; - content: JSX.Element; - }; - placeholder?: string; -} - -export function TextInput( - props: TextInputProps, -) { - const value = () => props.value; - - return ( - - ); -} diff --git a/pkgs/webview-ui/app/src/components/inputBase/index.tsx b/pkgs/webview-ui/app/src/components/inputBase/index.tsx index 7a1ed0d2d..728a72451 100644 --- a/pkgs/webview-ui/app/src/components/inputBase/index.tsx +++ b/pkgs/webview-ui/app/src/components/inputBase/index.tsx @@ -56,7 +56,7 @@ export const InputBase = (props: InputBaseProps) => { // Cursor "aria-readonly:cursor-no-drop", - props.class + props.class, )} classList={{ [cx("!border !border-semantic-1 !outline-semantic-1")]: !!props.error, diff --git a/pkgs/webview-ui/app/src/routes/clans/create.tsx b/pkgs/webview-ui/app/src/routes/clans/create.tsx index b7ac26f65..022c42045 100644 --- a/pkgs/webview-ui/app/src/routes/clans/create.tsx +++ b/pkgs/webview-ui/app/src/routes/clans/create.tsx @@ -8,7 +8,7 @@ import { } from "@modular-forms/solid"; import toast from "solid-toast"; import { setActiveURI, setClanList } from "@/src/App"; -import { TextInput } from "@/src/components/TextInput"; +import { TextInput } from "@/src/Form/fields/TextInput"; import { useNavigate } from "@solidjs/router"; import { Button } from "@/src/components/button"; import Icon from "@/src/components/icon"; @@ -165,7 +165,6 @@ export const CreateClan = () => { ), position: "start", }} - formStore={formStore} inputProps={props} label="Template to use" value={field.value ?? ""} diff --git a/pkgs/webview-ui/app/src/routes/clans/details.tsx b/pkgs/webview-ui/app/src/routes/clans/details.tsx index a86a6432f..7a11eacac 100644 --- a/pkgs/webview-ui/app/src/routes/clans/details.tsx +++ b/pkgs/webview-ui/app/src/routes/clans/details.tsx @@ -11,7 +11,7 @@ import { setValue, SubmitHandler, } from "@modular-forms/solid"; -import { TextInput } from "@/src/components/TextInput"; +import { TextInput } from "@/src/Form/fields/TextInput"; import toast from "solid-toast"; import { set_single_service } from "@/src/api/inventory"; import { Button } from "@/src/components/button"; @@ -215,7 +215,6 @@ const AdminModuleForm = (props: AdminModuleFormProps) => { {(field, props) => ( { {(field, props) => ( <> { class="col-span-6" required /> - +