From 75691a0b33b390cfdda6da4122724417e766cee0 Mon Sep 17 00:00:00 2001 From: Laurids Kern Date: Fri, 9 Oct 2026 12:17:09 +0200 Subject: [PATCH 1/2] feat(ui): move workspace controls to a bar under the simulators The tools and platform menus sat in the first visible simulator's header beside its device controls. In the sidebar panel they now share one full-width bar under the simulators, tools on the left and platforms on the right, with menus opening upward. Fullscreen and a layout without visible platforms keep the bar above the tools. --- docs/devices.md | 2 +- src/ui/components/simulator-view.tsx | 5 ++--- src/ui/components/workspace.tsx | 29 +++++++++++++++++----------- tests/react-ui.test.ts | 7 +++++++ 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/docs/devices.md b/docs/devices.md index b5e2afe..ce12f81 100644 --- a/docs/devices.md +++ b/docs/devices.md @@ -14,7 +14,7 @@ Android logs need `adb` from an installed Android SDK. The reader checks `ANDROI ## Device panel -Open a new chat after installing. Open Mobile Dev in the sidebar or call `mobile_open_workspace` for the fullscreen view. Call `mobile_open_simulator` for the panel beside a chat. iOS opens by default, including when an iOS device and an Android device are both running. Android opens instead when it has the only running device. Enable both platforms from the toolbar to show the panels side by side. Each panel has a device dropdown, Home, App Switcher, and Screenshot. Pick a device in each panel. Use the iOS and Android toggles to show either, both, or neither simulator. Selecting a device boots it if needed, then connects its screen. A selected running device connects automatically. The panel uses Apple’s device bezel and screen mask from the installed DeviceKit assets, with a simple frame as a fallback when assets are unavailable. Use the settings button at the bottom right for appearance, text size, location, and the device frame. iOS also offers contrast; Android offers rotation. The menu shows only settings supported by the bundled backend. Click the screen to type or drag. Closing the panel closes its stream. +Open a new chat after installing. Open Mobile Dev in the sidebar or call `mobile_open_workspace` for the fullscreen view. Call `mobile_open_simulator` for the panel beside a chat. iOS opens by default, including when an iOS device and an Android device are both running. Android opens instead when it has the only running device. Enable both platforms from the platform menu to show the panels side by side. Each panel has a device dropdown, Home, App Switcher, and Screenshot. Pick a device in each panel. In the sidebar panel, the bar under the simulators holds the tools menu on the left and the platform menu on the right; fullscreen shows them above the tools. Use the platform menu to show either, both, or neither simulator. Selecting a device boots it if needed, then connects its screen. A selected running device connects automatically. The panel uses Apple’s device bezel and screen mask from the installed DeviceKit assets, with a simple frame as a fallback when assets are unavailable. Use the settings button at the bottom right for appearance, text size, location, and the device frame. iOS also offers contrast; Android offers rotation. The menu shows only settings supported by the bundled backend. Click the screen to type or drag. Closing the panel closes its stream. Use Select in the simulator toolbar to pause the screen. Hover to outline a component, then click to add a note. React Native development apps can supply runtime elements when accessibility omits a view. Drag to mark a region when neither source exposes it. Saved notes leave numbered blue bubbles. Notes attach text and available element details to your next chat message. The captured screen stays local for editing; annotations never attach screenshots. Click a bubble to edit or remove a note, or use Send to chat to send all notes for that device. If chat is unavailable, the panel keeps the notes and retries when you return. A sent or cleared batch starts again at 1. diff --git a/src/ui/components/simulator-view.tsx b/src/ui/components/simulator-view.tsx index cbba839..d1cf8ad 100644 --- a/src/ui/components/simulator-view.tsx +++ b/src/ui/components/simulator-view.tsx @@ -1,5 +1,5 @@ import { CameraIcon, HouseIcon, CopyIcon, PowerIcon, SmartphoneIcon, type LucideIcon } from "lucide-react"; -import { memo, useState, type ReactNode } from "react"; +import { memo, useState } from "react"; import { Button } from "./ui/button"; import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "./ui/empty"; import { DevicePicker } from "./device-picker"; @@ -14,7 +14,7 @@ const deviceButtons: { action: string; icon: LucideIcon; label: string }[] = [ // The stream controller owns canvas pixels and device control state after mount. // Keep this subtree stable so log batches never reset a live device. -export const SimulatorView = memo(function SimulatorView({ platform, visible, toolbar }: { platform: "ios" | "android"; visible: boolean; toolbar?: ReactNode }) { +export const SimulatorView = memo(function SimulatorView({ platform, visible }: { platform: "ios" | "android"; visible: boolean }) { const [annotations] = useState(() => new ScreenAnnotationsStore()); const label = platform === "ios" ? "iOS" : "Android"; const sidebar = document.documentElement.dataset.view !== "workspace"; @@ -22,7 +22,6 @@ export const SimulatorView = memo(function SimulatorView({ platform, visible, to return