Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions blendmate-app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { useState, useEffect } from "react";
import { useBlendmateSocket } from "./useBlendmateSocket";
import { Card } from "@/components/ui/card";
import {BackgroundPaths} from "@/components/ui/BackgroundPaths";
import { ScrollArea } from "@/components/ui/scroll-area";
import Outliner from "./components/Outliner";
import NodeHelpView from "./components/NodeHelpView";
import EventsLogPanel from "./components/panels/EventsLogPanel";
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
import { Outliner, NodeHelpView } from "@/components";
import { EventsLogPanel } from "@/components/panels";
import { Activity, LayoutGrid, Info, ListTree } from "lucide-react";
import BackgroundPaths from "@/components/ui/BackgroundPaths";
import { ResizableHandle, ResizablePanel, ResizablePanelGroup, Card, ScrollArea } from "@/components/ui";

// Color tokens (increased opacity for debug visibility)

Expand Down
69 changes: 69 additions & 0 deletions blendmate-app/src/app/AppShell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { useEffect } from "react";
import { TopBar } from "./layout/TopBar";
import { CenterWorkspace } from "./layout/CenterWorkspace";
import { RightInspector } from "./layout/RightInspector";
import { BottomBar } from "./layout/BottomBar";
import { useLayoutStore } from "../state/layoutStore";

export type SocketStatus = "connecting" | "connected" | "disconnected" | string;

export type AppShellProps = {
socketStatus: SocketStatus;
lastMessage: any;
sendJson: (json: any) => void;
};

export function AppShell(props: AppShellProps) {
const layout = useLayoutStore();

useEffect(() => {
// Sanity marker: guarantees you're seeing the vNext shell build.
// eslint-disable-next-line no-console
console.info("Blendmate UI vNext Shell mounted");
}, []);

return (
<div className="h-screen w-screen overflow-hidden">
<TopBar
socketStatus={props.socketStatus}
inspectorOpen={layout.inspectorOpen}
onToggleInspector={layout.toggleInspector}
onResetLayout={layout.resetLayout}
/>

<div className="flex h-[calc(100vh-88px)] w-full">
<div className="flex min-w-0 flex-1">
<CenterWorkspace />
</div>

{layout.inspectorOpen ? (
<div className="w-[360px] shrink-0 border-l border-white/10">
<RightInspector />
</div>
) : null}
</div>

{layout.bottomOpen ? (
<div className="h-[44px] border-t border-white/10">
<BottomBar
lastMessage={props.lastMessage}
sendJson={props.sendJson}
onToggleBottom={layout.toggleBottom}
vnextBadge
/>
</div>
) : (
<div className="h-[44px] border-t border-white/10 flex items-center justify-between px-3 text-xs opacity-80">
<span>Bottom bar hidden</span>
<button
className="px-2 py-1 rounded hover:bg-white/10"
onClick={layout.toggleBottom}
type="button"
>
Show
</button>
</div>
)}
</div>
);
}
60 changes: 60 additions & 0 deletions blendmate-app/src/app/layout/BottomBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useMemo, useState } from "react";

export type BottomBarProps = {
lastMessage: any;
sendJson: (json: any) => void;
onToggleBottom: () => void;
vnextBadge?: boolean;
};

