"use client" /** * WhatsNewSheet — compact floating rail for one featured release note. * * Composes {@link WhatsNewAnnouncementCard} in `FloatingSheetPanel` (`size="sm"`). * Left rail, content height, scroll body + pinned footer. Hero uses * {@link WhatsNewLeoHero} (Leo invited + one-shot dot burst), not screenshots. * * App wiring (catalog, seen list, routes) lives in the consumer shell. */ import * as React from "react" import type { CSSProperties } from "react" import { cn } from "../../lib/utils" import { Badge } from "./badge" import { Button } from "./button" import { FloatingSheetPanel, FloatingSheetPanelBody, FloatingSheetPanelContent, FloatingSheetPanelFooter, } from "./floating-sheet-panel" import { SheetTitle } from "./sheet" import { Tip } from "./tip" import { WhatsNewAnnouncementCard, type WhatsNewHighlight, } from "./whats-new-announcement-card" import { WhatsNewLeoHero } from "./whats-new-leo-hero" /** Left rail, hugs content; scroll body + pinned footer when tall. */ export const WHATS_NEW_SHEET_PANEL_PROPS = { side: "left" as const, contentSlot: "whats-new-sheet", size: "sm" as const, resizable: false, className: "!h-auto max-h-[min(85vh,38rem)]", style: { top: "auto", bottom: "0.5rem", height: "auto", maxHeight: "min(85vh, 38rem)", } satisfies CSSProperties, /** Hub stays clickable; close only via dismiss, Esc, or footer actions. */ onInteractOutside: (event: { preventDefault: () => void }) => { event.preventDefault() }, } export interface WhatsNewReleaseItem { title: string eyebrow?: string sourceLabel?: string highlights?: WhatsNewHighlight[] /** Used when `highlights` is empty. */ body?: string primaryActionLabel?: string } export interface WhatsNewSheetFeaturedUpdate { id: string item: WhatsNewReleaseItem brandColor: string } export interface WhatsNewSheetProps { open: boolean onOpenChange: (open: boolean) => void featured: WhatsNewSheetFeaturedUpdate onDismiss: (id: string) => void onPrimaryAction: () => void /** Secondary footer action, e.g. Release history link. */ footerSecondary?: React.ReactNode } export function WhatsNewSheet({ open, onOpenChange, featured, onDismiss, onPrimaryAction, footerSecondary, }: WhatsNewSheetProps) { const { id, item, brandColor } = featured const resolvedBrand = brandColor || "var(--brand)" const [playKey, setPlayKey] = React.useState(0) React.useEffect(() => { if (open) setPlayKey(key => key + 1) }, [open, id]) function handleDismiss() { onDismiss(id) onOpenChange(false) } return ( {item.title} } /> {footerSecondary} ) } export interface WhatsNewSheetEmptyProps { open: boolean onOpenChange: (open: boolean) => void footerSecondary?: React.ReactNode } export function WhatsNewSheetEmpty({ open, onOpenChange, footerSecondary, }: WhatsNewSheetEmptyProps) { return ( What's new

No release notes for your role right now.

{footerSecondary}
) } /** Megaphone trigger for the utility bar and profile menu. */ export function WhatsNewSheetTrigger({ className, open, unseenCount, onOpen, }: { className?: string open: boolean unseenCount: number onOpen: () => void }) { return (