diff --git a/components/portal/UtilitySwitcher.tsx b/components/portal/UtilitySwitcher.tsx index 9779eae9..7eff4ca8 100644 --- a/components/portal/UtilitySwitcher.tsx +++ b/components/portal/UtilitySwitcher.tsx @@ -1,149 +1,131 @@ // components/portal/UtilitySwitcher.tsx "use client"; +import { useEffect, useMemo, useRef, useState } from "react"; import { useRouter, useSearchParams } from "next/navigation"; import { cn } from "@/lib/utils"; type Item = { + key: string; // used in ?t= label: string; - note: string; - icon: string; - href: string; - check?: string; - /** present only for subdomain links */ - target?: "_blank"; + note?: string; + icon?: string; // optional icon (public/images/utils/) + href: string; // absolute URL }; -type Tab = "onsite" | "subdomains"; - -const TABS: { key: Tab; label: string }[] = [ - { key: "onsite", label: "On-site" }, -{ key: "subdomains", label: "Subdomains" }, -]; - -/** Raw catalog (from your old dashboard) */ -const RAW_ITEMS: Item[] = [ - // --- on-site (same tab) +const ITEMS: Item[] = [ + // On-site (embed) { + key: "laser-toolkit", label: "Laser Toolkit", note: "convert laser settings, interval and more", icon: "toolkit.png", href: "https://makearmy.io/laser-toolkit", - check: "https://makearmy.io/laser-toolkit", }, { + key: "files", label: "File Server", note: "download from our file explorer", icon: "fs.png", href: "https://makearmy.io/files", - check: "https://makearmy.io/files", }, { + key: "buying-guide", label: "Buying Guide", note: "reviews and listings for relevant products", icon: "bg.png", href: "https://makearmy.io/buying-guide", - check: "https://makearmy.io/buying-guide", }, { + key: "svgnest", label: "SVGnest", note: "automatically nests parts and exports svg", icon: "nest.png", href: "https://makearmy.io/svgnest", - check: "https://makearmy.io/svgnest", }, { + key: "background-remover", label: "BG Remover", - note: "advanced open source background remover featuring 10 AI models", + note: "open source background remover", icon: "bgrm.png", href: "https://makearmy.io/background-remover", - check: "https://makearmy.io/background-remover", }, -// --- subdomains (new tab) + +// Subdomains (new tab) { + key: "picsur", label: "Picsur", note: "Simple Image Host", icon: "picsur.png", href: "https://images.makearmy.io", - target: "_blank", - check: "https://images.makearmy.io", }, { + key: "privatebin", label: "PrivateBin", - note: "Your encrypted internet clipboard.", + note: "Encrypted internet clipboard", icon: "privatebin.png", href: "https://paste.makearmy.io/", - target: "_blank", - check: "https://paste.makearmy.io/", }, { + key: "forgejo", label: "Forgejo", note: "git for our community members", icon: "forgejo.png", href: "https://forge.makearmy.io", - target: "_blank", - check: "https://forge.makearmy.io", }, ]; -function classify(items: Item[]) { - const onsite: Item[] = []; - const subdomains: Item[] = []; - for (const it of items) { - try { - const u = new URL(it.href); - if (u.hostname === "makearmy.io") onsite.push(it); - else subdomains.push(it); - } catch { - // Treat malformed URLs as on-site paths - onsite.push(it); - } +function isExternal(urlStr: string) { + try { + const u = new URL(urlStr); + return u.hostname !== "makearmy.io"; + } catch { + return true; } - return { onsite, subdomains }; } -const { onsite: ONSITE, subdomains: SUBS } = classify(RAW_ITEMS); +/** For on-site URLs, convert absolute https://makearmy.io/path → /path for iframe src */ +function toOnsitePath(urlStr: string): string { + try { + const u = new URL(urlStr); + if (u.hostname === "makearmy.io") { + return `${u.pathname}${u.search}${u.hash}`; + } + } catch {} + return urlStr; +} -function Grid({ items, external }: { items: Item[]; external: boolean }) { +function Panel({ item }: { item: Item }) { + const external = isExternal(item.href); + + if (external) { + return ( +
+
+ Opened {item.label} in a new tab. +
+ + Click here if it didn’t open. + +
+ ); + } + + const src = toOnsitePath(item.href); return ( -
- {items.map((it) => { - const iconSrc = `/images/utils/${it.icon}`; - const isExternal = external || it.target === "_blank"; - return ( - -
- {/* eslint-disable-next-line @next/next/no-img-element */} - { - (e.currentTarget as HTMLImageElement).style.display = "none"; - }} - /> -
-
-
{it.label}
- {isExternal && ( - - new tab - - )} -
-
{it.note}
-
-
-
- ); - })} +
+
{item.note}
+