diff --git a/apps/web/client/src/app/project/[id]/_components/left-panel/design-panel/index.tsx b/apps/web/client/src/app/project/[id]/_components/left-panel/design-panel/index.tsx
index 2ca8c8973c..f70ff96b0f 100644
--- a/apps/web/client/src/app/project/[id]/_components/left-panel/design-panel/index.tsx
+++ b/apps/web/client/src/app/project/[id]/_components/left-panel/design-panel/index.tsx
@@ -1,10 +1,13 @@
-import { useEditorEngine } from '@/components/store/editor';
-import { transKeys } from '@/i18n/keys';
+import { observer } from 'mobx-react-lite';
+import { useTranslations } from 'next-intl';
+
import { LeftPanelTabValue } from '@onlook/models';
+import { Button } from '@onlook/ui/button';
import { Icons } from '@onlook/ui/icons';
import { cn } from '@onlook/ui/utils';
-import { observer } from 'mobx-react-lite';
-import { useTranslations } from 'next-intl';
+
+import { useEditorEngine } from '@/components/store/editor';
+import { transKeys } from '@/i18n/keys';
import { BranchesTab } from './branches-tab';
import { BrandTab } from './brand-tab';
import { HelpButton } from './help-button';
@@ -16,38 +19,41 @@ import { ZoomControls } from './zoom-controls';
const tabs: {
value: LeftPanelTabValue;
icon: React.ReactNode;
- label: any,
- disabled?: boolean
-}[] =
- [
- {
- value: LeftPanelTabValue.LAYERS,
- icon: ,
- label: transKeys.editor.panels.layers.tabs.layers,
- },
- {
- value: LeftPanelTabValue.BRAND,
- icon: ,
- label: transKeys.editor.panels.layers.tabs.brand,
- },
- {
- value: LeftPanelTabValue.PAGES,
- icon: ,
- label: transKeys.editor.panels.layers.tabs.pages,
- },
- {
- value: LeftPanelTabValue.IMAGES,
- icon: ,
- label: transKeys.editor.panels.layers.tabs.images,
- },
- {
- value: LeftPanelTabValue.BRANCHES,
- icon: ,
- label: transKeys.editor.panels.layers.tabs.branches,
- },
- ];
+ label: any;
+ disabled?: boolean;
+}[] = [
+ {
+ value: LeftPanelTabValue.LAYERS,
+ icon: ,
+ label: transKeys.editor.panels.layers.tabs.layers,
+ },
+ {
+ value: LeftPanelTabValue.BRAND,
+ icon: ,
+ label: transKeys.editor.panels.layers.tabs.brand,
+ },
+ {
+ value: LeftPanelTabValue.PAGES,
+ icon: ,
+ label: transKeys.editor.panels.layers.tabs.pages,
+ },
+ {
+ value: LeftPanelTabValue.IMAGES,
+ icon: ,
+ label: transKeys.editor.panels.layers.tabs.images,
+ },
+ {
+ value: LeftPanelTabValue.BRANCHES,
+ icon: ,
+ label: transKeys.editor.panels.layers.tabs.branches,
+ },
+];
+
+interface DesignPanelProps {
+ onClose?: () => void;
+}
-export const DesignPanel = observer(() => {
+export const DesignPanel = observer(({ onClose }: DesignPanelProps) => {
const editorEngine = useEditorEngine();
const t = useTranslations();
const isLocked = editorEngine.state.leftPanelLocked;
@@ -98,21 +104,19 @@ export const DesignPanel = observer(() => {
};
return (
-
+
{/* Left sidebar with tabs */}
-
+
{tabs.map((tab) => (
))}
-
+
@@ -132,8 +136,18 @@ export const DesignPanel = observer(() => {
{/* Content panel */}
{editorEngine.state.leftPanelTab && (
<>
-
-
+
+
+ {onClose && (
+
+ )}
{selectedTab === LeftPanelTabValue.LAYERS &&
}
{selectedTab === LeftPanelTabValue.BRAND &&
}
{selectedTab === LeftPanelTabValue.PAGES &&
}
@@ -143,7 +157,7 @@ export const DesignPanel = observer(() => {
{/* Invisible padding area that maintains hover state */}
- {!isLocked &&
}
+ {!isLocked &&
}
>
)}
diff --git a/apps/web/client/src/app/project/[id]/_components/left-panel/index.tsx b/apps/web/client/src/app/project/[id]/_components/left-panel/index.tsx
index dc8fc0e5b6..3390764c0c 100644
--- a/apps/web/client/src/app/project/[id]/_components/left-panel/index.tsx
+++ b/apps/web/client/src/app/project/[id]/_components/left-panel/index.tsx
@@ -1,18 +1,38 @@
-import { useEditorEngine } from "@/components/store/editor";
-import { EditorMode } from "@onlook/models";
-import { cn } from "@onlook/ui/utils";
-import { observer } from "mobx-react-lite";
-import { CodePanel } from "./code-panel";
-import { DesignPanel } from "./design-panel";
+import { observer } from 'mobx-react-lite';
-export const LeftPanel = observer(() => {
+import { EditorMode } from '@onlook/models';
+import { cn } from '@onlook/ui/utils';
+
+import { useEditorEngine } from '@/components/store/editor';
+import { CodePanel } from './code-panel';
+import { DesignPanel } from './design-panel';
+
+interface LeftPanelProps {
+ onClose?: () => void;
+}
+
+export const LeftPanel = observer(({ onClose }: LeftPanelProps) => {
const editorEngine = useEditorEngine();
- return <>
-
-
-
-
-
-
- >;
-});
\ No newline at end of file
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+});
diff --git a/apps/web/client/src/app/project/[id]/_components/main.tsx b/apps/web/client/src/app/project/[id]/_components/main.tsx
index 4109496d6f..ff0547682f 100644
--- a/apps/web/client/src/app/project/[id]/_components/main.tsx
+++ b/apps/web/client/src/app/project/[id]/_components/main.tsx
@@ -1,17 +1,29 @@
'use client';
-import { useEditorEngine } from '@/components/store/editor';
-import { SubscriptionModal } from '@/components/ui/pricing-modal';
-import { SettingsModalWithProjects } from '@/components/ui/settings-modal/with-project';
+import { useEffect, useRef } from 'react';
+import { useRouter } from 'next/navigation';
+import { observer } from 'mobx-react-lite';
+
import { EditorAttributes } from '@onlook/constants';
-import { EditorMode } from '@onlook/models';
+import { EditorMode, LeftPanelTabValue } from '@onlook/models';
import { Button } from '@onlook/ui/button';
+import {
+ ContextMenu,
+ ContextMenuContent,
+ ContextMenuItem,
+ ContextMenuSeparator,
+ ContextMenuSub,
+ ContextMenuSubContent,
+ ContextMenuSubTrigger,
+ ContextMenuTrigger,
+} from '@onlook/ui/context-menu';
import { Icons } from '@onlook/ui/icons';
import { TooltipProvider } from '@onlook/ui/tooltip';
import { cn } from '@onlook/ui/utils';
-import { observer } from 'mobx-react-lite';
-import { useRouter } from 'next/navigation';
-import { useEffect, useRef } from 'react';
+
+import { useEditorEngine } from '@/components/store/editor';
+import { SubscriptionModal } from '@/components/ui/pricing-modal';
+import { SettingsModalWithProjects } from '@/components/ui/settings-modal/with-project';
import { usePanelMeasurements } from '../_hooks/use-panel-measure';
import { useStartProject } from '../_hooks/use-start-project';
import { BottomBar } from './bottom-bar';
@@ -32,15 +44,23 @@ export const Main = observer(() => {
rightPanelRef,
);
+ const handleSidebarClick = (tab: LeftPanelTabValue) => {
+ editorEngine.state.leftPanelTab = tab;
+ editorEngine.state.leftPanelLocked = true;
+ };
+
+ const handleClosePanel = () => {
+ editorEngine.state.leftPanelTab = null;
+ editorEngine.state.leftPanelLocked = false;
+ };
+
useEffect(() => {
function handleGlobalWheel(event: WheelEvent) {
if (!(event.ctrlKey || event.metaKey)) {
return;
}
- const canvasContainer = document.getElementById(
- EditorAttributes.CANVAS_CONTAINER_ID,
- );
+ const canvasContainer = document.getElementById(EditorAttributes.CANVAS_CONTAINER_ID);
if (canvasContainer?.contains(event.target as Node | null)) {
return;
}
@@ -56,14 +76,16 @@ export const Main = observer(() => {
if (error) {
return (
-
+
-
+
Error starting project: {error}
-
@@ -72,8 +94,8 @@ export const Main = observer(() => {
if (!isProjectReady) {
return (
-
-
+
);
@@ -81,19 +103,78 @@ export const Main = observer(() => {
return (
-
-
+
+
+
+
+
+
+
+
+
+
+ Add Element
+
+
+
+ Add Component
+
+
+
+
+
+ Panels
+
+
+ handleSidebarClick(LeftPanelTabValue.LAYERS)}
+ >
+ Layers
+
+ handleSidebarClick(LeftPanelTabValue.BRAND)}
+ >
+ Brand
+
+ handleSidebarClick(LeftPanelTabValue.PAGES)}
+ >
+ Pages
+
+ handleSidebarClick(LeftPanelTabValue.IMAGES)}
+ >
+ Images
+
+
+ handleSidebarClick(LeftPanelTabValue.BRANCHES)}
+ >
+ Branches
+
+
+
+
+ void editorEngine.copy.copy()}>
+
+ Copy
+ ⌘ C
+
+ void editorEngine.copy.paste()}>
+
+ Paste
+ ⌘ V
+
+
+
{/* Left Panel */}
-
-
+
+
{/* EditorBar anchored between panels */}
{
@@ -129,6 +210,6 @@ export const Main = observer(() => {
-
+
);
});