SidebarLayout
Content beside a sidebar, left or right, that goes under the content where its box is narrow.
Demo
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.qwemain.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>}Related
AppShellAn app's frame: a sidebar of links, a top bar and the page; the sidebar is a drawer on phones.10 views · 7 downloadsFooterA site's footer: brand and tagline, columns of links under titles, and a bottom line with the small print.6 views · 6 downloadsPageHeaderA page's top: breadcrumb, title, a line about it, small facts and the actions, with room under it for tabs.7 views · 5 downloadsCollapsibleA block shown and hidden under a line you click, on the browser's own <details>; open by default or not.7 views · 6 downloadsCoverA block as tall as the screen with one thing in its middle, and something at its top and bottom if given.7 views · 7 downloadsDockA floating bar of icon buttons fixed to the bottom or a side of the page, with badges and the current one marked.6 views · 7 downloads
Thread
Thread 0 posts
On SidebarLayout: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.