Media

IconGrid

Every icon of the kit with its name in a grid, narrowed as you type, each one a click away from its name.

#icon#media#search#interactive

Demo

Preview
78 of 78

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.qwe
main.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>}
Thread
67Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.