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 = {
|
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"/>`,
|
"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"/>`,
|
"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"> {
|
export interface IconProps extends ComponentProps<"svg"> {
|
||||||
name: keyof typeof icons
|
name: keyof typeof icons
|
||||||
size?: "small" | "normal" | "medium" | "large"
|
size?: "small" | "normal" | "medium" | "large"
|
||||||
@@ -112,8 +147,8 @@ export interface IconProps extends ComponentProps<"svg"> {
|
|||||||
|
|
||||||
export function Icon(props: IconProps) {
|
export function Icon(props: IconProps) {
|
||||||
const [local, others] = splitProps(props, ["name", "size", "class", "classList"])
|
const [local, others] = splitProps(props, ["name", "size", "class", "classList"])
|
||||||
const viewBox = () =>
|
onMount(ensureSprite)
|
||||||
local.name === "magnifying-glass" || local.name === "arrow-undo-down" ? "0 0 16 16" : "0 0 20 20"
|
|
||||||
return (
|
return (
|
||||||
<div data-component="icon" data-size={local.size || "normal"}>
|
<div data-component="icon" data-size={local.size || "normal"}>
|
||||||
<svg
|
<svg
|
||||||
@@ -123,11 +158,12 @@ export function Icon(props: IconProps) {
|
|||||||
[local.class ?? ""]: !!local.class,
|
[local.class ?? ""]: !!local.class,
|
||||||
}}
|
}}
|
||||||
fill="none"
|
fill="none"
|
||||||
viewBox={viewBox()}
|
viewBox={viewBox(local.name)}
|
||||||
innerHTML={icons[local.name as keyof typeof icons]}
|
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
{...others}
|
{...others}
|
||||||
/>
|
>
|
||||||
|
<use href={`#${symbol(local.name)}`} />
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user