feat: Visual CoPilot module + collapsible sidebar

- Add visual-copilot module (iframe embed, env: NEXT_PUBLIC_VIM_URL)
- Sidebar collapse to icon-only with localStorage persistence
- Tooltips on collapsed nav items
- Full-viewport layout for canvas routes (/visual-copilot)
- Register module in modules.ts + feature flag in flags.ts
This commit is contained in:
Marius Tarau
2026-03-01 03:52:43 +02:00
parent 5ca276fb26
commit afdd349631
9 changed files with 297 additions and 74 deletions
@@ -0,0 +1,62 @@
"use client";
import { ExternalLink, AlertTriangle, Maximize2 } from "lucide-react";
import { useState } from "react";
const VIM_URL = process.env.NEXT_PUBLIC_VIM_URL ?? "";
export function VisualCopilotModule() {
const [isFullscreen, setIsFullscreen] = useState(false);
if (!VIM_URL) {
return (
<div className="flex h-full flex-col items-center justify-center gap-4 text-muted-foreground">
<AlertTriangle className="h-8 w-8 text-amber-500" />
<div className="text-center">
<p className="text-sm font-medium text-foreground">
Visual CoPilot nu este configurat
</p>
<p className="mt-1 text-xs">
Setează{" "}
<code className="rounded bg-muted px-1 py-0.5 text-xs">
NEXT_PUBLIC_VIM_URL
</code>{" "}
în fișierul .env
</p>
</div>
</div>
);
}
return (
<div className="relative h-full w-full">
<iframe
src={VIM_URL}
className="h-full w-full border-0"
title="Visual CoPilot"
allow="fullscreen"
/>
{/* Floating action bar */}
<div className="absolute bottom-4 right-4 flex items-center gap-1.5">
<button
onClick={() => setIsFullscreen(!isFullscreen)}
className="flex items-center gap-1.5 rounded-md bg-background/80 px-2 py-1.5 text-xs text-muted-foreground backdrop-blur transition-colors hover:text-foreground"
title="Deschide fullscreen"
>
<Maximize2 className="h-3 w-3" />
</button>
<a
href={VIM_URL}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1.5 rounded-md bg-background/80 px-2 py-1.5 text-xs text-muted-foreground backdrop-blur transition-colors hover:text-foreground"
title="Deschide în tab nou"
>
<ExternalLink className="h-3 w-3" />
Tab nou
</a>
</div>
</div>
);
}
+18
View File
@@ -0,0 +1,18 @@
import type { ModuleConfig } from "@/core/module-registry/types";
export const visualCopilotConfig: ModuleConfig = {
id: "visual-copilot",
name: "Visual CoPilot",
description:
"Canvas AI pentru vizualizare arhitecturală — generare imagini cu noduri conectate",
icon: "image",
route: "/visual-copilot",
category: "ai",
featureFlag: "module.visual-copilot",
visibility: "all",
version: "0.1.0",
dependencies: [],
storageNamespace: "visual-copilot",
navOrder: 52,
tags: ["ai", "imagine", "canvas", "arhitectura", "generare", "flux"],
};
+2
View File
@@ -0,0 +1,2 @@
export { VisualCopilotModule } from "./components/visual-copilot-module";
export { visualCopilotConfig } from "./config";