mirror of
https://github.com/block/buzz.git
synced 2026-10-27 20:41:57 +00:00
## Summary - align the multi-community rail with the content surface and balance its visible 10px side gutters - center Mobile pairing, start sessions on demand, and keep retry states inside the QR area - reveal the QR code and copy action with 250ms motion and use the standard loading spinner The rail was centered within its own box, but the adjacent sidebar added another 11px to the visible right gap. Mobile pairing also started before user intent, which could leave an idle session waiting for EOSE. ## Validation - `pnpm -C desktop build:e2e` - `pnpm -C desktop test` — 3,516 passed - `pnpm -C desktop exec playwright test tests/e2e/community-rail.spec.ts --project=smoke` — 19 passed - `pnpm -C desktop exec playwright test tests/e2e/mobile-pairing-qr.spec.ts --project=smoke` — 1 passed `pnpm -C desktop check` is currently blocked by the existing `src-tauri/src/managed_agents/runtime.rs` file-size baseline (2,220 lines; limit 2,216).
112 lines
4.3 KiB
TypeScript
112 lines
4.3 KiB
TypeScript
import { AnimatePresence, motion } from "motion/react";
|
|
import { AlertCircle } from "lucide-react";
|
|
|
|
import { SidebarRelayConnectionCard } from "@/features/sidebar/ui/SidebarRelayConnectionCard";
|
|
import type { useSidebarRelayConnectionCard } from "@/features/sidebar/ui/useSidebarRelayConnectionCard";
|
|
import { cn } from "@/shared/lib/cn";
|
|
import { useIsMobile } from "@/shared/hooks/use-mobile";
|
|
import { useRelayConnection } from "@/shared/api/useRelayConnection";
|
|
import { useSidebar } from "@/shared/ui/sidebar";
|
|
|
|
type RelayConnectionOverlayProps = {
|
|
card: ReturnType<typeof useSidebarRelayConnectionCard>;
|
|
errorMessage?: string;
|
|
hasCommunityRail?: boolean;
|
|
isHuddleDrawerOpen?: boolean;
|
|
};
|
|
|
|
/**
|
|
* Fixed bottom-left overlay that shows the relay reconnect card when the
|
|
* sidebar is collapsed. When the sidebar is open, the card lives in the
|
|
* sidebar footer instead (and this overlay is hidden). Offsets itself for
|
|
* the community rail (48px) and huddle drawer when present.
|
|
*
|
|
* Also surfaces non-unreachable disconnect errors (e.g. auth rejections)
|
|
* when the sidebar is hidden, since those errors are only rendered inside
|
|
* the sidebar content area which is off-canvas when collapsed.
|
|
*/
|
|
export function RelayConnectionOverlay({
|
|
card,
|
|
errorMessage,
|
|
hasCommunityRail,
|
|
isHuddleDrawerOpen,
|
|
}: RelayConnectionOverlayProps) {
|
|
const { open: sidebarOpen, openMobile } = useSidebar();
|
|
const isMobile = useIsMobile();
|
|
const connectionState = useRelayConnection();
|
|
|
|
// Show the overlay when the sidebar surface isn't visible:
|
|
// - Desktop: sidebar is collapsed (open === false)
|
|
// - Mobile: the sheet is closed (openMobile === false)
|
|
const isSidebarSurfaceHidden = isMobile ? !openMobile : !sidebarOpen;
|
|
const shouldShowReconnectCard =
|
|
card.showSidebarRelayConnectionCard && isSidebarSurfaceHidden;
|
|
|
|
// Show a non-unreachable error (e.g. auth rejection) when the sidebar is
|
|
// hidden and the reconnect card isn't already covering it.
|
|
const hasNonUnreachableError =
|
|
Boolean(errorMessage) &&
|
|
!card.hasRelayUnreachableError &&
|
|
connectionState === "disconnected";
|
|
const shouldShowErrorFallback =
|
|
hasNonUnreachableError &&
|
|
isSidebarSurfaceHidden &&
|
|
!shouldShowReconnectCard;
|
|
|
|
return (
|
|
<AnimatePresence>
|
|
{shouldShowReconnectCard ? (
|
|
<motion.div
|
|
animate={{ opacity: 1, y: 0 }}
|
|
className={cn(
|
|
"pointer-events-none fixed z-50 w-[284px]",
|
|
hasCommunityRail ? "left-[68px]" : "left-3",
|
|
isHuddleDrawerOpen
|
|
? "bottom-[calc(var(--buzz-huddle-drawer-height,0px)+12px)]"
|
|
: "bottom-3",
|
|
)}
|
|
exit={{ opacity: 0, y: 20 }}
|
|
initial={{ opacity: 0, y: -20 }}
|
|
key="relay-connection-overlay"
|
|
transition={{ duration: 0.25, ease: [0.22, 1, 0.36, 1] }}
|
|
>
|
|
<div className="pointer-events-auto rounded-xl bg-background shadow-md">
|
|
<SidebarRelayConnectionCard
|
|
isConnected={card.isRelayConnectionSuccess}
|
|
isReconnectPending={card.isRelayReconnectPending}
|
|
isWaitingOnReconnectHook={card.isWaitingOnReconnectHook}
|
|
onDismiss={card.onDismissRelayConnectionCard}
|
|
onReconnect={card.onReconnectRelay}
|
|
/>
|
|
</div>
|
|
</motion.div>
|
|
) : null}
|
|
{shouldShowErrorFallback ? (
|
|
<motion.div
|
|
animate={{ opacity: 1, y: 0 }}
|
|
className={cn(
|
|
"pointer-events-none fixed z-50 w-[284px]",
|
|
hasCommunityRail ? "left-[68px]" : "left-3",
|
|
isHuddleDrawerOpen
|
|
? "bottom-[calc(var(--buzz-huddle-drawer-height,0px)+12px)]"
|
|
: "bottom-3",
|
|
)}
|
|
exit={{ opacity: 0, y: 20 }}
|
|
initial={{ opacity: 0, y: -20 }}
|
|
key="relay-error-overlay"
|
|
transition={{ duration: 0.25, ease: [0.22, 1, 0.36, 1] }}
|
|
>
|
|
<div
|
|
className="pointer-events-auto flex items-center gap-2 rounded-xl bg-background px-3 py-2.5 text-sm text-destructive shadow-md"
|
|
data-testid="relay-error-overlay"
|
|
role="alert"
|
|
>
|
|
<AlertCircle aria-hidden="true" className="h-4 w-4 shrink-0" />
|
|
<span className="flex-1">{errorMessage}</span>
|
|
</div>
|
|
</motion.div>
|
|
) : null}
|
|
</AnimatePresence>
|
|
);
|
|
}
|