Skip to content

Instantly share code, notes, and snippets.

@mike-at-redspace
Created April 17, 2026 07:57
Show Gist options
  • Select an option

  • Save mike-at-redspace/9c083d24722b58e0b58621d7d7df143c to your computer and use it in GitHub Desktop.

Select an option

Save mike-at-redspace/9c083d24722b58e0b58621d7d7df143c to your computer and use it in GitHub Desktop.
Nerd Fonts (virtualized)
h1 Nerd Fonts
#toast
.toolbar
input#search(type='text' placeholder='Search glyphs…' autocomplete='off' spellcheck='false')
span#count
#viewport
div
#spacer
#grid
import * as nf from "https://esm.sh/@m234/nerd-fonts";
const $ = (id) => document.getElementById(id);
const [search, count, viewport, spacer, grid, toast] = [
"search",
"count",
"viewport",
"spacer",
"grid",
"toast"
].map($);
const ROW_H = 94,
COL_W = 96,
OVERSCAN = 3;
let filtered,
cols = 1,
rafId,
toastTimer,
searchTimer,
isFiltering = false;
const all = Object.entries(nf.icons).map(([name, { value }]) => ({
name,
short: name.replace(/^nf-[^-]+-/, ""),
value,
cp: value.codePointAt(0).toString(16).toUpperCase().padStart(4, "0")
}));
filtered = all;
const showToast = (msg) => {
toast.textContent = msg;
toast.className = "show";
clearTimeout(toastTimer);
toastTimer = setTimeout(() => (toast.className = ""), 1800);
};
const render = () => {
cols = Math.max(1, Math.floor((viewport.clientWidth + 2) / COL_W));
grid.style.setProperty("--cols", cols);
const rows = Math.ceil(filtered.length / cols);
spacer.style.height = `${rows * ROW_H}px`;
const { scrollTop, clientHeight } = viewport;
const first = Math.max(0, Math.floor(scrollTop / ROW_H) - OVERSCAN);
const last = Math.min(
rows - 1,
Math.ceil((scrollTop + clientHeight) / ROW_H) + OVERSCAN
);
grid.style.top = `${first * ROW_H}px`;
const start = first * cols;
const frag = document.createDocumentFragment();
filtered.slice(start, (last + 1) * cols).forEach((g, i) => {
const el = document.createElement("div");
el.className = `cell ${isFiltering ? "entering" : ""}`;
el.title = el.dataset.name = g.name;
el.dataset.value = g.value;
if (isFiltering) {
const rowOffset = Math.floor(i / cols);
const colIndex = i % cols;
// • 35ms per row → nice downward cascade
// • 12ms per col → subtle left-to-right wave inside each row
const delayMs = Math.round(rowOffset * 35 + colIndex * 12);
el.style.setProperty("--enter-delay", `${delayMs}ms`);
el.addEventListener(
"animationend",
() => el.classList.remove("entering"),
{ once: true }
);
}
el.innerHTML = `
<span class="glyph">${g.value}</span>
<span class="name">${g.short}</span>
<span class="cp">U+${g.cp}</span>`;
frag.append(el);
});
grid.replaceChildren(frag);
count.textContent = `${filtered.length.toLocaleString()} glyphs`;
};
const schedule = () => {
cancelAnimationFrame(rafId);
rafId = requestAnimationFrame(render);
};
search.addEventListener("input", (e) => {
clearTimeout(searchTimer);
searchTimer = setTimeout(() => {
const q = e.target.value.trim().toLowerCase();
filtered = q
? all.filter((g) => g.name.includes(q) || g.cp.toLowerCase().includes(q))
: all;
viewport.scrollTop = 0;
isFiltering = true;
render();
isFiltering = false;
}, 120);
});
viewport.addEventListener("scroll", schedule, { passive: true });
window.addEventListener("resize", schedule);
grid.addEventListener("click", (e) => {
const c = e.target.closest(".cell");
if (!c) return;
navigator.clipboard.writeText(c.dataset.name);
c.classList.add("copied");
setTimeout(() => c.classList.remove("copied"), 700);
showToast(`Copied ${c.dataset.name}`);
});
grid.addEventListener("contextmenu", (e) => {
const c = e.target.closest(".cell");
if (!c) return;
e.preventDefault();
navigator.clipboard.writeText(c.dataset.value);
showToast(`Copied glyph ${c.dataset.value}`);
});
render();
:root {
--grad-start: oklch(58% 0.28 255);
--grad-end: oklch(42% 0.34 295);
--grad-angle: 110deg;
--surface: oklch(100% 0 0 / 0.08);
--surface-hover: oklch(100% 0 0 / 0.25);
--surface-active: oklch(100% 0 0 / 0.35);
--border: oklch(100% 0 0 / 0.14);
--border-hover: oklch(100% 0 0 / 0.5);
--border-focus: oklch(100% 0 0 / 0.7);
--text-primary: oklch(100% 0 0);
--text-muted: oklch(100% 0 0 / 0.65);
--text-faint: oklch(100% 0 0 / 0.35);
--text-placeholder: oklch(100% 0 0 / 0.45);
--copied-bg: oklch(75% 0.18 145 / 0.25);
--copied-border: oklch(75% 0.18 145 / 0.6);
--scrollbar-thumb: oklch(100% 0 0 / 0.25);
--scrollbar-hover: oklch(100% 0 0 / 0.45);
--cell-h: 88px;
--cell-min-w: 90px;
--gap: 6px;
--radius: 8px;
--radius-pill: 20px;
--pad-page: 1.5rem;
--scrollbar-w: 4px;
--font-ui: system-ui, sans-serif;
--font-mono: monospace;
--font-nerd: "Symbols Nerd Font", monospace;
}
/* ─── font face ─────────────────────────────────────────────────── */
@font-face {
font-family: "Symbols Nerd Font";
src: url("https://github.com/ryanoasis/nerd-fonts/raw/HEAD/patched-fonts/NerdFontsSymbolsOnly/SymbolsNerdFont-Regular.ttf") format("truetype");
}
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
overflow: hidden;
}
body {
font-family: var(--font-ui);
display: flex;
flex-direction: column;
height: 100dvh;
background: linear-gradient(var(--grad-angle), var(--grad-start) 0%, var(--grad-end) 100%);
color: var(--text-primary);
padding: var(--pad-page) var(--scrollbar-w) var(--pad-page) var(--pad-page);
}
h1 {
margin-bottom: 0.5rem;
}
.toolbar {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 1rem;
flex-shrink: 0;
}
#search {
flex: 1;
max-width: 360px;
padding: 8px 14px;
font-size: 14px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--text-primary);
outline: none;
transition: border-color 0.15s, background 0.15s;
&::placeholder { color: var(--text-placeholder); }
&:focus {
border-color: var(--border-focus);
background: var(--surface-hover);
}
}
#count {
font-size: 12px;
color: var(--text-faint);
white-space: nowrap;
}
// virtualised viewport
#viewport {
flex: 1;
overflow-y: scroll;
overflow-x: hidden;
position: relative;
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-thumb) transparent;
padding-top: 2px;
&::-webkit-scrollbar { width: var(--scrollbar-w); }
&::-webkit-scrollbar-track { background: transparent; }
&::-webkit-scrollbar-thumb {
background: var(--scrollbar-thumb);
border-radius: calc(var(--scrollbar-w) / 2);
&:hover { background: var(--scrollbar-hover); }
}
> * {
position: relative;
}
}
#spacer { width: 100%; }
#grid {
display: grid;
grid-template-columns: repeat(var(--cols), 1fr);
gap: var(--gap);
position: absolute;
left: 0;
right: var(--scrollbar-w);
> * {
min-width: 0;
}
}
.cell {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
padding: 12px 6px 9px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
cursor: pointer;
user-select: none;
transition: background 0.1s, border-color 0.1s, transform 0.1s;
min-width: 0;
&:hover {
background: var(--surface-hover);
border-color: var(--border-hover);
transform: translateY(-1px);
.glyph, .name {
color: oklch(95% 0.28 195);
}
.glyph {
transform: scale(1.2);
}
}
&:active { transform: translateY(0); }
&.copied {
background: var(--copied-bg);
border-color: var(--copied-border);
}
&.entering {
animation: glyph-enter 340ms cubic-bezier(0.4, 0, 0.2, 1) both;
animation-delay: var(--enter-delay, 0ms);
}
.glyph {
font-family: var(--font-nerd);
font-size: clamp(24px, 2.5vw, 36px);
line-height: 1;
color: var(--text-primary);
transition: color .2s ease, transform 0.1s;
}
.name {
font-size: 10px;
color: var(--text-muted);
text-align: center;
line-height: 1.3;
width: 100%;
min-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
transition: color .2s ease;
}
.cp {
font-size: 9px;
color: var(--text-faint);
font-family: var(--font-mono);
}
}
#toast {
position: fixed;
bottom: var(--pad-page);
left: 50%;
translate: -50% 4px;
background: var(--surface-hover);
backdrop-filter: blur(8px);
border: 1px solid var(--border);
border-radius: var(--radius-pill);
padding: 7px 16px;
font-size: 13px;
color: var(--text-primary);
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity 0.15s, translate 0.15s;
text-shadow: 0 1px 2px oklch(0% 0 0 / 0.3);
z-index: 9999;
&.show {
opacity: 1;
translate: -50% 0;
}
}
@keyframes glyph-enter {
from {
opacity: 0;
transform: scale(0.8) translateY(10px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
@keyframes glyph-enter {
from {
opacity: 0;
transform: scale(0.85) translateY(14px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
@keyframes glyph-exit {
to {
opacity: 0;
transform: scale(0.85) translateY(-10px);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment