Files
buzz/desktop/src/app/AppHuddleShell.tsx
klopez4212 ce3cf3cd25 Polish Huddle voice controls (#4694)
## Summary

- add a visible Stop control for interrupting agent speech
- make push-to-talk available by default while preserving manual mute
controls
- refine agent management, muted audio states, drawer layering, and
return navigation
- suppress duplicate notification sounds for Huddle messages

## Why

Huddles could trap users behind long agent speech, hide useful agent
controls, and leave temporary Huddle state visible after the call. The
drawer also regressed when the terminal substrate began painting behind
the rounded app surface.

## Validation

- `just desktop-ci`
- focused Huddle Playwright coverage for the drawer, speech
interruption, agent picker, and leave navigation

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
2026-08-04 13:07:50 -07:00

84 lines
2.7 KiB
TypeScript

import type * as React from "react";
import { AppHuddleBar } from "@/app/AppHuddleBar";
import * as BuzzTheme from "@/app/BuzzThemeSurfaces";
import { HuddleProvider } from "@/features/huddle";
import { RemindMeLaterProvider } from "@/features/reminders/ui/RemindMeLaterProvider";
import { cn } from "@/shared/lib/cn";
type AppHuddleShellProps = {
children: React.ReactNode;
currentPubkey?: string;
isCompanionOpen: boolean;
isDrawerOpen: boolean;
isRoom: boolean;
onCompanionOpen: () => void;
onHuddleStartPendingChange: (pending: boolean) => void;
onHuddleStarted: (ephemeralChannelId: string) => void | Promise<void>;
onShowHuddleInMainApp: (ephemeralChannelId: string) => void;
onViewHuddleChannel: (ephemeralChannelId: string) => void;
onVisibilityChange: (visible: boolean) => void;
};
export function AppHuddleShell({
children,
currentPubkey,
isCompanionOpen,
isDrawerOpen,
isRoom,
onCompanionOpen,
onHuddleStartPendingChange,
onHuddleStarted,
onShowHuddleInMainApp,
onViewHuddleChannel,
onVisibilityChange,
}: AppHuddleShellProps) {
return (
<HuddleProvider
ownsAudioSession={!isRoom}
onHuddleStartPendingChange={
isRoom ? undefined : onHuddleStartPendingChange
}
onHuddleStarted={isRoom ? undefined : onHuddleStarted}
onShowHuddleInMainApp={isRoom ? undefined : onShowHuddleInMainApp}
onViewHuddleChannel={isRoom ? undefined : onViewHuddleChannel}
>
<RemindMeLaterProvider pubkey={currentPubkey}>
<div
className="buzz-huddle-shell relative h-dvh overflow-hidden overscroll-none"
data-huddle-open={isDrawerOpen}
data-huddle-window={isRoom}
>
<div
aria-hidden="true"
className={cn(
"buzz-huddle-drawer-backdrop",
isDrawerOpen && "buzz-huddle-drawer-backdrop-open",
)}
/>
<div
className={cn(
"buzz-huddle-app-surface z-10 flex min-h-0 flex-row overflow-hidden bg-background",
isDrawerOpen &&
(isRoom
? "buzz-huddle-app-surface-room-open"
: "buzz-huddle-app-surface-open"),
)}
>
<BuzzTheme.GradientLayer />
{children}
</div>
{isRoom || !isCompanionOpen ? (
<div className="absolute inset-x-0 bottom-0 z-[2] h-(--buzz-huddle-drawer-height)">
<AppHuddleBar
mode={isRoom ? "room" : "main"}
onOpenHuddleWindow={isRoom ? undefined : onCompanionOpen}
onVisibilityChange={onVisibilityChange}
/>
</div>
) : null}
</div>
</RemindMeLaterProvider>
</HuddleProvider>
);
}