mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-13 15:44:56 +00:00
perf(ui): render icons through an svg sprite (#26950)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { splitProps, type ComponentProps } from "solid-js"
|
||||
import { onMount, splitProps, type ComponentProps } from "solid-js"
|
||||
|
||||
const icons = {
|
||||
"align-right": `<path d="M12.292 6.04167L16.2503 9.99998L12.292 13.9583M2.91699 9.99998H15.6253M17.0837 3.75V16.25" stroke="currentColor" stroke-linecap="square"/>`,
|
||||
@@ -105,6 +105,41 @@ const icons = {
|
||||
"arrow-undo-down": `<path d="M4.08333 11.0859L1.75 8.7526L4.08333 6.41927M2.33333 8.7526L12.5417 8.7526L12.5417 3.21094L7 3.21094" stroke="currentColor" stroke-width="1" stroke-linecap="square"/>`,
|
||||
}
|
||||
|
||||
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 `<symbol id="${symbol(key)}" viewBox="${viewBox(key)}">${path}</symbol>`
|
||||
})
|
||||
.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 (
|
||||
<div data-component="icon" data-size={local.size || "normal"}>
|
||||
<svg
|
||||
@@ -123,11 +158,12 @@ export function Icon(props: IconProps) {
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
fill="none"
|
||||
viewBox={viewBox()}
|
||||
innerHTML={icons[local.name as keyof typeof icons]}
|
||||
viewBox={viewBox(local.name)}
|
||||
aria-hidden="true"
|
||||
{...others}
|
||||
/>
|
||||
>
|
||||
<use href={`#${symbol(local.name)}`} />
|
||||
</svg>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user