Files
com.gregkilmer.www/src/components/Icon.astro
T
2026-07-04 07:42:24 -04:00

48 lines
1.6 KiB
Plaintext

---
/**
* Icon.astro
* ---------------------------------------------------------------------------
* Inline mdi (Material Design Icons) renderer. Pulls icon path data at build
* time from `@iconify-json/mdi/icons.json` and emits a single inline <svg>, so
* there is no runtime icon library and no extra requests. The svg inherits
* `currentColor`, so color is controlled via text-* utilities or inline style.
*
* The spec calls for mdi icons everywhere instead of emojis; all spec emoji
* references are mapped to mdi names at the call sites.
*
* Usage: <Icon name="briefcase" class="h-6 w-6" />
*/
import mdi from '@iconify-json/mdi/icons.json';
interface Props {
/** mdi icon name WITHOUT prefix, e.g. "briefcase". */
name: string;
/** Accessible label. Set when the icon conveys meaning alone (not decorative). */
title?: string;
class?: string;
/** Override default 1em sizing (rarely needed; prefer class utilities). */
size?: number | string;
style?: string;
}
const { name, title, class: className, size, style } = Astro.props;
const icon = (mdi as { icons: Record<string, { body: string }> }).icons[name];
if (!icon) {
// Surface missing-icon names during dev so typos are caught immediately.
console.warn(`[Icon] unknown mdi icon: "${name}"`);
}
---
<svg
xmlns="http://www.w3.org/2000/svg"
width={size ?? '1em'}
height={size ?? '1em'}
viewBox="0 0 24 24"
class={className}
style={style}
aria-hidden={title ? undefined : 'true'}
role={title ? 'img' : undefined}
set:html={(title ? `<title>${title}</title>` : '') + (icon?.body ?? '')}
/>