From afdd3496312d011d5d9b1023f14fb7f3ef9e7168 Mon Sep 17 00:00:00 2001 From: Marius Tarau Date: Sun, 1 Mar 2026 03:52:43 +0200 Subject: [PATCH] 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 --- app_modules_overview.xlsx | Bin 0 -> 11334 bytes src/app/(modules)/visual-copilot/page.tsx | 5 + src/config/flags.ts | 8 + src/config/modules.ts | 6 +- .../components/visual-copilot-module.tsx | 62 +++++ src/modules/visual-copilot/config.ts | 18 ++ src/modules/visual-copilot/index.ts | 2 + src/shared/components/layout/app-shell.tsx | 48 +++- src/shared/components/layout/sidebar.tsx | 222 +++++++++++++----- 9 files changed, 297 insertions(+), 74 deletions(-) create mode 100644 app_modules_overview.xlsx create mode 100644 src/app/(modules)/visual-copilot/page.tsx create mode 100644 src/modules/visual-copilot/components/visual-copilot-module.tsx create mode 100644 src/modules/visual-copilot/config.ts create mode 100644 src/modules/visual-copilot/index.ts diff --git a/app_modules_overview.xlsx b/app_modules_overview.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e62f247d6727f9b928b22baa12dbddc0c38c7691 GIT binary patch literal 11334 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 literal 0 HcmV?d00001 diff --git a/src/app/(modules)/visual-copilot/page.tsx b/src/app/(modules)/visual-copilot/page.tsx new file mode 100644 index 0000000..2a675a9 --- /dev/null +++ b/src/app/(modules)/visual-copilot/page.tsx @@ -0,0 +1,5 @@ +import { VisualCopilotModule } from "@/modules/visual-copilot"; + +export default function VisualCopilotPage() { + return ; +} diff --git a/src/config/flags.ts b/src/config/flags.ts index 4ae16fd..faf580c 100644 --- a/src/config/flags.ts +++ b/src/config/flags.ts @@ -98,6 +98,14 @@ export const DEFAULT_FLAGS: FeatureFlag[] = [ category: "module", overridable: true, }, + { + key: "module.visual-copilot", + enabled: true, + label: "Visual CoPilot", + description: "Canvas AI pentru vizualizare arhitecturală", + category: "module", + overridable: true, + }, { key: "module.hot-desk", enabled: true, diff --git a/src/config/modules.ts b/src/config/modules.ts index 9ec3a4c..e9cd504 100644 --- a/src/config/modules.ts +++ b/src/config/modules.ts @@ -14,6 +14,7 @@ import { tagManagerConfig } from "@/modules/tag-manager/config"; import { miniUtilitiesConfig } from "@/modules/mini-utilities/config"; import { aiChatConfig } from "@/modules/ai-chat/config"; import { hotDeskConfig } from "@/modules/hot-desk/config"; +import { visualCopilotConfig } from "@/modules/visual-copilot/config"; /** * Toate configurările modulelor ArchiTools, ordonate după navOrder. @@ -31,8 +32,9 @@ export const MODULE_CONFIGS: ModuleConfig[] = [ hotDeskConfig, // navOrder: 33 | management tagManagerConfig, // navOrder: 40 | tools miniUtilitiesConfig, // navOrder: 41 | tools - promptGeneratorConfig, // navOrder: 50 | ai - aiChatConfig, // navOrder: 51 | ai + promptGeneratorConfig, // navOrder: 50 | ai + aiChatConfig, // navOrder: 51 | ai + visualCopilotConfig, // navOrder: 52 | ai ]; // Înregistrare automată a tuturor modulelor în registru diff --git a/src/modules/visual-copilot/components/visual-copilot-module.tsx b/src/modules/visual-copilot/components/visual-copilot-module.tsx new file mode 100644 index 0000000..68f5d3c --- /dev/null +++ b/src/modules/visual-copilot/components/visual-copilot-module.tsx @@ -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 ( +
+ +
+

+ Visual CoPilot nu este configurat +

+

+ Setează{" "} + + NEXT_PUBLIC_VIM_URL + {" "} + în fișierul .env +

+
+
+ ); + } + + return ( +
+