diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index 2e4d1f53b7..7bd461f110 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -1,4 +1,4 @@ -import { splitProps, type ComponentProps } from "solid-js" +import { onMount, splitProps, type ComponentProps } from "solid-js" const icons = { "align-right": ``, @@ -105,6 +105,41 @@ const icons = { "arrow-undo-down": ``, } +const spriteID = "opencode-icon-sprite" +const symbol = (name: keyof typeof icons) => `opencode-icon-${name}` +let spriteInserted = false + +function viewBox(name: keyof typeof icons) { + return name === "magnifying-glass" || name === "arrow-undo-down" ? "0 0 16 16" : "0 0 20 20" +} + +function ensureSprite() { + if (spriteInserted) return + if (typeof document === "undefined") return + if (document.getElementById(spriteID)) { + spriteInserted = true + return + } + const body = document.body as HTMLElement | null + if (!body) return + + const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg") + svg.id = spriteID + svg.setAttribute("aria-hidden", "true") + svg.setAttribute("width", "0") + svg.setAttribute("height", "0") + svg.style.position = "absolute" + svg.style.overflow = "hidden" + svg.innerHTML = Object.entries(icons) + .map(([name, path]) => { + const key = name as keyof typeof icons + return `${path}` + }) + .join("") + body.insertBefore(svg, body.firstChild) + spriteInserted = true +} + export interface IconProps extends ComponentProps<"svg"> { name: keyof typeof icons size?: "small" | "normal" | "medium" | "large" @@ -112,8 +147,8 @@ export interface IconProps extends ComponentProps<"svg"> { export function Icon(props: IconProps) { const [local, others] = splitProps(props, ["name", "size", "class", "classList"]) - const viewBox = () => - local.name === "magnifying-glass" || local.name === "arrow-undo-down" ? "0 0 16 16" : "0 0 20 20" + onMount(ensureSprite) + return (
+ > + +
) }