master @ 88 LINES
[ HISTORY ] [ UP ]
┌─ ASTRO ────────────────────────────────────────────────────────────────────┐
│ --- │
│ import Pre from "../Pre/Pre.astro"; │
│ import TextField from "../TextField/TextField.astro"; │
│ import Select from "../Select/Select.astro"; │
│ import { selectWidth } from "../Select/Select"; │
│ import Radio from "../Radio/Radio.astro"; │
│ import { radioWidth } from "../Radio/Radio"; │
│ import Checkbox from "../Checkbox/Checkbox.astro"; │
│ import { checkboxWidth } from "../Checkbox/Checkbox"; │
│ import Button from "../Button/Button.astro"; │
│ import { buttonWidth } from "../Button/Button"; │
│ import { G, checkGrid, len, pad } from "../../lib/ascii"; │
│ import { MOBILE_FRAME_W } from "../../lib/config"; │
│ import { formGeometry, FORM_LABEL_W, FORM_INDENT, type Props } from "./FormFrame"; │
│ import "./FormFrame.scss"; │
│ │
│ const { title, fields, width = MOBILE_FRAME_W, action, method } = Astro.props as P │
│ rops; │
│ const { inner, contentW, defaultCells, textareaCells } = formGeometry(width); │
│ │
│ const ctx = `FormFrame(${title})`; │
│ const open = `${G.V}${" ".repeat(FORM_INDENT)}`; │
│ const close = (used: number) => `${" ".repeat(Math.max(0, contentW - used))}${G.V} │
│ `; │
│ const lbl = (s: string) => pad(s, FORM_LABEL_W); │
│ │
│ const top = checkGrid( │
│ `${G.TL}${G.H} ${title} ${G.H.repeat(Math.max(0, inner - 3 - len(title)))}${G.TR │
│ }`, │
│ width, │
│ ctx, │
│ ); │
│ const blank = `${G.V}${" ".repeat(inner)}${G.V}`; │
│ const bottom = `${G.BL}${G.H.repeat(inner)}${G.BR}`; │
│ --- │
│ <form class="form-frame" action={action} method={method}> │
│ <Pre>{top}</Pre> │
│ <Pre>{blank}</Pre> │
│ {fields.map((f) => { │
│ if (f.kind === "gap") return <Pre>{blank}</Pre>; │
│ │
│ if (f.kind === "text" || f.kind === "password") { │
│ const cells = f.cells ?? defaultCells; │
│ return <Pre>{open}{lbl(f.label)}<TextField name={f.name} cells={cells} type= │
│ {f.kind} />{close(FORM_LABEL_W + cells)}</Pre>; │
│ } │
│ │
│ if (f.kind === "select") { │
│ const cells = f.cells ?? defaultCells - 6; │
│ return <Pre>{open}{lbl(f.label)}<Select name={f.name} options={f.options} ce │
│ lls={cells} value={f.value} />{close(FORM_LABEL_W + selectWidth(cells))}</Pre>; │
│ } │
│ │
│ if (f.kind === "radios") { │
│ return f.options.map((opt, i) => ( │
│ <Pre>{open}{i === 0 ? lbl(f.label) : " ".repeat(FORM_LABEL_W)}<Radio label │
│ ={opt} name={f.name} value={opt.toLowerCase()} checked={f.value === opt} />{close( │
│ FORM_LABEL_W + radioWidth(opt))}</Pre> │
│ )); │
│ } │
│ │
│ if (f.kind === "checkbox") { │
│ return <Pre>{open}<Checkbox label={f.label} name={f.name} checked={f.checked │
│ } />{close(checkboxWidth(f.label))}</Pre>; │
│ } │
│ │
│ if (f.kind === "textarea") { │
│ const rows = f.rows ?? 4; │
│ return ( │
│ <Fragment> │
│ <Pre>{open}{checkGrid(f.label, contentW, ctx)}{close(len(f.label))}</Pre │
│ > │
│ <div class="form-textarea"> │
│ {Array.from({ length: rows }, () => ( │
│ <Pre>{blank}</Pre> │
│ ))} │
│ <textarea │
│ name={f.name} │
│ rows={rows} │
│ spellcheck="false" │
│ aria-label={f.label} │
│ style={`left: calc(var(--cell-w) * ${1 + FORM_INDENT}); width: calc( │
│ var(--cell-w) * ${textareaCells}); height: calc(var(--cell-h) * ${rows})`} │
│ ></textarea> │
│ </div> │
│ </Fragment> │
│ ); │
│ } │
│ │
│ const used = f.buttons.reduce((s, b, i) => s + buttonWidth(b.label) + (i ? 2 : │
│ 0), 0); │
│ return <Pre>{open}{f.buttons.map((b, i) => ( │
│ <Fragment>{i > 0 ? " " : ""}<Button label={b.label} type={b.type ?? "button │
│ "} variant={b.variant} /></Fragment> │
│ ))}{close(used)}</Pre>; │
│ })} │
│ <Pre>{blank}</Pre> │
│ <Pre>{bottom}</Pre> │
│ </form> │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ASTRO ──────────────────────────────┐
│ --- │
│ import Pre from "../Pre/Pre.astro"; │
│ import TextField from "../TextField/TextFiel │
│ d.astro"; │
│ import Select from "../Select/Select.astro"; │
│ import { selectWidth } from "../Select/Selec │
│ t"; │
│ import Radio from "../Radio/Radio.astro"; │
│ import { radioWidth } from "../Radio/Radio"; │
│ import Checkbox from "../Checkbox/Checkbox.a │
│ stro"; │
│ import { checkboxWidth } from "../Checkbox/C │
│ heckbox"; │
│ import Button from "../Button/Button.astro"; │
│ import { buttonWidth } from "../Button/Butto │
│ n"; │
│ import { G, checkGrid, len, pad } from "../. │
│ ./lib/ascii"; │
│ import { MOBILE_FRAME_W } from "../../lib/co │
│ nfig"; │
│ import { formGeometry, FORM_LABEL_W, FORM_IN │
│ DENT, type Props } from "./FormFrame"; │
│ import "./FormFrame.scss"; │
│ │
│ const { title, fields, width = MOBILE_FRAME_ │
│ W, action, method } = Astro.props as Props; │
│ const { inner, contentW, defaultCells, texta │
│ reaCells } = formGeometry(width); │
│ │
│ const ctx = `FormFrame(${title})`; │
│ const open = `${G.V}${" ".repeat(FORM_INDENT │
│ )}`; │
│ const close = (used: number) => `${" ".repea │
│ t(Math.max(0, contentW - used))}${G.V}`; │
│ const lbl = (s: string) => pad(s, FORM_LABEL │
│ _W); │
│ │
│ const top = checkGrid( │
│ `${G.TL}${G.H} ${title} ${G.H.repeat(Math. │
│ max(0, inner - 3 - len(title)))}${G.TR}`, │
│ width, │
│ ctx, │
│ ); │
│ const blank = `${G.V}${" ".repeat(inner)}${G │
│ .V}`; │
│ const bottom = `${G.BL}${G.H.repeat(inner)}$ │
│ {G.BR}`; │
│ --- │
│ <form class="form-frame" action={action} met │
│ hod={method}> │
│ <Pre>{top}</Pre> │
│ <Pre>{blank}</Pre> │
│ {fields.map((f) => { │
│ if (f.kind === "gap") return <Pre>{blank │
│ }</Pre>; │
│ │
│ if (f.kind === "text" || f.kind === "pas │
│ sword") { │
│ const cells = f.cells ?? defaultCells; │
│ return <Pre>{open}{lbl(f.label)}<TextF │
│ ield name={f.name} cells={cells} type={f.kin │
│ d} />{close(FORM_LABEL_W + cells)}</Pre>; │
│ } │
│ │
│ if (f.kind === "select") { │
│ const cells = f.cells ?? defaultCells │
│ - 6; │
│ return <Pre>{open}{lbl(f.label)}<Selec │
│ t name={f.name} options={f.options} cells={c │
│ ells} value={f.value} />{close(FORM_LABEL_W │
│ + selectWidth(cells))}</Pre>; │
│ } │
│ │
│ if (f.kind === "radios") { │
│ return f.options.map((opt, i) => ( │
│ <Pre>{open}{i === 0 ? lbl(f.label) : │
│ " ".repeat(FORM_LABEL_W)}<Radio label={opt} │
│ name={f.name} value={opt.toLowerCase()} che │
│ cked={f.value === opt} />{close(FORM_LABEL_W │
│ + radioWidth(opt))}</Pre> │
│ )); │
│ } │
│ │
│ if (f.kind === "checkbox") { │
│ return <Pre>{open}<Checkbox label={f.l │
│ abel} name={f.name} checked={f.checked} />{c │
│ lose(checkboxWidth(f.label))}</Pre>; │
│ } │
│ │
│ if (f.kind === "textarea") { │
│ const rows = f.rows ?? 4; │
│ return ( │
│ <Fragment> │
│ <Pre>{open}{checkGrid(f.label, con │
│ tentW, ctx)}{close(len(f.label))}</Pre> │
│ <div class="form-textarea"> │
│ {Array.from({ length: rows }, () │
│ => ( │
│ <Pre>{blank}</Pre> │
│ ))} │
│ <textarea │
│ name={f.name} │
│ rows={rows} │
│ spellcheck="false" │
│ aria-label={f.label} │
│ style={`left: calc(var(--cell- │
│ w) * ${1 + FORM_INDENT}); width: calc(var(-- │
│ cell-w) * ${textareaCells}); height: calc(va │
│ r(--cell-h) * ${rows})`} │
│ ></textarea> │
│ </div> │
│ </Fragment> │
│ ); │
│ } │
│ │
│ const used = f.buttons.reduce((s, b, i) │
│ => s + buttonWidth(b.label) + (i ? 2 : 0), 0 │
│ ); │
│ return <Pre>{open}{f.buttons.map((b, i) │
│ => ( │
│ <Fragment>{i > 0 ? " " : ""}<Button l │
│ abel={b.label} type={b.type ?? "button"} var │
│ iant={b.variant} /></Fragment> │
│ ))}{close(used)}</Pre>; │
│ })} │
│ <Pre>{blank}</Pre> │
│ <Pre>{bottom}</Pre> │
│ </form> │
└──────────────────────────────────────────────┘
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET