mirror of
https://github.com/bybrooklyn/alchemist.git
synced 2026-04-18 01:43:34 -04:00
137 lines
4.6 KiB
Plaintext
137 lines
4.6 KiB
Plaintext
---
|
|
import {
|
|
Activity,
|
|
Sparkles,
|
|
Settings,
|
|
Wand2,
|
|
Video,
|
|
Terminal,
|
|
BarChart3,
|
|
Menu,
|
|
X,
|
|
} from "lucide-react";
|
|
import SystemStatus from "./SystemStatus.tsx";
|
|
|
|
const currentPath = Astro.url.pathname;
|
|
const basePath = "__ALCHEMIST_BASE_URL__";
|
|
const withBase = (href: string) => `${basePath}${href === "/" ? "/" : href}`;
|
|
const strippedPath =
|
|
basePath && currentPath.startsWith(basePath)
|
|
? currentPath.slice(basePath.length) || "/"
|
|
: currentPath;
|
|
|
|
const navItems = [
|
|
{ href: "/", label: "Dashboard", Icon: Activity },
|
|
{ href: "/jobs", label: "Jobs", Icon: Video },
|
|
{ href: "/logs", label: "Logs", Icon: Terminal },
|
|
{ href: "/stats", label: "Statistics", Icon: BarChart3 },
|
|
{ href: "/intelligence", label: "Intelligence", Icon: Sparkles },
|
|
{ href: "/convert", label: "Convert", Icon: Wand2 },
|
|
{ href: "/settings", label: "Settings", Icon: Settings },
|
|
];
|
|
---
|
|
|
|
{/* Mobile top bar */}
|
|
<div class="lg:hidden flex items-center justify-between px-4 py-3 bg-helios-surface border-b border-helios-line/60">
|
|
<a href={withBase("/")} class="font-bold text-lg tracking-tight text-helios-ink">Alchemist</a>
|
|
<button
|
|
id="sidebar-hamburger"
|
|
aria-label="Open navigation"
|
|
class="p-2 rounded-md text-helios-slate hover:bg-helios-surface-soft hover:text-helios-ink transition-colors"
|
|
>
|
|
<Menu size={22} />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Mobile overlay backdrop */}
|
|
<div
|
|
id="sidebar-backdrop"
|
|
class="hidden lg:hidden fixed inset-0 z-40 bg-black/50"
|
|
aria-hidden="true"
|
|
></div>
|
|
|
|
{/* Sidebar — hidden on mobile until hamburger opens it */}
|
|
<aside
|
|
id="sidebar"
|
|
class="hidden lg:flex w-64 bg-helios-surface border-r border-helios-line/60 flex-col p-4 gap-4
|
|
fixed lg:static inset-y-0 left-0 z-50 lg:z-auto
|
|
transition-transform duration-200 lg:transition-none"
|
|
>
|
|
<a
|
|
href={withBase("/")}
|
|
class="flex items-center px-3 pb-4 border-b border-helios-line/40"
|
|
>
|
|
<span class="font-bold text-lg tracking-tight text-helios-ink">
|
|
Alchemist
|
|
</span>
|
|
<button
|
|
id="sidebar-close"
|
|
aria-label="Close navigation"
|
|
class="lg:hidden ml-auto p-1 rounded-md text-helios-slate hover:bg-helios-surface-soft hover:text-helios-ink transition-colors"
|
|
>
|
|
<X size={18} />
|
|
</button>
|
|
</a>
|
|
|
|
<nav class="flex flex-col gap-2 flex-1">
|
|
{
|
|
navItems.map(({ href, label, Icon }) => {
|
|
const isActive =
|
|
strippedPath === href ||
|
|
(href !== "/" && strippedPath.startsWith(href));
|
|
return (
|
|
<a
|
|
href={withBase(href)}
|
|
class:list={[
|
|
"flex items-center gap-3 px-3 py-2 rounded-md border-l-2 border-transparent transition-colors whitespace-nowrap",
|
|
isActive
|
|
? "border-helios-solar bg-helios-solar/10 text-helios-ink font-semibold"
|
|
: "text-helios-slate hover:bg-helios-surface-soft hover:text-helios-ink",
|
|
]}
|
|
>
|
|
<Icon size={18} />
|
|
<span>{label}</span>
|
|
</a>
|
|
);
|
|
})
|
|
}
|
|
</nav>
|
|
|
|
<div class="mt-auto">
|
|
<div class="border-t border-helios-line/30 pt-3">
|
|
<SystemStatus client:load />
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
|
|
<script>
|
|
function initSidebar() {
|
|
const hamburger = document.getElementById("sidebar-hamburger");
|
|
const closeBtn = document.getElementById("sidebar-close");
|
|
const backdrop = document.getElementById("sidebar-backdrop");
|
|
const sidebar = document.getElementById("sidebar");
|
|
|
|
if (!hamburger || !closeBtn || !backdrop || !sidebar) return;
|
|
|
|
function openSidebar() {
|
|
sidebar!.classList.remove("hidden");
|
|
backdrop!.classList.remove("hidden");
|
|
document.body.style.overflow = "hidden";
|
|
}
|
|
|
|
function closeSidebar() {
|
|
sidebar!.classList.add("hidden");
|
|
backdrop!.classList.add("hidden");
|
|
document.body.style.overflow = "";
|
|
}
|
|
|
|
hamburger.addEventListener("click", openSidebar);
|
|
closeBtn.addEventListener("click", closeSidebar);
|
|
backdrop.addEventListener("click", closeSidebar);
|
|
}
|
|
|
|
// Run on initial load and after Astro view transitions
|
|
initSidebar();
|
|
document.addEventListener("astro:after-swap", initSidebar);
|
|
</script>
|