127 lines
4.5 KiB
TypeScript
127 lines
4.5 KiB
TypeScript
"use client";
|
|
|
|
import dynamic from "next/dynamic";
|
|
import { useMemo } from "react";
|
|
import { useRouter, useSearchParams } from "next/navigation";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
const LaserToolkit = dynamic(
|
|
() => import("@/components/portal/LaserToolkitSwitcher"),
|
|
{ ssr: false }
|
|
);
|
|
const FileBrowser = dynamic(
|
|
() => import("@/components/utilities/files/FileBrowserPanel"),
|
|
{ ssr: false }
|
|
);
|
|
const BackgroundRemover = dynamic(
|
|
() => import("@/components/utilities/BackgroundRemoverPanel"),
|
|
{ ssr: false }
|
|
);
|
|
|
|
const TOOLS = [
|
|
{
|
|
key: "laser-toolkit",
|
|
label: "Laser Toolkit",
|
|
description: "Calculators for beam size, overlap, hatch spacing, job time, and more.",
|
|
icon: "/images/utils/toolkit.png",
|
|
component: LaserToolkit,
|
|
},
|
|
{
|
|
key: "files",
|
|
label: "File Server",
|
|
description: "Browse, preview, and download files from the public library.",
|
|
icon: "/images/utils/fs.png",
|
|
component: FileBrowser,
|
|
},
|
|
{
|
|
key: "background-remover",
|
|
label: "Background Remover",
|
|
description: "Remove image backgrounds using our self-hosted processing service.",
|
|
icon: "/images/utils/bgrm.png",
|
|
component: BackgroundRemover,
|
|
},
|
|
] as const;
|
|
|
|
export default function TemporaryUtilityHub() {
|
|
const router = useRouter();
|
|
const searchParams = useSearchParams();
|
|
const activeKey = searchParams.get("tool") || TOOLS[0].key;
|
|
const active = useMemo(
|
|
() => TOOLS.find((tool) => tool.key === activeKey) || TOOLS[0],
|
|
[activeKey]
|
|
);
|
|
const ActiveTool = active.component;
|
|
|
|
function selectTool(key: string) {
|
|
const query = new URLSearchParams(searchParams.toString());
|
|
query.set("tool", key);
|
|
if (key !== "laser-toolkit") query.delete("lt");
|
|
router.replace(`/?${query.toString()}`, { scroll: false });
|
|
}
|
|
|
|
return (
|
|
<main className="mx-auto min-h-screen max-w-7xl px-4 py-6 sm:px-6 sm:py-10">
|
|
<header className="mb-8 border-b pb-6">
|
|
<p className="mb-2 text-sm font-medium uppercase tracking-[0.2em] text-muted-foreground">
|
|
Laser Everything
|
|
</p>
|
|
<h1 className="text-3xl font-semibold tracking-tight sm:text-4xl">Community Utilities</h1>
|
|
<p className="mt-3 max-w-3xl text-sm leading-6 text-muted-foreground sm:text-base">
|
|
Our database and member features are temporarily offline while we change backend
|
|
systems. These free utilities remain available without an account.
|
|
</p>
|
|
</header>
|
|
|
|
<nav aria-label="Utilities" className="mb-8 grid gap-3 md:grid-cols-3">
|
|
{TOOLS.map((tool) => {
|
|
const selected = tool.key === active.key;
|
|
return (
|
|
<button
|
|
key={tool.key}
|
|
type="button"
|
|
onClick={() => selectTool(tool.key)}
|
|
aria-pressed={selected}
|
|
className={cn(
|
|
"flex min-h-24 items-start gap-4 rounded-xl border p-4 text-left transition",
|
|
selected
|
|
? "border-primary bg-primary text-primary-foreground shadow-sm"
|
|
: "bg-card hover:border-muted-foreground/50 hover:bg-muted/50"
|
|
)}
|
|
>
|
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
<img src={tool.icon} alt="" className="h-10 w-10 rounded-lg object-cover" />
|
|
<span>
|
|
<span className="block font-semibold">{tool.label}</span>
|
|
<span
|
|
className={cn(
|
|
"mt-1 block text-sm leading-5",
|
|
selected ? "text-primary-foreground/80" : "text-muted-foreground"
|
|
)}
|
|
>
|
|
{tool.description}
|
|
</span>
|
|
</span>
|
|
</button>
|
|
);
|
|
})}
|
|
</nav>
|
|
|
|
<section aria-labelledby="active-tool-title" className="rounded-xl border bg-card p-3 sm:p-5">
|
|
<div className="mb-5 flex items-center gap-3 border-b pb-4">
|
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
<img src={active.icon} alt="" className="h-8 w-8 rounded-md object-cover" />
|
|
<div>
|
|
<h2 id="active-tool-title" className="text-xl font-semibold">{active.label}</h2>
|
|
<p className="text-sm text-muted-foreground">{active.description}</p>
|
|
</div>
|
|
</div>
|
|
<ActiveTool basePath="/" />
|
|
</section>
|
|
|
|
<footer className="mt-8 text-center text-xs leading-5 text-muted-foreground">
|
|
No account is required. Database-backed profiles, projects, settings, and submissions
|
|
are intentionally unavailable on this temporary site.
|
|
</footer>
|
|
</main>
|
|
);
|
|
}
|