From f638b0bba9ba1a9b73a63f65c4b4f1fab9c43c7e Mon Sep 17 00:00:00 2001 From: Ben Allfree Date: Fri, 10 Apr 2026 22:43:53 -0700 Subject: [PATCH] favicons --- src/bootstrapAppHead.ts | 54 +++++++++++++++++++++++++++++++++++++++++ src/main.tsx | 3 +++ 2 files changed, 57 insertions(+) create mode 100644 src/bootstrapAppHead.ts diff --git a/src/bootstrapAppHead.ts b/src/bootstrapAppHead.ts new file mode 100644 index 0000000..5816d64 --- /dev/null +++ b/src/bootstrapAppHead.ts @@ -0,0 +1,54 @@ +import appleTouchIconUrl from "@/assets/apple-touch-icon.png?url" +import favicon96x96Url from "@/assets/favicon-96x96.png?url" +import faviconIcoUrl from "@/assets/favicon.ico?url" +import faviconSvgUrl from "@/assets/favicon.svg?url" +import logoUrl from "@/assets/logo.png?url" +import webAppIcon192Url from "@/assets/web-app-manifest-192x192.png?url" +import webAppIcon512Url from "@/assets/web-app-manifest-512x512.png?url" + +const headMarker = "link[data-mesh-forge-head]" + +function appendLink(attrs: Record) { + const el = document.createElement('link') + el.setAttribute("data-mesh-forge-head", "") + for (const [k, v] of Object.entries(attrs)) { + el.setAttribute(k, v) + } + document.head.appendChild(el) +} + +/** Mirrors `main:pages/+Head.tsx` for the Vite SPA (tab icon, install manifest, etc.). */ +export function bootstrapAppHead() { + if (document.head.querySelector(headMarker)) return + + appendLink({ rel: 'icon', type: 'image/png', href: favicon96x96Url, sizes: '96x96' }) + appendLink({ rel: 'icon', type: 'image/svg+xml', href: faviconSvgUrl }) + appendLink({ rel: 'shortcut icon', href: faviconIcoUrl }) + appendLink({ rel: 'apple-touch-icon', sizes: '180x180', href: appleTouchIconUrl }) + appendLink({ rel: 'icon', href: logoUrl }) + + const manifest = { + name: "Mesh Forge", + short_name: "Mesh Forge", + icons: [ + { + src: webAppIcon192Url, + sizes: "192x192", + type: "image/png", + purpose: "maskable", + }, + { + src: webAppIcon512Url, + sizes: "512x512", + type: "image/png", + purpose: "maskable", + }, + ], + theme_color: "#ffffff", + background_color: "#ffffff", + display: "standalone" as const, + } + const blob = new Blob([JSON.stringify(manifest)], { type: "application/manifest+json" }) + const manifestUrl = URL.createObjectURL(blob) + appendLink({ rel: 'manifest', href: manifestUrl }) +} diff --git a/src/main.tsx b/src/main.tsx index c2df941..4cce58f 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -5,8 +5,11 @@ import { createRoot } from "react-dom/client" import { BrowserRouter } from "react-router-dom" import { Toaster } from "sonner" import App from "./App" +import { bootstrapAppHead } from "./bootstrapAppHead" import "./index.css" +bootstrapAppHead() + const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string) createRoot(document.getElementById("root")!).render(