Layout

BrowserFrame

A mock browser window around its content, with the address in its bar, for screenshots and demos.

#layout#media#image#marketing#no-js

Demo

Preview

Quillo UI

A page drawn inside a browser window, address and all.

No lock for a plain address; a named tab; 120px tall.
A dark screenshot

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

Example

The code of the preview above.

demos/browser_frame.qwe
view BrowserFrameDemo() =    <div.demo-stack>        <BrowserFrame id="browser-frame-demo-docs" url="https://quillolang.org/docs/components" title="The components page">            <div style="padding: 24px">                <h4 style="margin: 0 0 8px">Quillo UI</h4>                <p style="margin: 0; color: var(--ui-muted)">A page drawn inside a browser window, address and all.</p>            </div>        </BrowserFrame>        <Grid columns={2}>            <BrowserFrame id="browser-frame-demo-local" url="localhost:8080/admin" title="Admin" tab={true} height="120px">                <div style="padding: 16px; font-size: 13px">No lock for a plain address; a named tab; 120px tall.</div>            </BrowserFrame>            <BrowserFrame id="browser-frame-demo-dark" url="https://example.com" dark={true} height="120px">                <img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='120'%3E%3Crect width='400' height='120' fill='%232a2550'/%3E%3C/svg%3E" alt="A dark screenshot"/>            </BrowserFrame>        </Grid>    </div>

Source

ui/browser_frame.qwe
// BrowserFrame: a drawing of a browser window around what it holds, with an// address in its bar: for showing a screenshot, a demo or an <iframe> as it// would look on a site.////   <BrowserFrame url="https://quillolang.org/docs"><img src="/shots/docs.png" alt="The docs page"/></BrowserFrame>//   <BrowserFrame url="localhost:8080" title="The app in development" height="360px"> <App/> </BrowserFrame>//// url: the address shown in the bar; one starting with https:// gets a lock, and// its scheme is left out. title: the window's name (screen readers hear it; shown// as the tab's name when tab={true}). height: the content's height, as CSS (as// tall as the content). dark: a dark frame whatever the theme. An <img> fills the// width.import ui/theme.qwe use ui_clslet browser_frame_css = css`.ui-browser {  min-width: 0; overflow: hidden; border: 1px solid var(--ui-border); border-radius: var(--ui-radius);  background: var(--ui-surface); color: var(--ui-fg); box-shadow: var(--ui-shadow); font: 13px/1.4 var(--ui-font);}.ui-browser-bar { display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-bottom: 1px solid var(--ui-border); background: var(--ui-subtle); }.ui-browser-dots { display: flex; flex: none; gap: 6px; }.ui-browser-dots i { width: 11px; height: 11px; border-radius: 50%; background: var(--ui-strong); }.ui-browser-dots i:nth-child(1) { background: #ff5f57; }.ui-browser-dots i:nth-child(2) { background: #febc2e; }.ui-browser-dots i:nth-child(3) { background: #28c840; }.ui-browser-nav { display: flex; flex: none; gap: 2px; color: var(--ui-muted); }.ui-browser-nav svg { width: 16px; height: 16px; }.ui-browser-tab { flex: none; max-width: 160px; padding: 3px 10px; border-radius: 6px; background: var(--ui-surface); color: var(--ui-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }.ui-browser-url {  display: flex; flex: 1; align-items: center; gap: 6px; min-width: 0; height: 28px; padding: 0 10px; border-radius: 999px;  background: var(--ui-surface); color: var(--ui-muted); overflow: hidden; white-space: nowrap;}.ui-browser-url svg { flex: none; width: 12px; height: 12px; }.ui-browser-url span { overflow: hidden; text-overflow: ellipsis; }.ui-browser-url b { font-weight: 500; color: var(--ui-fg); }.ui-browser-body { position: relative; height: var(--ui-browser-h, auto); min-width: 0; overflow: auto; background: var(--ui-bg); }.ui-browser-body > img, .ui-browser-body > quillo-raw > img { display: block; width: 100%; height: auto; }.ui-browser-dark { --ui-bg: #0f0e17; --ui-surface: #17161f; --ui-subtle: #201f2b; --ui-fg: #ecebf3; --ui-muted: #a3a0b7; --ui-border: #2e2c3d; --ui-strong: #45435a; color-scheme: dark; }@media (max-width: 480px) { .ui-browser-nav, .ui-browser-tab { display: none; } }`// The address as shown: the scheme left out, the host in bold, and whether it is secure.fn browser_frame_address(url: str) -> map {    let secure = starts_with(url, "https://")    let rest = secure ? slice(url, 8) : starts_with(url, "http://") ? slice(url, 7) : url    let cut = index_of(rest, "/")    { secure, host: cut == null ? rest : slice(rest, 0, cut), path: cut == null ? "" : slice(rest, cut) }}view BrowserFrame(url: str = "https://example.com", title: str? = null, tab: bool = false, height: str? = null,                  dark: bool = false, id: str? = null, class: str? = null, children) {    style global browser_frame_css    let at = browser_frame_address(url)    <div class={ui_cls(["ui-browser", dark && "ui-browser-dark", class])} id={id} role="figure" aria-label={title ?? url}         style={height != null ? `--ui-browser-h: ${height}` : null}>        <div.ui-browser-bar aria-hidden="true">            <span.ui-browser-dots><i></i><i></i><i></i></span>            <span.ui-browser-nav>                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"/></svg>                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>            </span>            {tab && title != null && <span.ui-browser-tab>{title}</span>}            <span.ui-browser-url>                {at.secure && <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>}                <span><b>{at.host}</b>{at.path}</span>            </span>        </div>        <div.ui-browser-body>{children}</div>    </div>}
Thread
76Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.