export function BottomBar(props: BottomBarProps) {
const [prompt, setPrompt] = useState("");

const last = useMemo(() => {
if (!props.lastMessage) return "Awaiting Blender signal…";
try {
return "[RECV] " + JSON.stringify(props.lastMessage);
} catch {
return "[RECV] (unserializable message)";
}
}, [props.lastMessage]);

return (
<div className="h-full flex items-center gap-2 px-3" data-tauri-drag-region>
{props.vnextBadge ? (
<span className="text-[11px] px-2 py-1 rounded bg-white/10 shrink-0">vNext</span>
) : null}

<button
type="button"
className="text-xs px-2 py-1 rounded hover:bg-white/10 shrink-0"
onClick={props.onToggleBottom}
title="Hide bottom bar"
>
Hide
</button>

<div className="flex-1 min-w-0">
<input
className="w-full bg-white/5 border border-white/10 rounded px-3 py-2 text-sm outline-none"
placeholder="Ask your soulmate anything…"
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
/>
</div>

<button
type="button"
className="text-xs px-2 py-1 rounded hover:bg-white/10 shrink-0"
onClick={() => props.sendJson({ type: "ping" })}
title="Send ping"
>
Ping
</button>

<div className="max-w-[40%] min-w-[240px] truncate text-xs opacity-70" title={last}>
{last}
</div>
</div>
);
}
21 changes: 21 additions & 0 deletions blendmate-app/src/app/layout/CenterWorkspace.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export function CenterWorkspace() {
return (
<div className="flex h-full w-full flex-col">
<div className="h-[36px] flex items-center gap-2 px-3 border-b border-white/10">
<div className="text-xs px-2 py-1 rounded bg-white/10">Workspace</div>
<div className="text-xs opacity-60">tabs/splits later</div>
</div>

<div className="flex-1 min-h-0 p-4">
<div className="h-full w-full rounded-xl border border-white/10 flex items-center justify-center">
<div className="text-sm opacity-80 text-center max-w-[520px] px-6">
<div className="font-medium mb-2">Sandbox canvas</div>
<div className="opacity-70">
This is the vNext shell baseline. We'll add tabs, panels, and workflows on top of this.
</div>
</div>
</div>
</div>
</div>
);
}
13 changes: 13 additions & 0 deletions blendmate-app/src/app/layout/RightInspector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export function RightInspector() {
return (
<div className="h-full w-full p-3">
<div className="text-xs opacity-70 mb-2">Inspector</div>
<div className="rounded-xl border border-white/10 p-3">
<div className="text-sm font-medium mb-1">Nothing selected</div>
<div className="text-sm opacity-70">
Contextual help will appear here (tools, nodes, selection mode, shortcuts…).
</div>
</div>
</div>
);
}
62 changes: 62 additions & 0 deletions blendmate-app/src/app/layout/TopBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import type { SocketStatus } from "../AppShell";

export type TopBarProps = {
socketStatus: SocketStatus;
inspectorOpen: boolean;
onToggleInspector: () => void;
onResetLayout: () => void;
};

function statusLabel(s: SocketStatus) {
if (s === "connected") return "Connected";
if (s === "connecting") return "Connecting…";
if (s === "disconnected") return "Disconnected";
return String(s || "Unknown");
}

export function TopBar(props: TopBarProps) {
const connected = props.socketStatus === "connected";

return (
<div
className="h-[44px] flex items-center justify-between px-3 border-b border-white/10"
data-tauri-drag-region
>
<div className="flex items-center gap-3" data-tauri-drag-region>
<div className="font-semibold tracking-tight" data-tauri-drag-region>
Blendmate
</div>
<span className="text-xs px-2 py-1 rounded bg-white/10" data-tauri-drag-region>
vNext Shell
</span>
</div>

<div className="flex items-center gap-2">
<div className="flex items-center gap-2 px-2 py-1 rounded bg-white/5">
<span
className={"inline-block h-2 w-2 rounded-full " + (connected ? "bg-green-500" : "bg-red-500")}
aria-label="socket-status"
/>
<span className="text-xs opacity-80">{statusLabel(props.socketStatus)}</span>
</div>

<button
type="button"
className={"text-xs px-2 py-1 rounded hover:bg-white/10 " + (props.inspectorOpen ? "bg-white/10" : "")}
onClick={props.onToggleInspector}
>
Inspector
</button>

<button
type="button"
className="text-xs px-2 py-1 rounded hover:bg-white/10"
onClick={props.onResetLayout}
title="Reset layout"
>
Reset
</button>
</div>
</div>
);
}
5 changes: 5 additions & 0 deletions blendmate-app/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Barrel file for components
export { default as Outliner } from "./Outliner";
export { default as NodeHelpView } from "./NodeHelpView";
export * from "./ui";

5 changes: 5 additions & 0 deletions blendmate-app/src/components/panels/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { default as ChatPanel } from "./ChatPanel";
export { default as EventsLogPanel } from "./EventsLogPanel";
export { default as NodesHelpPanel } from "./NodesHelpPanel";
export { default as StatsPanel } from "./StatsPanel";

Loading
Loading