diff --git a/package.json b/package.json index a659586a..3dc33466 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "sharp": "^0.33.5", "svelte": "^5.16.0", "tailwindcss": "^3.4.17", + "uint8array-extras": "^1.4.0", "unplugin-icons": "^0.22.0" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 09363805..9d6a74ba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -101,6 +101,9 @@ importers: tailwindcss: specifier: ^3.4.17 version: 3.4.17(ts-node@10.9.1(@types/node@22.10.2)(typescript@5.7.2)) + uint8array-extras: + specifier: ^1.4.0 + version: 1.4.0 unplugin-icons: specifier: ^0.22.0 version: 0.22.0(svelte@5.16.0) @@ -3549,6 +3552,10 @@ packages: uid-promise@1.0.0: resolution: {integrity: sha512-R8375j0qwXyIu/7R0tjdF06/sElHqbmdmWC9M2qQHpEVbvE4I5+38KJI7LUUmQMp7NVq4tKHiBMkT0NFM453Ig==} + uint8array-extras@1.4.0: + resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==} + engines: {node: '>=18'} + ultrahtml@1.5.3: resolution: {integrity: sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==} @@ -8154,6 +8161,8 @@ snapshots: uid-promise@1.0.0: {} + uint8array-extras@1.4.0: {} + ultrahtml@1.5.3: {} undici-types@6.20.0: {} diff --git a/src/components/ExternalLink.astro b/src/components/ExternalLink.astro index 56924134..e2540fbb 100644 --- a/src/components/ExternalLink.astro +++ b/src/components/ExternalLink.astro @@ -1,5 +1,6 @@ --- import type { HTMLAttributes } from "astro/types"; +import { uint8ArrayToBase64 } from "uint8array-extras"; const FAVICON_API = new URL("https://www.google.com/s2/favicons"); @@ -9,7 +10,7 @@ type Props = HTMLAttributes<"a"> & { const { href, position = "before", ...props } = Astro.props; -let favicon: Buffer | undefined = undefined; +let favicon: Uint8Array | undefined = undefined; if ( href && (typeof href === "string" @@ -20,25 +21,26 @@ if ( const searchParams = new URLSearchParams({ domain: url.hostname, sz: "64" }); try { - favicon = await fetch(`${FAVICON_API}?${searchParams}`).then(async (res) => - Buffer.from(await res.arrayBuffer()), - ); + const response = await fetch(`${FAVICON_API}?${searchParams}`); + favicon = await response.bytes(); } catch (err) { - console.error(`Error fetching favicon: ${href}`, err); + console.warn(`Error fetching favicon: ${href}`, err); } } const content = (await Astro.slots.render("default")).trim(); -const imageProps = { - width: 16, - height: 16, - src: `data:image/png;base64,${favicon?.toString("base64")}`, - alt: "favicon", - fetchpriority: "low", - loading: "lazy", - decoding: "async", - "data-site-icon": true, -} as const satisfies HTMLAttributes<"img">; +const imageProps = + favicon && + ({ + width: 16, + height: 16, + src: `data:image/png;base64,${uint8ArrayToBase64(favicon)}`, + alt: "favicon", + fetchpriority: "low", + loading: "lazy", + decoding: "async", + "aria-hidden": true, + } as const satisfies HTMLAttributes<"img">); --- {