artifacts-dashboard/frontend/src/components/layout/sidebar.tsx
Paweł Orzech f845647934
Some checks failed
Release / release (push) Has been cancelled
Initial release: Artifacts MMO Dashboard & Automation Platform
Full-stack dashboard for controlling, automating, and analyzing
Artifacts MMO characters via the game's HTTP API.

Backend (FastAPI):
- Async Artifacts API client with rate limiting and retry
- 6 automation strategies (combat, gathering, crafting, trading, task, leveling)
- Automation engine with runner, manager, cooldown tracker, pathfinder
- WebSocket relay (game server -> frontend)
- Game data cache, character snapshots, price history, analytics
- 9 API routers, 7 database tables, 3 Alembic migrations
- 108 unit tests

Frontend (Next.js 15 + shadcn/ui):
- Live character dashboard with HP/XP bars and cooldowns
- Character detail with stats, equipment, inventory, skills, manual actions
- Automation management with live log streaming
- Interactive canvas map with content-type coloring and zoom/pan
- Bank management, Grand Exchange with price charts
- Events, logs, analytics pages with Recharts
- WebSocket auto-reconnect with query cache invalidation
- Settings page, error boundaries, dark theme

Infrastructure:
- Docker Compose (dev + prod)
- GitHub Actions CI/CD
- Documentation (Architecture, Automation, Deployment, API)
2026-03-01 19:46:45 +01:00

122 lines
3.3 KiB
TypeScript

"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useState } from "react";
import {
LayoutDashboard,
Bot,
Map,
Landmark,
ArrowLeftRight,
Zap,
ScrollText,
BarChart3,
Settings,
ChevronLeft,
ChevronRight,
Swords,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { NAV_ITEMS } from "@/lib/constants";
import { Button } from "@/components/ui/button";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
const ICON_MAP: Record<string, React.ComponentType<{ className?: string }>> = {
LayoutDashboard,
Bot,
Map,
Landmark,
ArrowLeftRight,
Zap,
ScrollText,
BarChart3,
Settings,
};
export function Sidebar() {
const pathname = usePathname();
const [collapsed, setCollapsed] = useState(false);
return (
<TooltipProvider>
<aside
className={cn(
"hidden md:flex flex-col h-screen border-r border-border bg-card transition-all duration-300 shrink-0",
collapsed ? "w-[60px]" : "w-[240px]"
)}
>
{/* Logo / Title */}
<div className="flex items-center gap-2 px-4 h-14 border-b border-border shrink-0">
<Swords className="size-5 text-primary shrink-0" />
{!collapsed && (
<span className="font-semibold text-lg tracking-tight text-foreground">
Artifacts
</span>
)}
</div>
{/* Navigation */}
<nav className="flex-1 flex flex-col gap-1 p-2 overflow-y-auto">
{NAV_ITEMS.map((item) => {
const Icon = ICON_MAP[item.icon];
const isActive =
pathname === item.href || pathname.startsWith(item.href + "/");
const linkContent = (
<Link
href={item.href}
className={cn(
"flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors",
isActive
? "bg-accent text-accent-foreground"
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground"
)}
>
{Icon && <Icon className="size-4 shrink-0" />}
{!collapsed && <span>{item.label}</span>}
</Link>
);
if (collapsed) {
return (
<Tooltip key={item.href}>
<TooltipTrigger asChild>{linkContent}</TooltipTrigger>
<TooltipContent side="right">
<p>{item.label}</p>
</TooltipContent>
</Tooltip>
);
}
return <div key={item.href}>{linkContent}</div>;
})}
</nav>
{/* Collapse toggle */}
<div className="border-t border-border p-2 shrink-0">
<Button
variant="ghost"
size="sm"
onClick={() => setCollapsed(!collapsed)}
className="w-full justify-center"
>
{collapsed ? (
<ChevronRight className="size-4" />
) : (
<>
<ChevronLeft className="size-4" />
<span>Collapse</span>
</>
)}
</Button>
</div>
</aside>
</TooltipProvider>
);
}