Layout

SidebarLayout

Content beside a sidebar, left or right, that goes under the content where its box is narrow.

#layout#page#navigation#no-js

Demo

Preview

In a 400px-wide box, the sidebar goes under the content:

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/sidebar_layout.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/sidebar_layout.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/sidebar_layout.qwe
view SidebarLayoutDemoBox(label: str, tall: bool = false) =    <div style={`padding: 16px; min-height: ${tall ? "180px" : "auto"}; border: 1px solid var(--ui-border); border-radius: var(--ui-radius-sm); background: var(--ui-subtle); font-size: 13px`}>{label}</div>view SidebarLayoutDemo() =    <div.demo-stack>        <SidebarLayout class="sidebar-layout-demo-left" width="240px" sidebar={<SidebarLayoutDemoBox label="Filters (240px, left)"/>}>            <SidebarLayoutDemoBox label="The content takes the rest." tall={true}/>        </SidebarLayout>        <SidebarLayout class="sidebar-layout-demo-right" side="right" width="200px" gap="lg"                       sidebar={<SidebarLayoutDemoBox label="On this page (200px, right)"/>}>            <SidebarLayoutDemoBox label="An article beside its table of contents." tall={true}/>        </SidebarLayout>        <p.demo-note>In a 400px-wide box, the sidebar goes under the content:</p>        <div style="width: 400px; max-width: 100%">            <SidebarLayout class="sidebar-layout-demo-narrow" sidebar={<SidebarLayoutDemoBox label="Sidebar, now below"/>}>                <SidebarLayoutDemoBox label="Content first"/>            </SidebarLayout>        </div>    </div>

Source

ui/sidebar_layout.qwe
// SidebarLayout: the page's content beside a sidebar (a filter panel, a table of// contents, an ad column) that goes under the content where there is no room. It// measures its own width, not the window's, so it works inside a card too.////   <SidebarLayout sidebar={<Filters/>}> <ProductGrid .../> </SidebarLayout>//   <SidebarLayout side="right" width="220px" sticky={true} sidebar={<TableOfContents .../>}>//       <article>...</article>//   </SidebarLayout>//// sidebar: the sidebar's HTML. children: the content. side: "left" (default) or "right".// width: the sidebar's width, as CSS ("260px"). gap: pixels (24, the default) or// "none", "xs" (4), "sm" (8), "md" (16), "lg" (24), "xl" (32).// stack: when the sidebar goes under the content: narrower than "sm" (480px), "md"// (640px, the default), "lg" (900px), or "none" (never). Stacked, the sidebar// comes after the content whichever side it was on, unless first={true}.// sticky: the sidebar stays in view as the content scrolls past it (top: var(--ui-sidebar-top, 16px)).import ui/theme.qwe use ui_clslet sidebar_layout_css = css`.ui-sidebar-layout { container-type: inline-size; min-width: 0; }.ui-sidebar-layout-in {  display: grid; grid-template-columns: var(--ui-sidebar-w, 260px) minmax(0, 1fr); gap: var(--ui-sidebar-gap, 24px);  align-items: start; min-width: 0;}.ui-sidebar-layout-right > .ui-sidebar-layout-in { grid-template-columns: minmax(0, 1fr) var(--ui-sidebar-w, 260px); }.ui-sidebar-layout-right > .ui-sidebar-layout-in > .ui-sidebar-layout-aside { order: 1; }.ui-sidebar-layout-aside, .ui-sidebar-layout-main { min-width: 0; }.ui-sidebar-layout-main { align-self: stretch; }.ui-sidebar-layout-sticky > .ui-sidebar-layout-in > .ui-sidebar-layout-aside { position: sticky; top: var(--ui-sidebar-top, 16px); }@container (max-width: 479px) {  .ui-sidebar-layout-sm > .ui-sidebar-layout-in { grid-template-columns: minmax(0, 1fr); }  .ui-sidebar-layout-sm > .ui-sidebar-layout-in > .ui-sidebar-layout-aside { order: 1; position: static; }  .ui-sidebar-layout-sm.ui-sidebar-layout-first > .ui-sidebar-layout-in > .ui-sidebar-layout-aside { order: 0; }}@container (max-width: 639px) {  .ui-sidebar-layout-md > .ui-sidebar-layout-in { grid-template-columns: minmax(0, 1fr); }  .ui-sidebar-layout-md > .ui-sidebar-layout-in > .ui-sidebar-layout-aside { order: 1; position: static; }  .ui-sidebar-layout-md.ui-sidebar-layout-first > .ui-sidebar-layout-in > .ui-sidebar-layout-aside { order: 0; }}@container (max-width: 899px) {  .ui-sidebar-layout-lg > .ui-sidebar-layout-in { grid-template-columns: minmax(0, 1fr); }  .ui-sidebar-layout-lg > .ui-sidebar-layout-in > .ui-sidebar-layout-aside { order: 1; position: static; }  .ui-sidebar-layout-lg.ui-sidebar-layout-first > .ui-sidebar-layout-in > .ui-sidebar-layout-aside { order: 0; }}`fn sidebar_layout_gap(gap) -> str =    match gap {        int as n => `${n}px`        float as n => `${n}px`        "none" => "0"        "xs" => "4px"        "sm" => "8px"        "md" => "16px"        "xl" => "32px"        _ => "24px"    }view SidebarLayout(sidebar = null, side: str = "left", width: str = "260px", gap = 24, stack: str = "md",                   first: bool = false, sticky: bool = false, class: str? = null, children) {    style global sidebar_layout_css    <div class={ui_cls(["ui-sidebar-layout", side == "right" && "ui-sidebar-layout-right", stack != "none" && `ui-sidebar-layout-${stack}`,                        first && "ui-sidebar-layout-first", sticky && "ui-sidebar-layout-sticky", class])}         style={`--ui-sidebar-w: ${width}; --ui-sidebar-gap: ${sidebar_layout_gap(gap)}`}>        <div.ui-sidebar-layout-in>            <aside.ui-sidebar-layout-aside>{sidebar}</aside>            <div.ui-sidebar-layout-main>{children}</div>        </div>    </div>}
Thread
56Useful? Like it, or add to its thread below.

Thread 0 posts

On SidebarLayout: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.