Media

Thumbnail

A small image in five sizes and three shapes, with a line of text over it, a "+N" veil, or a link.

#media#image#list#no-js

Demo

Preview
RedGreenBlueOrangeRedGreen
IMG_0412.jpg+3

Picked: none

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

Example

The code of the preview above.

demos/thumbnail.qwe
// A product shot drawn in SVG, so the demo needs no image files.fn thumbnail_demo_pic(bg: str, fg: str) -> str {    let svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="200" height="200">`        + `<rect width="200" height="200" fill="${bg}"/><circle cx="100" cy="90" r="46" fill="${fg}"/>`        + `<rect x="40" y="140" width="120" height="26" rx="13" fill="${fg}" opacity=".7"/></svg>`    `data:image/svg+xml,${url_encode(svg)}`}let thumbnail_demo_pics = [thumbnail_demo_pic("#fde2e4", "#c62a2f"), thumbnail_demo_pic("#e3f5ec", "#18794e"),                           thumbnail_demo_pic("#e5f1fc", "#0b6bcb"), thumbnail_demo_pic("#fdf0dc", "#a35200")]component ThumbnailDemoLive() {    state picked = "none"    <div.demo-row>        {for [i, p] in enumerate(thumbnail_demo_pics) => <Thumbnail src={p} alt="" label={`Pick colour ${i + 1}`} size="sm"                                                                     on_click={() => { picked = str(i + 1) }}/>}        <p.demo-note id="thumbnail-demo-picked">Picked: {picked}</p>    </div>}view ThumbnailDemo() =    <div.demo-stack>        <div.demo-row id="thumbnail-demo-sizes">            <Thumbnail src={thumbnail_demo_pics[0]} alt="Red" size="xs"/>            <Thumbnail src={thumbnail_demo_pics[1]} alt="Green" size="sm"/>            <Thumbnail src={thumbnail_demo_pics[2]} alt="Blue"/>            <Thumbnail src={thumbnail_demo_pics[3]} alt="Orange" size="lg"/>            <Thumbnail src={thumbnail_demo_pics[0]} alt="Red" size="xl"/>            <Thumbnail src={thumbnail_demo_pics[1]} alt="Green" px={40}/>        </div>        <div.demo-row id="thumbnail-demo-shapes">            <Thumbnail src={thumbnail_demo_pics[2]} alt="" shape="square" size="lg"/>            <Thumbnail src={thumbnail_demo_pics[3]} alt="" shape="circle" size="lg"/>            <Thumbnail src={thumbnail_demo_pics[0]} alt="" size="lg" overlay="IMG_0412.jpg"/>            <Thumbnail src={thumbnail_demo_pics[1]} alt="" size="lg" more={3}/>            <Thumbnail src={thumbnail_demo_pics[2]} alt="" size="lg" fit="contain" href="https://quillolang.org" label="Open the album"/>        </div>        <ThumbnailDemoLive/>    </div>

Source

ui/thumbnail.qwe
// Thumbnail: a small image in a fixed size and shape, for lists, grids and// pickers: a product's picture beside its name, a row of files, the people// in a thread. It can carry a line of text over its bottom, a "+N" veil for// the ones not shown, and be a link.////   <Thumbnail src="/img/shoe-sm.jpg" alt="Red running shoe" size="sm"/>//   <Thumbnail src="/img/cover.jpg" alt="" shape="circle" size="lg" href="/albums/7" label="Open the album"/>//   <Thumbnail src="/img/4.jpg" alt="" more={3}/>              the fourth of seven, veiled "+3"//// src, alt: the image (alt "" when the text beside it says what it is).// size: "xs" (32px), "sm" (48px), "md" (64px, default), "lg" (96px) or "xl" (128px);// px: a size in pixels instead. shape: "rounded" (default), "square" or "circle".// fit: "cover" (default) or "contain". overlay: a short line over its bottom.// more: a number N shown as "+N" over the image, for the ones not shown.// href makes it a link; label is then what screen readers call the link.// on_click(): inside one of your components, makes it a button that does that.import ui/theme.qwe use ui_clslet thumbnail_css = css`.ui-thumbnail {  position: relative; display: inline-grid; flex: none; overflow: hidden; width: var(--s, 64px); height: var(--s, 64px); padding: 0;  border: 1px solid var(--ui-border); border-radius: var(--ui-radius-sm); background: var(--ui-subtle); color: #fff;  font: 500 12px/1.2 var(--ui-font); text-decoration: none; vertical-align: middle;}.ui-thumbnail-xs { --s: 32px; border-radius: 4px; }.ui-thumbnail-sm { --s: 48px; }.ui-thumbnail-lg { --s: 96px; }.ui-thumbnail-xl { --s: 128px; }.ui-thumbnail-square { border-radius: 0; }.ui-thumbnail-circle { border-radius: 50%; }.ui-thumbnail img { display: block; width: 100%; height: 100%; object-fit: cover; }.ui-thumbnail-contain img { object-fit: contain; }.ui-thumbnail-text {  position: absolute; inset: auto 0 0 0; padding: 14px 6px 5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;  background: linear-gradient(to top, rgba(0, 0, 0, .65), transparent); text-align: center; text-shadow: 0 1px 2px rgba(0, 0, 0, .5);}.ui-thumbnail-more { position: absolute; inset: 0; display: grid; place-items: center; background: rgba(0, 0, 0, .5); font-size: calc(var(--s, 64px) * .26); font-weight: 600; }a.ui-thumbnail, button.ui-thumbnail { cursor: pointer; transition: box-shadow .15s, border-color .15s; }a.ui-thumbnail:hover, button.ui-thumbnail:hover { border-color: var(--ui-strong); box-shadow: var(--ui-shadow); }.ui-thumbnail:focus-visible { outline: none; box-shadow: var(--ui-focus); }@media (prefers-reduced-motion: reduce) { a.ui-thumbnail, button.ui-thumbnail { transition: none; } }`view Thumbnail(src: str, alt: str = "", size: str = "md", px: int? = null, shape: str = "rounded", fit: str = "cover",               overlay: str? = null, more: int? = null, href: str? = null, label: str? = null, on_click = null,               class: str? = null) {    style global thumbnail_css    let cls = ui_cls(["ui-thumbnail", px == null && size != "md" && `ui-thumbnail-${size}`, shape != "rounded" && `ui-thumbnail-${shape}`,                      fit == "contain" && "ui-thumbnail-contain", class])    let sty = px != null ? `--s: ${px}px` : null    let body = [        <img src={src} alt={alt} loading="lazy"/>,        overlay != null && <span.ui-thumbnail-text>{overlay}</span>,        more != null && more > 0 && <span.ui-thumbnail-more aria-label={`and ${more} more`}>+{more}</span>,    ]    href != null        ? <a class={cls} style={sty} href={href} aria-label={label}>{body}</a>        : on_click != null            ? <button class={cls} style={sty} type="button" aria-label={label} @click={() => { on_click() }}>{body}</button>            : <span class={cls} style={sty}>{body}</span>}
Thread
79Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.