create-stylus-ide 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/Readme.MD +1515 -0
  2. package/cli.js +28 -0
  3. package/frontend/.vscode/settings.json +9 -0
  4. package/frontend/app/api/chat/route.ts +101 -0
  5. package/frontend/app/api/check-setup/route.ts +93 -0
  6. package/frontend/app/api/cleanup/route.ts +14 -0
  7. package/frontend/app/api/compile/route.ts +95 -0
  8. package/frontend/app/api/compile-stream/route.ts +98 -0
  9. package/frontend/app/api/complete/route.ts +86 -0
  10. package/frontend/app/api/deploy/route.ts +118 -0
  11. package/frontend/app/api/export-abi/route.ts +58 -0
  12. package/frontend/app/favicon.ico +0 -0
  13. package/frontend/app/globals.css +177 -0
  14. package/frontend/app/layout.tsx +29 -0
  15. package/frontend/app/ml/page.tsx +694 -0
  16. package/frontend/app/page.tsx +1132 -0
  17. package/frontend/app/providers.tsx +18 -0
  18. package/frontend/app/qlearning/page.tsx +188 -0
  19. package/frontend/app/raytracing/page.tsx +268 -0
  20. package/frontend/components/abi/ABIDialog.tsx +132 -0
  21. package/frontend/components/ai/AICompletionPopup.tsx +76 -0
  22. package/frontend/components/ai/ChatPanel.tsx +292 -0
  23. package/frontend/components/ai/QuickActions.tsx +128 -0
  24. package/frontend/components/blockchain/BlockchainContractBanner.tsx +64 -0
  25. package/frontend/components/blockchain/BlockchainLoadingDialog.tsx +188 -0
  26. package/frontend/components/deploy/DeployDialog.tsx +334 -0
  27. package/frontend/components/editor/FileTabs.tsx +181 -0
  28. package/frontend/components/editor/MonacoEditor.tsx +306 -0
  29. package/frontend/components/file-tree/ContextMenu.tsx +110 -0
  30. package/frontend/components/file-tree/DeleteConfirmDialog.tsx +61 -0
  31. package/frontend/components/file-tree/FileInputDialog.tsx +97 -0
  32. package/frontend/components/file-tree/FileNode.tsx +60 -0
  33. package/frontend/components/file-tree/FileTree.tsx +259 -0
  34. package/frontend/components/file-tree/FileTreeSkeleton.tsx +26 -0
  35. package/frontend/components/file-tree/FolderNode.tsx +105 -0
  36. package/frontend/components/github/GitHubLoadingDialog.tsx +201 -0
  37. package/frontend/components/github/GitHubMetadataBanner.tsx +61 -0
  38. package/frontend/components/github/LoadFromGitHubDialog.tsx +125 -0
  39. package/frontend/components/github/URLCopyButton.tsx +60 -0
  40. package/frontend/components/interact/ContractInteraction.tsx +323 -0
  41. package/frontend/components/interact/ContractPlaceholder.tsx +41 -0
  42. package/frontend/components/orbit/BenchmarkDialog.tsx +342 -0
  43. package/frontend/components/orbit/OrbitExplorer.tsx +273 -0
  44. package/frontend/components/project/ProjectActions.tsx +176 -0
  45. package/frontend/components/q-learning/ContractConfig.tsx +172 -0
  46. package/frontend/components/q-learning/MazeGrid.tsx +346 -0
  47. package/frontend/components/q-learning/PathAnimation.tsx +384 -0
  48. package/frontend/components/q-learning/QTableHeatmap.tsx +300 -0
  49. package/frontend/components/q-learning/TrainingForm.tsx +349 -0
  50. package/frontend/components/ray-tracing/ContractConfig.tsx +245 -0
  51. package/frontend/components/ray-tracing/MintingForm.tsx +280 -0
  52. package/frontend/components/ray-tracing/RenderCanvas.tsx +228 -0
  53. package/frontend/components/ray-tracing/RenderingPanel.tsx +259 -0
  54. package/frontend/components/ray-tracing/StyleControls.tsx +217 -0
  55. package/frontend/components/setup/SetupGuide.tsx +290 -0
  56. package/frontend/components/ui/KeyboardShortcutHint.tsx +74 -0
  57. package/frontend/components/ui/alert-dialog.tsx +157 -0
  58. package/frontend/components/ui/alert.tsx +66 -0
  59. package/frontend/components/ui/badge.tsx +46 -0
  60. package/frontend/components/ui/button.tsx +62 -0
  61. package/frontend/components/ui/card.tsx +92 -0
  62. package/frontend/components/ui/context-menu.tsx +252 -0
  63. package/frontend/components/ui/dialog.tsx +143 -0
  64. package/frontend/components/ui/dropdown-menu.tsx +257 -0
  65. package/frontend/components/ui/input.tsx +21 -0
  66. package/frontend/components/ui/label.tsx +24 -0
  67. package/frontend/components/ui/progress.tsx +31 -0
  68. package/frontend/components/ui/scroll-area.tsx +58 -0
  69. package/frontend/components/ui/select.tsx +190 -0
  70. package/frontend/components/ui/separator.tsx +28 -0
  71. package/frontend/components/ui/sheet.tsx +139 -0
  72. package/frontend/components/ui/skeleton.tsx +13 -0
  73. package/frontend/components/ui/slider.tsx +63 -0
  74. package/frontend/components/ui/sonner.tsx +40 -0
  75. package/frontend/components/ui/tabs.tsx +66 -0
  76. package/frontend/components/ui/textarea.tsx +18 -0
  77. package/frontend/components/wallet/ConnectButton.tsx +167 -0
  78. package/frontend/components/wallet/FaucetButton.tsx +256 -0
  79. package/frontend/components.json +22 -0
  80. package/frontend/eslint.config.mjs +18 -0
  81. package/frontend/hooks/useAICompletion.ts +75 -0
  82. package/frontend/hooks/useBlockchainLoader.ts +58 -0
  83. package/frontend/hooks/useChats.ts +137 -0
  84. package/frontend/hooks/useCompilation.ts +173 -0
  85. package/frontend/hooks/useFileTabs.ts +178 -0
  86. package/frontend/hooks/useGitHubLoader.ts +50 -0
  87. package/frontend/hooks/useKeyboardShortcuts.ts +47 -0
  88. package/frontend/hooks/usePanelState.ts +115 -0
  89. package/frontend/hooks/useProjectState.ts +276 -0
  90. package/frontend/hooks/useResponsive.ts +29 -0
  91. package/frontend/lib/abi-parser.ts +58 -0
  92. package/frontend/lib/blockchain-api.ts +374 -0
  93. package/frontend/lib/blockchain-explorers.ts +75 -0
  94. package/frontend/lib/blockchain-loader.ts +112 -0
  95. package/frontend/lib/cargo-template.ts +64 -0
  96. package/frontend/lib/compilation.ts +529 -0
  97. package/frontend/lib/constants.ts +31 -0
  98. package/frontend/lib/deployment.ts +176 -0
  99. package/frontend/lib/file-utils.ts +83 -0
  100. package/frontend/lib/github-api.ts +246 -0
  101. package/frontend/lib/github-loader.ts +369 -0
  102. package/frontend/lib/ml-contract-template.txt +900 -0
  103. package/frontend/lib/orbit-chains.ts +181 -0
  104. package/frontend/lib/output-formatter.ts +68 -0
  105. package/frontend/lib/project-manager.ts +632 -0
  106. package/frontend/lib/ray-tracing-abi.ts +206 -0
  107. package/frontend/lib/storage.ts +189 -0
  108. package/frontend/lib/templates.ts +1662 -0
  109. package/frontend/lib/url-parser.ts +188 -0
  110. package/frontend/lib/utils.ts +6 -0
  111. package/frontend/lib/wagmi-config.ts +24 -0
  112. package/frontend/next.config.ts +7 -0
  113. package/frontend/package-lock.json +16259 -0
  114. package/frontend/package.json +60 -0
  115. package/frontend/postcss.config.mjs +7 -0
  116. package/frontend/public/file.svg +1 -0
  117. package/frontend/public/globe.svg +1 -0
  118. package/frontend/public/ml-weights/.gitkeep +0 -0
  119. package/frontend/public/ml-weights/model.pkl +0 -0
  120. package/frontend/public/ml-weights/model_weights.json +27102 -0
  121. package/frontend/public/ml-weights/test_samples.json +7888 -0
  122. package/frontend/public/next.svg +1 -0
  123. package/frontend/public/vercel.svg +1 -0
  124. package/frontend/public/window.svg +1 -0
  125. package/frontend/scripts/check-env.js +52 -0
  126. package/frontend/scripts/setup.js +285 -0
  127. package/frontend/tailwind.config.ts +64 -0
  128. package/frontend/tsconfig.json +34 -0
  129. package/frontend/types/blockchain.ts +63 -0
  130. package/frontend/types/github.ts +54 -0
  131. package/frontend/types/project.ts +106 -0
  132. package/ml-training/README.md +56 -0
  133. package/ml-training/train_tiny_model.py +325 -0
  134. package/ml-training/update_template.py +59 -0
  135. package/package.json +30 -0
@@ -0,0 +1,173 @@
1
+ "use client";
2
+
3
+ import { useState, useCallback, useEffect } from "react";
4
+ import { CompilationOutput } from "@/lib/compilation";
5
+
6
+ interface ParsedError {
7
+ line: number;
8
+ column: number;
9
+ message: string;
10
+ }
11
+
12
+ // NEW: Project file interface
13
+ interface ProjectFile {
14
+ path: string;
15
+ content: string;
16
+ }
17
+
18
+ interface UseCompilationReturn {
19
+ isCompiling: boolean;
20
+ output: CompilationOutput[];
21
+ errors: ParsedError[];
22
+ compilationTime: number | null;
23
+ sessionId: string | null;
24
+ compile: (
25
+ code: string,
26
+ streaming?: boolean,
27
+ projectFiles?: ProjectFile[] // NEW: Add projectFiles parameter
28
+ ) => Promise<void>;
29
+ clearOutput: () => void;
30
+ }
31
+
32
+ export function useCompilation(): UseCompilationReturn {
33
+ const [isCompiling, setIsCompiling] = useState(false);
34
+ const [output, setOutput] = useState<CompilationOutput[]>([]);
35
+ const [errors, setErrors] = useState<ParsedError[]>([]);
36
+ const [compilationTime, setCompilationTime] = useState<number | null>(null);
37
+ const [sessionId, setSessionId] = useState<string | null>(null);
38
+
39
+ // Cleanup old projects periodically
40
+ useEffect(() => {
41
+ const cleanupInterval = setInterval(() => {
42
+ fetch("/api/cleanup", { method: "POST" }).catch(() => {
43
+ // Ignore cleanup errors
44
+ });
45
+ }, 5 * 60 * 1000); // Every 5 minutes
46
+
47
+ return () => clearInterval(cleanupInterval);
48
+ }, []);
49
+
50
+ const compile = useCallback(
51
+ async (
52
+ code: string,
53
+ streaming = false,
54
+ projectFiles?: ProjectFile[] // NEW: Accept project files
55
+ ) => {
56
+ setIsCompiling(true);
57
+ setOutput([]);
58
+ setErrors([]);
59
+ setCompilationTime(null);
60
+ setSessionId(null);
61
+ const startTime = Date.now();
62
+
63
+ try {
64
+ if (streaming) {
65
+ // NEW: Updated streaming endpoint with projectFiles
66
+ const response = await fetch("/api/compile-stream", {
67
+ method: "POST",
68
+ headers: { "Content-Type": "application/json" },
69
+ body: JSON.stringify({
70
+ code,
71
+ projectFiles, // NEW: Send all files
72
+ }),
73
+ });
74
+
75
+ if (!response.ok) {
76
+ throw new Error("Compilation request failed");
77
+ }
78
+
79
+ const reader = response.body?.getReader();
80
+ const decoder = new TextDecoder();
81
+
82
+ if (!reader) {
83
+ throw new Error("No response body");
84
+ }
85
+
86
+ let buffer = "";
87
+ while (true) {
88
+ const { done, value } = await reader.read();
89
+ if (done) break;
90
+
91
+ buffer += decoder.decode(value, { stream: true });
92
+ const lines = buffer.split("\n\n");
93
+ buffer = lines.pop() || "";
94
+
95
+ for (const line of lines) {
96
+ if (line.startsWith("data: ")) {
97
+ const data = JSON.parse(line.slice(6));
98
+ setOutput((prev) => [...prev, data]);
99
+
100
+ if (data.type === "start" && data.sessionId) {
101
+ setSessionId(data.sessionId);
102
+ }
103
+
104
+ if (data.type === "result" && data.errors) {
105
+ setErrors(data.errors);
106
+ }
107
+ }
108
+ }
109
+ }
110
+
111
+ setCompilationTime(Date.now() - startTime);
112
+ } else {
113
+ // NEW: Updated non-streaming endpoint with projectFiles
114
+ const response = await fetch("/api/compile", {
115
+ method: "POST",
116
+ headers: { "Content-Type": "application/json" },
117
+ body: JSON.stringify({
118
+ code,
119
+ projectFiles, // NEW: Send all files
120
+ }),
121
+ });
122
+
123
+ const result = await response.json();
124
+
125
+ if (result.sessionId) {
126
+ setSessionId(result.sessionId);
127
+ }
128
+
129
+ if (result.output) {
130
+ setOutput(result.output);
131
+ }
132
+
133
+ if (result.errors) {
134
+ setErrors(result.errors);
135
+ }
136
+
137
+ if (result.error) {
138
+ setOutput([{ type: "error", data: result.error }]);
139
+ }
140
+
141
+ setCompilationTime(Date.now() - startTime);
142
+ }
143
+ } catch (error) {
144
+ setOutput([
145
+ {
146
+ type: "error",
147
+ data: error instanceof Error ? error.message : "Compilation failed",
148
+ },
149
+ ]);
150
+ setCompilationTime(Date.now() - startTime);
151
+ } finally {
152
+ setIsCompiling(false);
153
+ }
154
+ },
155
+ []
156
+ );
157
+
158
+ const clearOutput = useCallback(() => {
159
+ setOutput([]);
160
+ setErrors([]);
161
+ setCompilationTime(null);
162
+ }, []);
163
+
164
+ return {
165
+ isCompiling,
166
+ output,
167
+ errors,
168
+ compilationTime,
169
+ sessionId,
170
+ compile,
171
+ clearOutput,
172
+ };
173
+ }
@@ -0,0 +1,178 @@
1
+ "use client";
2
+
3
+ import { useState, useCallback } from "react";
4
+
5
+ export interface FileTab {
6
+ id: string;
7
+ name: string;
8
+ content: string;
9
+ language: "rust" | "toml" | "markdown" | "text" | "gitignore";
10
+ path: string; // NEW - Full path for multi-file support
11
+ modified: boolean; // NEW - Track if file has unsaved changes
12
+ }
13
+
14
+ interface UseFileTabsReturn {
15
+ tabs: FileTab[];
16
+ activeTabId: string | null;
17
+ activeTab: FileTab | undefined;
18
+ addTab: (
19
+ name: string,
20
+ content: string,
21
+ language: FileTab["language"],
22
+ path?: string
23
+ ) => string;
24
+ removeTab: (id: string) => void;
25
+ updateTabContent: (id: string, content: string) => void;
26
+ setActiveTab: (id: string) => void;
27
+ renameTab: (id: string, newName: string) => void;
28
+ getTabByPath: (path: string) => FileTab | undefined;
29
+ openOrActivateTab: (
30
+ path: string,
31
+ name: string,
32
+ content: string,
33
+ language: FileTab["language"]
34
+ ) => void;
35
+ markTabSaved: (id: string) => void;
36
+ closeTabByPath: (path: string) => void;
37
+ }
38
+
39
+ export function useFileTabs(defaultContent: string = ""): UseFileTabsReturn {
40
+ const [tabs, setTabs] = useState<FileTab[]>([
41
+ {
42
+ id: "default",
43
+ name: "lib.rs",
44
+ content: defaultContent,
45
+ language: "rust",
46
+ path: "src/lib.rs",
47
+ modified: false,
48
+ },
49
+ ]);
50
+ const [activeTabId, setActiveTabId] = useState<string | null>("default");
51
+
52
+ const activeTab = tabs.find((tab) => tab.id === activeTabId);
53
+
54
+ // Add a new tab
55
+ const addTab = useCallback(
56
+ (
57
+ name: string,
58
+ content: string,
59
+ language: FileTab["language"],
60
+ path?: string
61
+ ): string => {
62
+ const newTab: FileTab = {
63
+ id: `tab-${Date.now()}-${Math.random()}`,
64
+ name,
65
+ content,
66
+ language,
67
+ path: path || name,
68
+ modified: false,
69
+ };
70
+
71
+ setTabs((prev) => [...prev, newTab]);
72
+ setActiveTabId(newTab.id);
73
+ return newTab.id;
74
+ },
75
+ []
76
+ );
77
+
78
+ // Remove a tab
79
+ const removeTab = useCallback((id: string) => {
80
+ setTabs((prev) => {
81
+ const filtered = prev.filter((tab) => tab.id !== id);
82
+
83
+ // If we removed the active tab, activate another one
84
+ setActiveTabId((currentActive) => {
85
+ if (currentActive === id) {
86
+ return filtered.length > 0 ? filtered[filtered.length - 1].id : null;
87
+ }
88
+ return currentActive;
89
+ });
90
+
91
+ return filtered;
92
+ });
93
+ }, []);
94
+
95
+ // Update tab content
96
+ const updateTabContent = useCallback((id: string, content: string) => {
97
+ setTabs((prev) =>
98
+ prev.map((tab) =>
99
+ tab.id === id ? { ...tab, content, modified: true } : tab
100
+ )
101
+ );
102
+ }, []);
103
+
104
+ // Set active tab
105
+ const setActiveTab = useCallback((id: string) => {
106
+ setActiveTabId(id);
107
+ }, []);
108
+
109
+ // Rename a tab
110
+ const renameTab = useCallback((id: string, newName: string) => {
111
+ setTabs((prev) =>
112
+ prev.map((tab) => (tab.id === id ? { ...tab, name: newName } : tab))
113
+ );
114
+ }, []);
115
+
116
+ // Get tab by path (for file tree integration)
117
+ const getTabByPath = useCallback(
118
+ (path: string): FileTab | undefined => {
119
+ return tabs.find((tab) => tab.path === path);
120
+ },
121
+ [tabs]
122
+ );
123
+
124
+ // Open or activate existing tab (key function for file tree)
125
+ const openOrActivateTab = useCallback(
126
+ (
127
+ path: string,
128
+ name: string,
129
+ content: string,
130
+ language: FileTab["language"]
131
+ ) => {
132
+ const existingTab = tabs.find((tab) => tab.path === path);
133
+
134
+ if (existingTab) {
135
+ // Tab already open, just activate it
136
+ setActiveTabId(existingTab.id);
137
+ } else {
138
+ // Open new tab
139
+ const newTabId = addTab(name, content, language, path);
140
+ setActiveTabId(newTabId);
141
+ }
142
+ },
143
+ [tabs, addTab]
144
+ );
145
+
146
+ // Mark tab as saved (remove modified flag)
147
+ const markTabSaved = useCallback((id: string) => {
148
+ setTabs((prev) =>
149
+ prev.map((tab) => (tab.id === id ? { ...tab, modified: false } : tab))
150
+ );
151
+ }, []);
152
+
153
+ // Close tab by path (for file tree integration)
154
+ const closeTabByPath = useCallback(
155
+ (path: string) => {
156
+ const tab = tabs.find((t) => t.path === path);
157
+ if (tab) {
158
+ removeTab(tab.id);
159
+ }
160
+ },
161
+ [tabs, removeTab]
162
+ );
163
+
164
+ return {
165
+ tabs,
166
+ activeTabId,
167
+ activeTab,
168
+ addTab,
169
+ removeTab,
170
+ updateTabContent,
171
+ setActiveTab,
172
+ renameTab,
173
+ getTabByPath,
174
+ openOrActivateTab,
175
+ markTabSaved,
176
+ closeTabByPath,
177
+ };
178
+ }
@@ -0,0 +1,50 @@
1
+ "use client";
2
+
3
+ import { useState, useCallback } from "react";
4
+ import { ProjectState } from "@/types/project";
5
+ import { GitHubURLInfo } from "@/lib/url-parser";
6
+ import { loadGitHubRepo, GitHubLoadProgress } from "@/lib/github-loader";
7
+
8
+ export function useGitHubLoader() {
9
+ const [isLoading, setIsLoading] = useState(false);
10
+ const [progress, setProgress] = useState<GitHubLoadProgress | null>(null);
11
+ const [error, setError] = useState<string | null>(null);
12
+
13
+ const loadFromGitHub = useCallback(
14
+ async (urlInfo: GitHubURLInfo): Promise<ProjectState | null> => {
15
+ setIsLoading(true);
16
+ setError(null);
17
+ setProgress(null);
18
+
19
+ try {
20
+ const project = await loadGitHubRepo(urlInfo, (progressUpdate) => {
21
+ setProgress(progressUpdate);
22
+ });
23
+
24
+ setIsLoading(false);
25
+ return project;
26
+ } catch (err) {
27
+ const errorMessage =
28
+ err instanceof Error ? err.message : "Unknown error";
29
+ setError(errorMessage);
30
+ setIsLoading(false);
31
+ return null;
32
+ }
33
+ },
34
+ []
35
+ );
36
+
37
+ const reset = useCallback(() => {
38
+ setIsLoading(false);
39
+ setProgress(null);
40
+ setError(null);
41
+ }, []);
42
+
43
+ return {
44
+ isLoading,
45
+ progress,
46
+ error,
47
+ loadFromGitHub,
48
+ reset,
49
+ };
50
+ }
@@ -0,0 +1,47 @@
1
+ 'use client';
2
+
3
+ import { useEffect } from 'react';
4
+
5
+ interface KeyboardShortcutsProps {
6
+ onToggleAI: () => void;
7
+ onToggleOutput: () => void;
8
+ onCompile: () => void;
9
+ }
10
+
11
+ export function useKeyboardShortcuts({ onToggleAI, onToggleOutput, onCompile }: KeyboardShortcutsProps) {
12
+ useEffect(() => {
13
+ const handleKeyDown = (event: KeyboardEvent) => {
14
+ // Check if user is typing in an input/textarea
15
+ const target = event.target as HTMLElement;
16
+ const isInputElement = target.tagName === 'INPUT' ||
17
+ target.tagName === 'TEXTAREA' ||
18
+ target.contentEditable === 'true';
19
+
20
+ // Cmd/Ctrl + K: Toggle AI panel
21
+ if ((event.metaKey || event.ctrlKey) && event.key === 'k' && !isInputElement) {
22
+ event.preventDefault();
23
+ onToggleAI();
24
+ }
25
+
26
+ // Cmd/Ctrl + `: Toggle output panel
27
+ if ((event.metaKey || event.ctrlKey) && event.key === '`' && !isInputElement) {
28
+ event.preventDefault();
29
+ onToggleOutput();
30
+ }
31
+
32
+ // Cmd/Ctrl + Enter: Compile
33
+ if ((event.metaKey || event.ctrlKey) && event.key === 'Enter' && !isInputElement) {
34
+ event.preventDefault();
35
+ onCompile();
36
+ }
37
+
38
+ // Escape: Close panels on mobile
39
+ if (event.key === 'Escape' && window.innerWidth < 1024) {
40
+ onToggleAI(); // This will close if open
41
+ }
42
+ };
43
+
44
+ document.addEventListener('keydown', handleKeyDown);
45
+ return () => document.removeEventListener('keydown', handleKeyDown);
46
+ }, [onToggleAI, onToggleOutput, onCompile]);
47
+ }
@@ -0,0 +1,115 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect } from 'react';
4
+
5
+ interface PanelState {
6
+ showAIPanel: boolean;
7
+ showContractPanel: boolean;
8
+ showOutput: boolean;
9
+ isAIPanelCollapsed: boolean;
10
+ isContractPanelCollapsed: boolean;
11
+ setShowAIPanel: (show: boolean) => void;
12
+ setShowContractPanel: (show: boolean) => void;
13
+ setShowOutput: (show: boolean) => void;
14
+ setIsAIPanelCollapsed: (collapsed: boolean) => void;
15
+ setIsContractPanelCollapsed: (collapsed: boolean) => void;
16
+ toggleAIPanel: () => void;
17
+ toggleContractPanel: () => void;
18
+ toggleOutput: () => void;
19
+ toggleAIPanelCollapse: () => void;
20
+ toggleContractPanelCollapse: () => void;
21
+ }
22
+
23
+ export function usePanelState(): PanelState {
24
+ const [showAIPanel, setShowAIPanel] = useState(false);
25
+ const [showContractPanel, setShowContractPanel] = useState(false);
26
+ const [showOutput, setShowOutput] = useState(true);
27
+ const [isAIPanelCollapsed, setIsAIPanelCollapsed] = useState(false);
28
+ const [isContractPanelCollapsed, setIsContractPanelCollapsed] = useState(false);
29
+
30
+ // Handle responsive behavior
31
+ useEffect(() => {
32
+ const handleResize = () => {
33
+ const isDesktop = window.innerWidth >= 1024;
34
+
35
+ if (!isDesktop) {
36
+ // On smaller screens, ensure panels don't conflict
37
+ const activePanels = [showAIPanel, showContractPanel, showOutput].filter(Boolean).length;
38
+ if (activePanels > 1) {
39
+ // Close output panel if multiple panels are open on mobile
40
+ setShowOutput(false);
41
+ }
42
+ // Reset collapse state on mobile
43
+ setIsAIPanelCollapsed(false);
44
+ setIsContractPanelCollapsed(false);
45
+ }
46
+ };
47
+
48
+ window.addEventListener('resize', handleResize);
49
+ handleResize(); // Initial check
50
+
51
+ return () => window.removeEventListener('resize', handleResize);
52
+ }, [showAIPanel, showContractPanel, showOutput]);
53
+
54
+ const toggleAIPanel = () => {
55
+ setShowAIPanel(prev => {
56
+ const newValue = !prev;
57
+ // On mobile, close other panels when opening AI panel
58
+ if (newValue && window.innerWidth < 1024) {
59
+ setShowContractPanel(false);
60
+ setShowOutput(false);
61
+ }
62
+ return newValue;
63
+ });
64
+ };
65
+
66
+ const toggleContractPanel = () => {
67
+ setShowContractPanel(prev => {
68
+ const newValue = !prev;
69
+ // On mobile, close other panels when opening contract panel
70
+ if (newValue && window.innerWidth < 1024) {
71
+ setShowAIPanel(false);
72
+ setShowOutput(false);
73
+ }
74
+ return newValue;
75
+ });
76
+ };
77
+
78
+ const toggleOutput = () => {
79
+ setShowOutput(prev => {
80
+ const newValue = !prev;
81
+ // On mobile, close side panels when opening output
82
+ if (newValue && window.innerWidth < 1024) {
83
+ setShowAIPanel(false);
84
+ setShowContractPanel(false);
85
+ }
86
+ return newValue;
87
+ });
88
+ };
89
+
90
+ const toggleAIPanelCollapse = () => {
91
+ setIsAIPanelCollapsed(prev => !prev);
92
+ };
93
+
94
+ const toggleContractPanelCollapse = () => {
95
+ setIsContractPanelCollapsed(prev => !prev);
96
+ };
97
+
98
+ return {
99
+ showAIPanel,
100
+ showContractPanel,
101
+ showOutput,
102
+ isAIPanelCollapsed,
103
+ isContractPanelCollapsed,
104
+ setShowAIPanel,
105
+ setShowContractPanel,
106
+ setShowOutput,
107
+ setIsAIPanelCollapsed,
108
+ setIsContractPanelCollapsed,
109
+ toggleAIPanel,
110
+ toggleContractPanel,
111
+ toggleOutput,
112
+ toggleAIPanelCollapse,
113
+ toggleContractPanelCollapse,
114
+ };
115
+ }