diff --git a/package.json b/package.json
index 53674b2..c7809ef 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,8 @@
"@types/node": "^24.0.14",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
+ "mobx": "^6.13.7",
+ "mobx-react-lite": "^4.1.0",
"radix-ui": "^1.4.2",
"react": "^19.0.0",
"react-dom": "^19.0.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 50700e9..dcd6d8b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -38,6 +38,12 @@ importers:
clsx:
specifier: ^2.1.1
version: 2.1.1
+ mobx:
+ specifier: ^6.13.7
+ version: 6.13.7
+ mobx-react-lite:
+ specifier: ^4.1.0
+ version: 4.1.0(mobx@6.13.7)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
radix-ui:
specifier: ^1.4.2
version: 1.4.2(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
@@ -2037,6 +2043,22 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ mobx-react-lite@4.1.0:
+ resolution: {integrity: sha512-QEP10dpHHBeQNv1pks3WnHRCem2Zp636lq54M2nKO2Sarr13pL4u6diQXf65yzXUn0mkk18SyIDCm9UOJYTi1w==}
+ peerDependencies:
+ mobx: ^6.9.0
+ react: ^16.8.0 || ^17 || ^18 || ^19
+ react-dom: '*'
+ react-native: '*'
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+ react-native:
+ optional: true
+
+ mobx@6.13.7:
+ resolution: {integrity: sha512-aChaVU/DO5aRPmk1GX8L+whocagUUpBQqoPtJk+cm7UOXUk87J4PeWCh6nNmTTIfEhiR9DI/+FnA8dln/hTK7g==}
+
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -4439,6 +4461,16 @@ snapshots:
mkdirp@3.0.1: {}
+ mobx-react-lite@4.1.0(mobx@6.13.7)(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ dependencies:
+ mobx: 6.13.7
+ react: 19.1.0
+ use-sync-external-store: 1.5.0(react@19.1.0)
+ optionalDependencies:
+ react-dom: 19.1.0(react@19.1.0)
+
+ mobx@6.13.7: {}
+
ms@2.1.3: {}
nanoid@3.3.11: {}
diff --git a/src/components/common/main-menu.tsx b/src/components/common/main-menu.tsx
new file mode 100644
index 0000000..12dbcb4
--- /dev/null
+++ b/src/components/common/main-menu.tsx
@@ -0,0 +1,17 @@
+import { Button } from "../ui/button";
+import { observer } from "mobx-react-lite";
+import { useAccountStore } from "@/contexts/AccountContext";
+
+export const MainMenu = observer(() => {
+ const { isMainMenuOpen, setIsMainMenuOpen } = useAccountStore();
+ return (
+
+
+
+ );
+});
diff --git a/src/components/interaction-panel/chat.tsx b/src/components/interaction-panel/chat.tsx
new file mode 100644
index 0000000..727010e
--- /dev/null
+++ b/src/components/interaction-panel/chat.tsx
@@ -0,0 +1,24 @@
+import { useAccountStore } from "@/contexts/AccountContext";
+import { Button } from "../ui/button";
+import { observer } from "mobx-react-lite";
+
+export const Chat = observer(() => {
+ const { isSandboxOpen, setIsSandboxOpen, isMainMenuOpen, setIsMainMenuOpen } =
+ useAccountStore();
+
+ return (
+
+
+
+ );
+});
diff --git a/src/components/interaction-panel/sandbox.tsx b/src/components/interaction-panel/sandbox.tsx
new file mode 100644
index 0000000..1126f0a
--- /dev/null
+++ b/src/components/interaction-panel/sandbox.tsx
@@ -0,0 +1,15 @@
+import { useAccountStore } from "@/contexts/AccountContext";
+import { observer } from "mobx-react-lite";
+
+export const Sandbox = observer(() => {
+ const { isSandboxOpen } = useAccountStore();
+
+ return (
+
+ SANDBOOOOX
+
+ );
+});
diff --git a/src/contexts/AccountContext.tsx b/src/contexts/AccountContext.tsx
new file mode 100644
index 0000000..e0a6ead
--- /dev/null
+++ b/src/contexts/AccountContext.tsx
@@ -0,0 +1,47 @@
+import { createContext, useContext, useState } from "react";
+import { AccountStore } from "@/store/account";
+
+interface StoreProviderState {
+ store?: AccountStore;
+ setStore: (store: AccountStore) => void;
+}
+
+interface StoreProviderProps {
+ children: React.ReactNode;
+}
+
+const initialState: StoreProviderState = {
+ store: undefined,
+ setStore: () => null,
+};
+
+const AccountStoreProviderContext = createContext(initialState);
+const _AccountStore = new AccountStore();
+
+export function AccountStoreProvider({
+ children,
+ ...props
+}: StoreProviderProps) {
+ const [_store, _setStore] = useState(_AccountStore);
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function useAccountStore() {
+ const context = useContext(AccountStoreProviderContext);
+ if (context === undefined) {
+ throw new Error("useStoreProvider must be used within a StoreProvider");
+ }
+
+ return _AccountStore;
+}
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
new file mode 100644
index 0000000..79e74f1
--- /dev/null
+++ b/src/lib/constants.ts
@@ -0,0 +1,3 @@
+export const LS_TOKENS = {
+ isMainMenuOpen: "isMainMenuOpen",
+};
diff --git a/src/main.tsx b/src/main.tsx
index 10f7546..67ba82c 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -9,6 +9,7 @@ import "./styles.css";
import reportWebVitals from "./reportWebVitals.ts";
import { Toaster } from "./components/ui/toaster.tsx";
import { TooltipProvider } from "./components/ui/tooltip.tsx";
+import { AccountStoreProvider } from "./contexts/AccountContext.tsx";
// Create a new router instance
const router = createRouter({
@@ -33,10 +34,12 @@ if (rootElement && !rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement);
root.render(
-
-
-
-
+
+
+
+
+
+
,
);
}
diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts
index d204c26..93a4947 100644
--- a/src/routeTree.gen.ts
+++ b/src/routeTree.gen.ts
@@ -9,8 +9,14 @@
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
import { Route as rootRouteImport } from './routes/__root'
+import { Route as InteractionPanelRouteImport } from './routes/interaction-panel'
import { Route as IndexRouteImport } from './routes/index'
+const InteractionPanelRoute = InteractionPanelRouteImport.update({
+ id: '/interaction-panel',
+ path: '/interaction-panel',
+ getParentRoute: () => rootRouteImport,
+} as any)
const IndexRoute = IndexRouteImport.update({
id: '/',
path: '/',
@@ -19,28 +25,39 @@ const IndexRoute = IndexRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
+ '/interaction-panel': typeof InteractionPanelRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
+ '/interaction-panel': typeof InteractionPanelRoute
}
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
+ '/interaction-panel': typeof InteractionPanelRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
- fullPaths: '/'
+ fullPaths: '/' | '/interaction-panel'
fileRoutesByTo: FileRoutesByTo
- to: '/'
- id: '__root__' | '/'
+ to: '/' | '/interaction-panel'
+ id: '__root__' | '/' | '/interaction-panel'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
+ InteractionPanelRoute: typeof InteractionPanelRoute
}
declare module '@tanstack/react-router' {
interface FileRoutesByPath {
+ '/interaction-panel': {
+ id: '/interaction-panel'
+ path: '/interaction-panel'
+ fullPath: '/interaction-panel'
+ preLoaderRoute: typeof InteractionPanelRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/': {
id: '/'
path: '/'
@@ -53,6 +70,7 @@ declare module '@tanstack/react-router' {
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
+ InteractionPanelRoute: InteractionPanelRoute,
}
export const routeTree = rootRouteImport
._addFileChildren(rootRouteChildren)
diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx
index d495d48..f5d6902 100644
--- a/src/routes/__root.tsx
+++ b/src/routes/__root.tsx
@@ -1,11 +1,24 @@
-import { Outlet, createRootRoute } from '@tanstack/react-router'
-import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
+// src/routes/__root.tsx
+import { Outlet, createRootRoute } from "@tanstack/react-router";
+import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
+import { MainMenu } from "@/components/common/main-menu";
export const Route = createRootRoute({
- component: () => (
- <>
-
-
- >
- ),
-})
+ component: RootLayout,
+});
+
+function RootLayout() {
+ return (
+
+ );
+}
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
index b1b72fc..af885e7 100644
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -1,3 +1,4 @@
+import { TextLink } from "@/components/ui/text-link";
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/")({
@@ -5,5 +6,9 @@ export const Route = createFileRoute("/")({
});
function App() {
- return hi
;
+ return (
+
+ Lable
+
+ );
}
diff --git a/src/routes/interaction-panel.tsx b/src/routes/interaction-panel.tsx
new file mode 100644
index 0000000..6fa1021
--- /dev/null
+++ b/src/routes/interaction-panel.tsx
@@ -0,0 +1,17 @@
+// src/routes/chat.tsx
+import { Chat } from "@/components/interaction-panel/chat";
+import { Sandbox } from "@/components/interaction-panel/sandbox";
+import { createFileRoute } from "@tanstack/react-router";
+
+export const Route = createFileRoute("/interaction-panel")({
+ component: InteractionPanelRoute,
+});
+
+function InteractionPanelRoute() {
+ return (
+
+
+
+
+ );
+}
diff --git a/src/store/account.ts b/src/store/account.ts
new file mode 100644
index 0000000..2f3c96c
--- /dev/null
+++ b/src/store/account.ts
@@ -0,0 +1,25 @@
+import { LS_TOKENS } from "@/lib/constants";
+import { makeAutoObservable } from "mobx";
+
+export class AccountStore {
+ isMainMenuOpen: boolean;
+ isSandboxOpen: boolean;
+
+ constructor() {
+ makeAutoObservable(this, {}, { autoBind: true });
+
+ const savedState = localStorage.getItem(LS_TOKENS.isMainMenuOpen);
+ this.isMainMenuOpen = savedState ? savedState === "true" : false;
+
+ this.isSandboxOpen = false;
+ }
+
+ setIsMainMenuOpen(value: boolean) {
+ this.isMainMenuOpen = value;
+ localStorage.setItem(LS_TOKENS.isMainMenuOpen, String(this.isMainMenuOpen));
+ }
+
+ setIsSandboxOpen(value: boolean) {
+ this.isSandboxOpen = value;
+ }
+}