Feedback

SkeletonText

Grey lines in the shape of a paragraph, with a heading and several paragraphs if asked, while text loads.

#feedback#loading#text#no-js

Demo

Preview
Loading the article

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

Example

The code of the preview above.

demos/skeleton_text.qwe
view SkeletonTextDemo() =    <div.demo-stack>        <SkeletonText id="skeleton-text-demo-plain"/>        <SkeletonText id="skeleton-text-demo-article" lines={4} heading={true} label="Loading the article"/>        <div.demo-row style="align-items: flex-start; gap: 32px">            <div style="flex: 1; min-width: 200px"><SkeletonText id="skeleton-text-demo-small" paragraphs={2} lines={3} size="sm"/></div>            <div style="flex: 1; min-width: 200px"><SkeletonText lines={2} size="lg" last={40}/></div>        </div>    </div>

Source

ui/skeleton_text.qwe
// SkeletonText: grey lines in the shape of a paragraph, where text will be while// it loads. The lines vary in width as text does, the last one shorter. Hidden// from screen readers unless given a label, which they then hear (role="status").////   <SkeletonText/>//   <SkeletonText lines={5} heading={true} label="Loading the article"/>//   <SkeletonText paragraphs={3} lines={4} size="sm"/>//// lines: rows per paragraph (3). paragraphs: how many (1), with a gap between.// heading: a taller, shorter bar above the first paragraph. last: the last// line's width in percent (60). size: "sm", "md" (default) or "lg": the lines'// height and spacing, as a text size. label: what is loading, for screen// readers; without it the shape is aria-hidden, so say so elsewhere. The shimmer// stops with reduced motion.import ui/theme.qwe use ui_clslet skeleton_text_css = css`.ui-sktext { display: grid; gap: 16px; --l: .85em; --g: 9px; font-size: 15px; }.ui-sktext-sm { font-size: 13px; --g: 7px; }.ui-sktext-lg { font-size: 18px; --g: 11px; }.ui-sktext-p { display: grid; gap: var(--g); }.ui-sktext-line, .ui-sktext-h { display: block; height: var(--l); border-radius: 4px;  background: linear-gradient(90deg, var(--ui-subtle) 0%, color-mix(in srgb, var(--ui-subtle) 55%, var(--ui-strong)) 50%, var(--ui-subtle) 100%);  background-size: 200% 100%; animation: ui-sktext-shine 1.4s ease-in-out infinite; }.ui-sktext-h { height: 1.4em; width: 45%; border-radius: 6px; }@keyframes ui-sktext-shine { from { background-position: 100% 0; } to { background-position: -100% 0; } }@media (prefers-reduced-motion: reduce) { .ui-sktext-line, .ui-sktext-h { animation: none; background: var(--ui-subtle); } }`// The widths, in percent, of `lines` lines of a paragraph: full-ish ones that// vary, and the last one `last` wide.fn skeleton_text_widths(lines: int, last: int) -> list {    let pattern = [100, 94, 98, 91, 97, 89, 99, 93]    range(lines) | map((i) => i == lines - 1 && lines > 1 ? last : pattern[i % len(pattern)])}view SkeletonText(lines: int = 3, paragraphs: int = 1, heading: bool = false, last: int = 60, size: str = "md",                  label: str? = null, id: str? = null, class: str? = null) {    style global skeleton_text_css    let widths = skeleton_text_widths(lines < 1 ? 1 : lines, last)    <div class={ui_cls(["ui-sktext", size != "md" && `ui-sktext-${size}`, class])} id={id}         role={label != null ? "status" : null} aria-hidden={label == null ? "true" : null}>        {heading && <span.ui-sktext-h aria-hidden="true"></span>}        {for p in range(paragraphs < 1 ? 1 : paragraphs) => <div.ui-sktext-p key={p} aria-hidden="true">            {for [i, w] in enumerate(widths) => <span.ui-sktext-line key={i} style={`width: ${w}%`}></span>}        </div>}        {label != null && <span.ui-sr>{label}</span>}    </div>}
Thread
55Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.