Skip to content

Commit 0d439e4

Browse files
echobtfactorydroid
andauthored
fix: hamburger menu now uses Figma-themed dropdown instead of separate navbar (#388)
The hamburger menu (3 bars) in FigmaTitleBar was previously opening the full MenuBar component in a floating div, which displayed with the old orange theme (Vibe/IDE toggle with #f97316) instead of the new Figma yellow/lime theme. This fix: - Replaces the MenuBar import with a new FigmaMenuDropdown component - The new dropdown is styled with Figma design tokens (#BFFF00 lime accent) - Menu items use proper hover states with lime/yellow highlights - The dropdown stays on the new navbar's theme and position - All menu functionality (File, Edit, Selection, View, Go, Terminal, Help) is preserved with the same keyboard shortcuts Co-authored-by: Droid Agent <droid@factory.ai>
1 parent f2e0a37 commit 0d439e4

1 file changed

Lines changed: 298 additions & 32 deletions

File tree

cortex-gui/src/components/figma/FigmaDesktopLayout.tsx

Lines changed: 298 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
onMount,
1515
onCleanup,
1616
Show,
17+
For,
1718
lazy,
1819
Suspense,
1920
} from "solid-js";
@@ -25,9 +26,6 @@ import FigmaActivityBar from "./FigmaActivityBar";
2526
import FigmaChatPanel, { ChatPanelState, ChatMessage } from "./FigmaChatPanel";
2627
import FigmaStatusBar from "./FigmaStatusBar";
2728

28-
// Existing Components
29-
import { MenuBar } from "@/components/MenuBar";
30-
3129
// Existing Contexts
3230
import { useEditor } from "@/context/EditorContext";
3331
import { useSDK } from "@/context/SDKContext";
@@ -119,6 +117,301 @@ function SidebarSkeleton() {
119117
);
120118
}
121119

120+
// ============================================================================
121+
// Figma Menu Dropdown - Hamburger menu with Figma theme styling
122+
// ============================================================================
123+
124+
interface FigmaMenuDropdownProps {
125+
onClose: () => void;
126+
}
127+
128+
interface MenuItem {
129+
label: string;
130+
shortcut?: string;
131+
action?: () => void;
132+
separator?: boolean;
133+
icon?: string;
134+
}
135+
136+
function FigmaMenuDropdown(props: FigmaMenuDropdownProps) {
137+
const [activeMenu, setActiveMenu] = createSignal<string | null>(null);
138+
139+
// Menu structure matching VS Code/IDE layout
140+
const menus: { label: string; items: MenuItem[] }[] = [
141+
{
142+
label: "File",
143+
items: [
144+
{ label: "New File", shortcut: "Ctrl+N", action: () => window.dispatchEvent(new CustomEvent("file:new")) },
145+
{ label: "New Window", shortcut: "Ctrl+Shift+N", action: () => window.dispatchEvent(new CustomEvent("window:new")) },
146+
{ separator: true, label: "" },
147+
{ label: "Open File...", shortcut: "Ctrl+O", action: () => window.dispatchEvent(new CustomEvent("file:open")) },
148+
{ label: "Open Folder...", shortcut: "Ctrl+K Ctrl+O", action: () => window.dispatchEvent(new CustomEvent("folder:open")) },
149+
{ separator: true, label: "" },
150+
{ label: "Save", shortcut: "Ctrl+S", action: () => window.dispatchEvent(new CustomEvent("file:save")) },
151+
{ label: "Save As...", shortcut: "Ctrl+Shift+S", action: () => window.dispatchEvent(new CustomEvent("file:save-as")) },
152+
{ label: "Save All", shortcut: "Ctrl+K S", action: () => window.dispatchEvent(new CustomEvent("file:save-all")) },
153+
{ separator: true, label: "" },
154+
{ label: "Close", shortcut: "Ctrl+W", action: () => window.dispatchEvent(new CustomEvent("file:close")) },
155+
{ label: "Close Folder", action: () => window.dispatchEvent(new CustomEvent("folder:close")) },
156+
],
157+
},
158+
{
159+
label: "Edit",
160+
items: [
161+
{ label: "Undo", shortcut: "Ctrl+Z", action: () => window.dispatchEvent(new CustomEvent("edit:undo")) },
162+
{ label: "Redo", shortcut: "Ctrl+Shift+Z", action: () => window.dispatchEvent(new CustomEvent("edit:redo")) },
163+
{ separator: true, label: "" },
164+
{ label: "Cut", shortcut: "Ctrl+X", action: () => window.dispatchEvent(new CustomEvent("edit:cut")) },
165+
{ label: "Copy", shortcut: "Ctrl+C", action: () => window.dispatchEvent(new CustomEvent("edit:copy")) },
166+
{ label: "Paste", shortcut: "Ctrl+V", action: () => window.dispatchEvent(new CustomEvent("edit:paste")) },
167+
{ separator: true, label: "" },
168+
{ label: "Find", shortcut: "Ctrl+F", action: () => window.dispatchEvent(new CustomEvent("edit:find")) },
169+
{ label: "Replace", shortcut: "Ctrl+H", action: () => window.dispatchEvent(new CustomEvent("edit:replace")) },
170+
{ label: "Find in Files", shortcut: "Ctrl+Shift+F", action: () => window.dispatchEvent(new CustomEvent("search:find-in-files")) },
171+
],
172+
},
173+
{
174+
label: "Selection",
175+
items: [
176+
{ label: "Select All", shortcut: "Ctrl+A", action: () => window.dispatchEvent(new CustomEvent("selection:select-all")) },
177+
{ label: "Expand Selection", shortcut: "Shift+Alt+→", action: () => window.dispatchEvent(new CustomEvent("selection:expand")) },
178+
{ label: "Shrink Selection", shortcut: "Shift+Alt+←", action: () => window.dispatchEvent(new CustomEvent("selection:shrink")) },
179+
{ separator: true, label: "" },
180+
{ label: "Copy Line Up", shortcut: "Shift+Alt+↑", action: () => window.dispatchEvent(new CustomEvent("selection:copy-line-up")) },
181+
{ label: "Copy Line Down", shortcut: "Shift+Alt+↓", action: () => window.dispatchEvent(new CustomEvent("selection:copy-line-down")) },
182+
{ label: "Move Line Up", shortcut: "Alt+↑", action: () => window.dispatchEvent(new CustomEvent("selection:move-line-up")) },
183+
{ label: "Move Line Down", shortcut: "Alt+↓", action: () => window.dispatchEvent(new CustomEvent("selection:move-line-down")) },
184+
],
185+
},
186+
{
187+
label: "View",
188+
items: [
189+
{ label: "Command Palette...", shortcut: "Ctrl+Shift+P", action: () => window.dispatchEvent(new CustomEvent("command-palette:open")) },
190+
{ label: "Quick Open...", shortcut: "Ctrl+P", action: () => window.dispatchEvent(new CustomEvent("quick-open:show")) },
191+
{ separator: true, label: "" },
192+
{ label: "Explorer", shortcut: "Ctrl+Shift+E", action: () => window.dispatchEvent(new CustomEvent("view:explorer")) },
193+
{ label: "Search", shortcut: "Ctrl+Shift+F", action: () => window.dispatchEvent(new CustomEvent("view:search")) },
194+
{ label: "Source Control", shortcut: "Ctrl+Shift+G", action: () => window.dispatchEvent(new CustomEvent("view:git")) },
195+
{ label: "Extensions", shortcut: "Ctrl+Shift+X", action: () => window.dispatchEvent(new CustomEvent("view:extensions")) },
196+
{ separator: true, label: "" },
197+
{ label: "Terminal", shortcut: "Ctrl+`", action: () => window.dispatchEvent(new CustomEvent("terminal:toggle")) },
198+
{ label: "Toggle Sidebar", shortcut: "Ctrl+B", action: () => window.dispatchEvent(new CustomEvent("sidebar:toggle")) },
199+
],
200+
},
201+
{
202+
label: "Go",
203+
items: [
204+
{ label: "Go to File...", shortcut: "Ctrl+P", action: () => window.dispatchEvent(new CustomEvent("goto:file")) },
205+
{ label: "Go to Symbol...", shortcut: "Ctrl+Shift+O", action: () => window.dispatchEvent(new CustomEvent("goto:symbol")) },
206+
{ label: "Go to Line...", shortcut: "Ctrl+G", action: () => window.dispatchEvent(new CustomEvent("goto:line")) },
207+
{ separator: true, label: "" },
208+
{ label: "Go to Definition", shortcut: "F12", action: () => window.dispatchEvent(new CustomEvent("goto:definition")) },
209+
{ label: "Go to References", shortcut: "Shift+F12", action: () => window.dispatchEvent(new CustomEvent("goto:references")) },
210+
{ separator: true, label: "" },
211+
{ label: "Go Back", shortcut: "Alt+←", action: () => window.dispatchEvent(new CustomEvent("goto:back")) },
212+
{ label: "Go Forward", shortcut: "Alt+→", action: () => window.dispatchEvent(new CustomEvent("goto:forward")) },
213+
],
214+
},
215+
{
216+
label: "Terminal",
217+
items: [
218+
{ label: "New Terminal", shortcut: "Ctrl+Shift+`", action: () => window.dispatchEvent(new CustomEvent("terminal:new")) },
219+
{ label: "Split Terminal", action: () => window.dispatchEvent(new CustomEvent("terminal:split")) },
220+
{ separator: true, label: "" },
221+
{ label: "Run Task...", action: () => window.dispatchEvent(new CustomEvent("task:run")) },
222+
{ label: "Run Build Task", shortcut: "Ctrl+Shift+B", action: () => window.dispatchEvent(new CustomEvent("task:build")) },
223+
],
224+
},
225+
{
226+
label: "Help",
227+
items: [
228+
{ label: "Welcome", action: () => window.dispatchEvent(new CustomEvent("help:welcome")) },
229+
{ label: "Documentation", action: () => window.dispatchEvent(new CustomEvent("help:docs")) },
230+
{ label: "Release Notes", action: () => window.dispatchEvent(new CustomEvent("help:release-notes")) },
231+
{ separator: true, label: "" },
232+
{ label: "Keyboard Shortcuts", shortcut: "Ctrl+K Ctrl+S", action: () => window.dispatchEvent(new CustomEvent("help:keybindings")) },
233+
{ separator: true, label: "" },
234+
{ label: "About", action: () => window.dispatchEvent(new CustomEvent("help:about")) },
235+
],
236+
},
237+
];
238+
239+
const handleMenuClick = (label: string) => {
240+
if (activeMenu() === label) {
241+
setActiveMenu(null);
242+
} else {
243+
setActiveMenu(label);
244+
}
245+
};
246+
247+
const handleItemClick = (item: MenuItem) => {
248+
if (item.action) {
249+
item.action();
250+
props.onClose();
251+
}
252+
};
253+
254+
return (
255+
<>
256+
{/* Backdrop to close menu */}
257+
<div
258+
style={{
259+
position: "fixed",
260+
top: "0",
261+
left: "0",
262+
right: "0",
263+
bottom: "0",
264+
"z-index": "2400",
265+
}}
266+
onClick={props.onClose}
267+
/>
268+
269+
{/* Menu Container - styled with Figma theme */}
270+
<div
271+
style={{
272+
position: "fixed",
273+
top: "53px",
274+
left: "143px", // Aligned with hamburger menu position
275+
"z-index": "2500",
276+
display: "flex",
277+
"align-items": "flex-start",
278+
gap: "2px",
279+
background: "var(--figma-bg-secondary, #1A1A1A)",
280+
"border-radius": "var(--figma-radius-md, 8px)",
281+
border: "1px solid var(--figma-border-default, rgba(255,255,255,0.1))",
282+
padding: "6px",
283+
"box-shadow": "0 4px 24px rgba(0,0,0,0.5)",
284+
}}
285+
onClick={(e) => e.stopPropagation()}
286+
>
287+
{/* Menu Bar Items */}
288+
<For each={menus}>
289+
{(menu) => (
290+
<div style={{ position: "relative" }}>
291+
<button
292+
onClick={() => handleMenuClick(menu.label)}
293+
style={{
294+
height: "28px",
295+
padding: "0 12px",
296+
"font-size": "13px",
297+
"font-family": "var(--figma-font-sans, Inter, sans-serif)",
298+
"font-weight": "400",
299+
color: activeMenu() === menu.label
300+
? "var(--figma-accent-primary, #BFFF00)"
301+
: "var(--figma-text-secondary, #A0A0A0)",
302+
background: activeMenu() === menu.label
303+
? "rgba(191, 255, 0, 0.1)"
304+
: "transparent",
305+
border: "none",
306+
"border-radius": "var(--figma-radius-sm, 6px)",
307+
cursor: "pointer",
308+
transition: "all 100ms ease",
309+
"white-space": "nowrap",
310+
}}
311+
onMouseEnter={(e) => {
312+
if (activeMenu() !== menu.label) {
313+
(e.currentTarget as HTMLElement).style.color = "var(--figma-text-primary, #FFFFFF)";
314+
(e.currentTarget as HTMLElement).style.background = "rgba(255,255,255,0.05)";
315+
}
316+
// If any menu is open, switch to this one on hover
317+
if (activeMenu() !== null) {
318+
setActiveMenu(menu.label);
319+
}
320+
}}
321+
onMouseLeave={(e) => {
322+
if (activeMenu() !== menu.label) {
323+
(e.currentTarget as HTMLElement).style.color = "var(--figma-text-secondary, #A0A0A0)";
324+
(e.currentTarget as HTMLElement).style.background = "transparent";
325+
}
326+
}}
327+
>
328+
{menu.label}
329+
</button>
330+
331+
{/* Dropdown Menu */}
332+
<Show when={activeMenu() === menu.label}>
333+
<div
334+
style={{
335+
position: "absolute",
336+
top: "calc(100% + 4px)",
337+
left: "0",
338+
"min-width": "220px",
339+
background: "var(--figma-bg-secondary, #1A1A1A)",
340+
"border-radius": "var(--figma-radius-md, 8px)",
341+
border: "1px solid var(--figma-border-default, rgba(255,255,255,0.1))",
342+
padding: "6px 0",
343+
"box-shadow": "0 8px 32px rgba(0,0,0,0.5)",
344+
"z-index": "1",
345+
}}
346+
>
347+
<For each={menu.items}>
348+
{(item) => (
349+
<Show
350+
when={!item.separator}
351+
fallback={
352+
<div
353+
style={{
354+
height: "1px",
355+
background: "var(--figma-border-default, rgba(255,255,255,0.1))",
356+
margin: "6px 0",
357+
}}
358+
/>
359+
}
360+
>
361+
<button
362+
onClick={() => handleItemClick(item)}
363+
style={{
364+
width: "100%",
365+
display: "flex",
366+
"align-items": "center",
367+
"justify-content": "space-between",
368+
height: "28px",
369+
padding: "0 12px",
370+
"font-size": "13px",
371+
"font-family": "var(--figma-font-sans, Inter, sans-serif)",
372+
"font-weight": "400",
373+
color: "var(--figma-text-secondary, #A0A0A0)",
374+
background: "transparent",
375+
border: "none",
376+
cursor: "pointer",
377+
transition: "all 100ms ease",
378+
"text-align": "left",
379+
}}
380+
onMouseEnter={(e) => {
381+
(e.currentTarget as HTMLElement).style.color = "var(--figma-text-primary, #FFFFFF)";
382+
(e.currentTarget as HTMLElement).style.background = "rgba(191, 255, 0, 0.1)";
383+
}}
384+
onMouseLeave={(e) => {
385+
(e.currentTarget as HTMLElement).style.color = "var(--figma-text-secondary, #A0A0A0)";
386+
(e.currentTarget as HTMLElement).style.background = "transparent";
387+
}}
388+
>
389+
<span>{item.label}</span>
390+
<Show when={item.shortcut}>
391+
<span
392+
style={{
393+
"font-size": "11px",
394+
color: "var(--figma-text-muted, #808080)",
395+
"font-family": "ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Monaco, Consolas, monospace",
396+
}}
397+
>
398+
{item.shortcut}
399+
</span>
400+
</Show>
401+
</button>
402+
</Show>
403+
)}
404+
</For>
405+
</div>
406+
</Show>
407+
</div>
408+
)}
409+
</For>
410+
</div>
411+
</>
412+
);
413+
}
414+
122415
// ============================================================================
123416
// Main Layout Component
124417
// ============================================================================
@@ -346,36 +639,9 @@ export function FigmaDesktopLayout(props: ParentProps) {
346639
onMenuClick={() => setIsMenuOpen(!isMenuOpen())}
347640
/>
348641

349-
{/* MenuBar - Shows when hamburger menu is clicked */}
642+
{/* Figma-styled Menu Dropdown - Shows when hamburger menu is clicked */}
350643
<Show when={isMenuOpen()}>
351-
<div
352-
style={{
353-
position: "fixed",
354-
top: "53px",
355-
left: "179px", // Aligned with breadcrumbs
356-
"z-index": "2500",
357-
background: "#1A1A1A",
358-
"border-radius": "8px",
359-
border: "1px solid rgba(255,255,255,0.1)",
360-
padding: "8px 0",
361-
"box-shadow": "0 4px 16px rgba(0,0,0,0.4)",
362-
}}
363-
onClick={(e) => e.stopPropagation()}
364-
>
365-
<MenuBar />
366-
</div>
367-
{/* Backdrop to close menu */}
368-
<div
369-
style={{
370-
position: "fixed",
371-
top: "0",
372-
left: "0",
373-
right: "0",
374-
bottom: "0",
375-
"z-index": "2400",
376-
}}
377-
onClick={() => setIsMenuOpen(false)}
378-
/>
644+
<FigmaMenuDropdown onClose={() => setIsMenuOpen(false)} />
379645
</Show>
380646

381647
{/* Main Content Area - Activity Bar + Content + StatusBar always visible */}

0 commit comments

Comments
 (0)