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
7 changes: 7 additions & 0 deletions .changeset/embed-fill-host.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@ioai/lerobot-studio': minor
---

The embedded viewer now fills its host container. The package stylesheet is scoped to descendants of `.lerobot-root`, so the `h-full w-full` utilities on the root element itself never matched and the viewer collapsed to its content height. A base-layer `.lerobot-root` rule now sets `position: relative`, `width` / `height: 100%`, `min-width` / `min-height: 0`, and the theme `background-color` and `color`; host CSS passed through `className` still wins. In a host whose wrapper has a fixed height the viewer now stretches to it.

Below 640px of container width (the `@container/viewer` box, not the window) the episode sidebar moves under the player and stays resizable (drag the handle, or focus it and use the arrow keys; it is named "Resize episode list" and reports its size range through `aria-valuenow`, `aria-valuemin` and `aria-valuemax`). The sidebar follows the player in DOM and focus order, is moved rather than remounted when the container crosses 640px, and keeps the width the user chose. At the same width the playback bar wraps: progress on its own row, transport centred, FPS and version hidden.
5 changes: 5 additions & 0 deletions .changeset/navbar-phone-title.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@ioai/lerobot-studio': patch
---

The standalone navbar keeps the dataset name clear of the controls on phones: the name truncates with an ellipsis and shows the full name on hover, and the playback-bar toggle and GitHub link hide below 640px of window width.
5 changes: 5 additions & 0 deletions .changeset/shortcuts-own-keys.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@ioai/lerobot-studio': patch
---

Playback shortcuts (Space, arrow keys) no longer fire while a widget that owns those keys has focus: tabs, sliders, radios, checkboxes, menus, listboxes and resize handles. A focused button or link keeps Space for its own activation (one press, one click), while the arrow keys still step playback there; with focus on the page or an episode row, Space plays and pauses. Element checks are realm-safe for hosts that render into another window.
4 changes: 3 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions scripts/check-bundle-size.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ if (!Number.isFinite(scale) || scale <= 0 || scale > 1) {
// ceilings only move to cover upstream's growth. Heads are ~1-3% (web initial
// JS gzip is the tightest at ~0.2% and will need the next review).
const budgets = {
libEntry: { raw: 400_000, gzip: 125_000 },
// +5 KB raw head for the splitter ARIA values and Space-on-button handling
// (measured ~400.1 KB raw, just over the old 400,000-byte ceiling).
libEntry: { raw: 405_000, gzip: 125_000 },
libCss: { raw: 360_000, gzip: 110_000 },
webInitialJs: { raw: 2_700_000, gzip: 740_000 },
// +5 KB gzip head for the embed layout hook, resizable stacked sidebar and
// phone navbar (measured 722.7 KiB gzip, level with the old 740,000-byte ceiling).
webInitialJs: { raw: 2_700_000, gzip: 745_000 },
webInitialCss: { raw: 200_000, gzip: 25_000 },
libDataLoader: { raw: 280_000, gzip: 60_000 },
webDataLoader: { raw: 40_000, gzip: 10_000 },
Expand Down
17 changes: 9 additions & 8 deletions src/react/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ export const Navbar: React.FC<NavbarProps> = ({

return (
<nav className="sticky top-0 z-50 w-full border-b bg-background text-foreground">
<div className="flex h-12 items-center px-4 gap-4 relative">
<div className="relative grid h-12 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-2 px-3 sm:grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] sm:gap-4 sm:px-4">
{/* Left: Open & History */}
<div className="flex items-center gap-2 mr-auto">
<div className="flex min-w-0 items-center gap-2 justify-self-start">
{datasetName && onGoHome && (
<Tooltip>
<TooltipTrigger
Expand Down Expand Up @@ -269,7 +269,7 @@ export const Navbar: React.FC<NavbarProps> = ({

{/* Center: Title & Logo */}
<div
className="absolute left-1/2 top-1/2 flex max-w-[40vw] -translate-x-1/2 -translate-y-1/2 items-center gap-2 pointer-events-none"
className="flex min-w-0 items-center justify-center gap-2 sm:max-w-[40vw]"
role={isLoading ? 'status' : undefined}
aria-live={isLoading ? 'polite' : undefined}
>
Expand All @@ -282,6 +282,7 @@ export const Navbar: React.FC<NavbarProps> = ({
<img src="logo.svg" alt="LeRobot Studio Logo" className="h-5 w-5 opacity-90" />
) : null}
<span
data-testid="lerobot-navbar-title"
className={`block min-w-0 truncate text-sm font-semibold tracking-tight ${isLoading ? 'text-muted-foreground animate-pulse' : ''}`}
title={displayName}
>
Expand All @@ -290,11 +291,11 @@ export const Navbar: React.FC<NavbarProps> = ({
</div>

{/* Right: Controls */}
<div className="flex items-center gap-1 ml-auto">
<div className="flex items-center gap-1 justify-self-end">
{/* View Controls */}
{(onToggleSidebar || onTogglePlaybackBar) && (
<>
<div className="flex items-center gap-0.5 mr-2">
<div className="flex items-center gap-0.5 sm:mr-2">
{onToggleSidebar && (
<Tooltip>
<TooltipTrigger
Expand Down Expand Up @@ -326,7 +327,7 @@ export const Navbar: React.FC<NavbarProps> = ({
<Button
variant="ghost"
size="icon"
className="h-8 w-8 text-muted-foreground hover:text-foreground"
className="hidden h-8 w-8 text-muted-foreground hover:text-foreground sm:inline-flex"
onClick={onTogglePlaybackBar}
/>
}
Expand All @@ -345,7 +346,7 @@ export const Navbar: React.FC<NavbarProps> = ({
</Tooltip>
)}
</div>
<Separator orientation="vertical" className="h-4 mr-2" />
<Separator orientation="vertical" className="mr-2 hidden h-4 sm:block" />
</>
)}

Expand All @@ -356,7 +357,7 @@ export const Navbar: React.FC<NavbarProps> = ({
<Button
variant="ghost"
size="icon"
className="h-9 w-9 text-muted-foreground hover:text-foreground"
className="hidden h-9 w-9 text-muted-foreground hover:text-foreground sm:inline-flex"
asChild
>
<a
Expand Down
Loading
Loading