IconGrid
Every icon of the kit with its name in a grid, narrowed as you type, each one a click away from its name.
Demo
Click an icon to see its name.
Get it
It needs theme.qwe, as every component does, and icon.qwe; 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/icon.qwe$ curl -O https://quillolang.org/components/ui/icon_grid.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/icon_grid.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/icon_grid.qwe
component IconGridDemoLive() { state name = null <div.demo-stack> <IconGrid id="icon-grid-demo" on_pick={(n) => { name = n }}/> <p.demo-note>{name == null ? "Click an icon to see its name." : `<Icon name="${name}"/>`}</p> </div>}view IconGridDemo() = <IconGridDemoLive/>Source
ui/icon_grid.qwe
// IconGrid: every icon of the kit with its name, as a grid that a search box// narrows as one types; a click on one gives its name, to copy into code.//// <IconGrid/>// <IconGrid size="lg" on_pick={(name) => { chosen = name }}/>//// It needs icon.qwe (Icon and icon_names).// size: the icons' size, "md" (default), "lg" or "xl". columns: the tiles' least// width in pixels (96). label: the search box's label ("Search icons").// id: the search box's id ("ui-icon-grid"); give each grid on a page its own.// on_pick(name): inside one of your components, called with the icon's name when// one is clicked. The tile clicked last is marked, and the count of matches is// said to screen readers.import ui/icon.qwe use Icon, icon_namesimport ui/theme.qwe use ui_clslet icon_grid_css = css`.ui-icon-grid { display: grid; gap: 12px; font: 14px/1.4 var(--ui-font); color: var(--ui-fg); }.ui-icon-grid-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }.ui-icon-grid-head label { font-size: 13px; font-weight: 500; }.ui-icon-grid-search { flex: 1 1 200px; height: 36px; padding: 0 12px; border: 1px solid var(--ui-border); border-radius: var(--ui-radius-sm); background: var(--ui-surface); color: var(--ui-fg); font: 14px var(--ui-font);}.ui-icon-grid-search:focus { outline: none; border-color: var(--ui-accent); box-shadow: var(--ui-focus); }.ui-icon-grid-count { color: var(--ui-muted); font-size: 13px; font-variant-numeric: tabular-nums; }.ui-icon-grid-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--w, 96px), 1fr)); gap: 6px; margin: 0; padding: 0; list-style: none; }.ui-icon-grid-tile { display: grid; justify-items: center; gap: 8px; width: 100%; padding: 14px 6px 10px; border: 1px solid var(--ui-border); border-radius: var(--ui-radius-sm); background: var(--ui-surface); color: var(--ui-fg); font: 12px/1.2 var(--ui-font); cursor: pointer; transition: border-color .15s, background .15s;}.ui-icon-grid-tile:hover { border-color: var(--ui-strong); background: var(--ui-subtle); }.ui-icon-grid-tile:focus-visible { outline: none; box-shadow: var(--ui-focus); }.ui-icon-grid-tile[aria-pressed="true"] { border-color: var(--ui-accent); background: var(--ui-accent-soft); color: var(--ui-accent); }.ui-icon-grid-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ui-muted); }.ui-icon-grid-tile[aria-pressed="true"] .ui-icon-grid-name { color: inherit; }.ui-icon-grid-empty { padding: 20px; text-align: center; color: var(--ui-muted); }@media (prefers-reduced-motion: reduce) { .ui-icon-grid-tile { transition: none; } }`component IconGrid(size: str = "md", columns: int = 96, label: str = "Search icons", id: str = "ui-icon-grid", on_pick = null, class: str? = null) { style global icon_grid_css state query = "" state picked = null let needle = lower(trim(query)) let shown = needle == "" ? icon_names : icon_names | filter((n) => contains(n, needle)) <div class={ui_cls(["ui-icon-grid", class])}> <div.ui-icon-grid-head> <label for={id}>{label}</label> <input.ui-icon-grid-search type="search" id={id} value={query} placeholder="arrow, chevron, user…" autocomplete="off" @input={(e) => { query = e.value }}/> <span.ui-icon-grid-count role="status">{len(shown)} of {len(icon_names)}</span> </div> {len(shown) > 0 ? <ul.ui-icon-grid-tiles style={`--w: ${columns}px`}> {for n in shown => <li key={n}> <button.ui-icon-grid-tile type="button" aria-pressed={n == picked ? "true" : "false"} title={n} @click={() => { picked = n on_pick && on_pick(n) }}> <Icon name={n} size={size}/> <span.ui-icon-grid-name>{n}</span> </button> </li>} </ul> : <p.ui-icon-grid-empty>No icon matches “{query}”.</p>} </div>}Related
FileIconA file's icon by its extension, written on it and coloured by its kind: document, sheet, PDF, image, code and more.6 views · 9 downloadsIconEighty common icons by name, drawn inline as SVG in the text's colour, in five sizes or any pixel size.7 views · 6 downloadsIconPickerPick an icon from a grid of 51, narrowed by a search over names and meanings; the arrow keys move and a form gets the name.5 views · 5 downloadsAudioPlayerAn audio clip with play, a seek bar that says the time, and a button cycling through playback speeds.6 views · 7 downloadsCameraCaptureTakes a photo with the camera into a hidden input as a data URL, with retake, and says so when there is no camera.6 views · 6 downloadsCoverImageA wide picture with a title, subtitle and actions over a gradient, in three heights.7 views · 7 downloads
Thread
Thread 0 posts
On IconGrid: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.