|
|
@@ -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>
|
|
|
)
|
|
|
}
|