Panel
A bordered box in three parts: a header bar with a title and controls, a body, and a footer bar for actions.
Demo
Members
3 of 5 seats used
Ada LovelaceOwner
Grace HopperAdmin
Linus TorvaldsMember
Danger zone
Delete this project
Transfer ownership
Activity
Live
A tinted header, no footer.
Get it
It needs theme.qwe, as every component does; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.
$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/panel.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/panel.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/panel.qwe
let panel_demo_people = [["Ada Lovelace", "Owner"], ["Grace Hopper", "Admin"], ["Linus Torvalds", "Member"]]view PanelDemo() = <div.demo-stack> <Panel id="panel-demo-members" title="Members" subtitle="3 of 5 seats used" header={[<SearchInput name="q" field="panel-demo-q" placeholder="Find a person" size="sm"/>, <Button size="sm" id="panel-demo-invite">Invite</Button>]} footer={[<Button variant="ghost" size="sm">Cancel</Button>, <Button size="sm">Save</Button>]}> {for [n, r] in panel_demo_people => <div style="display: flex; justify-content: space-between; padding: 6px 0"><span>{n}</span><span style="color: var(--ui-muted)">{r}</span></div>} </Panel> <Grid columns={2}> <Panel id="panel-demo-danger" title="Danger zone" tone="danger" padding="none" footer={<span style="font-size: 13px; color: var(--ui-muted)">These cannot be undone.</span>} footer_align="start"> <div style="padding: 14px 16px; border-bottom: 1px solid var(--ui-border); display: flex; justify-content: space-between; align-items: center"> <span>Delete this project</span><Button tone="danger" variant="outline" size="sm">Delete</Button> </div> <div style="padding: 14px 16px; display: flex; justify-content: space-between; align-items: center"> <span>Transfer ownership</span><Button variant="outline" size="sm">Transfer</Button> </div> </Panel> <Panel id="panel-demo-subtle" title="Activity" tone="subtle" header={<Badge>Live</Badge>}> <p>A tinted header, no footer.</p> </Panel> </Grid> </div>Source
ui/panel.qwe
// Panel: a bordered box in three parts: a header bar with a title and room for// controls, a body, and a footer bar for actions. For a settings block, a table// with its toolbar, a form with its buttons.//// <Panel title="Members" header={<Button size="sm">Invite</Button>} footer={<Pagination .../>}>// <DataTable .../>// </Panel>// <Panel title="Danger zone" tone="danger" padding="none"> ... </Panel>//// title: its heading (an <h3>); subtitle: a line under it. header: HTML at the end of// the header bar (buttons, a search, a badge). footer: HTML in the footer bar, at the// right unless footer_align is "start" or "between". children: the body.// padding: the body's, "none" (for a table or a list that fills it), "sm", "md"// (default) or "lg". tone: "neutral" (default), "accent", "danger" or "subtle" (a// tinted header). id: the panel's id; its heading then names it for screen readers.import ui/theme.qwe use ui_clslet panel_css = css`.ui-panel { --ui-panel-pad: 20px; display: flex; flex-direction: column; min-width: 0; border: 1px solid var(--ui-border); border-radius: var(--ui-radius); background: var(--ui-surface); color: var(--ui-fg); font: 15px/1.5 var(--ui-font);}.ui-panel-pad-none { --ui-panel-pad: 0; }.ui-panel-pad-sm { --ui-panel-pad: 12px; }.ui-panel-pad-lg { --ui-panel-pad: 28px; }.ui-panel-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; min-height: 52px; padding: 10px 16px; border-bottom: 1px solid var(--ui-border);}.ui-panel-title { margin: 0; font-size: 15px; font-weight: 600; line-height: 1.35; }.ui-panel-sub { margin: 1px 0 0; color: var(--ui-muted); font-size: 13px; }.ui-panel-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-left: auto; }.ui-panel-body { flex: 1; padding: var(--ui-panel-pad); }.ui-panel-body > :first-child { margin-top: 0; }.ui-panel-body > :last-child { margin-bottom: 0; }.ui-panel-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 8px; padding: 10px 16px; border-top: 1px solid var(--ui-border); background: var(--ui-subtle); border-radius: 0 0 var(--ui-radius) var(--ui-radius);}.ui-panel-foot-start { justify-content: flex-start; }.ui-panel-foot-between { justify-content: space-between; }.ui-panel-subtle .ui-panel-head { background: var(--ui-subtle); border-radius: var(--ui-radius) var(--ui-radius) 0 0; }.ui-panel-accent { border-color: color-mix(in srgb, var(--ui-accent) 45%, var(--ui-border)); }.ui-panel-accent .ui-panel-head { background: var(--ui-accent-soft); color: var(--ui-accent); border-radius: var(--ui-radius) var(--ui-radius) 0 0; }.ui-panel-accent .ui-panel-sub { color: inherit; opacity: .8; }.ui-panel-danger { border-color: color-mix(in srgb, var(--ui-danger) 45%, var(--ui-border)); }.ui-panel-danger .ui-panel-head { background: var(--ui-danger-soft); color: var(--ui-danger); border-radius: var(--ui-radius) var(--ui-radius) 0 0; }.ui-panel-danger .ui-panel-sub { color: inherit; opacity: .8; }`view Panel(title: str? = null, subtitle: str? = null, header = null, footer = null, footer_align: str = "end", padding: str = "md", tone: str = "neutral", id: str? = null, class: str? = null, children) { style global panel_css let hid = id != null && title != null ? `${id}-title` : null <section class={ui_cls(["ui-panel", padding != "md" && `ui-panel-pad-${padding}`, tone != "neutral" && `ui-panel-${tone}`, class])} id={id} aria-labelledby={hid}> {(title != null || subtitle != null || header != null) && <header.ui-panel-head> {(title != null || subtitle != null) && <div> {title != null && <h3.ui-panel-title id={hid}>{title}</h3>} {subtitle != null && <p.ui-panel-sub>{subtitle}</p>} </div>} {header != null && <div.ui-panel-tools>{header}</div>} </header>} <div.ui-panel-body>{children}</div> {footer != null && <footer class={ui_cls(["ui-panel-foot", footer_align != "end" && `ui-panel-foot-${footer_align}`])}>{footer}</footer>} </section>}Related
BentoGridA grid of tiles spanning columns and rows, with titles, tints and links, packed to leave no holes.9 views · 6 downloadsCardA surface for one thing, with a title, a header and a footer, or a link as a whole.8 views · 6 downloadsMasonryCards of different heights packed into columns, each filled from the top, on CSS columns alone.6 views · 7 downloadsSectionA part of a page under its title and a line about it, kept to a readable width, with room above and below.6 views · 5 downloadsWidgetA dashboard panel: a title row with a menu slot, the body, and a footer line or link, as a named region.7 views · 6 downloadsActionBarA page's main action and a line about it, fixed to the bottom of the screen on a phone.13 views · 6 downloads
Thread
Thread 0 posts
On Panel: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.