Files
kandev/apps/web/components/app-status-bar/app-status-drawer.tsx
T
José Almeida 9c16d337a2 feat(web): add global app status surface (#1869)
* feat(web): add app status bar

* feat(web): add app status bar visibility toggle

* feat(web): persist status bar item order

* fix(web): refine app status bar behavior

* fix(web): polish app status bar presentation

* test(web): split plugin slot coverage groups

* fix(web): address status surface review feedback

* fix(web): stabilize status bar overlay tests
2026-07-23 12:28:54 +01:00

66 lines
2.2 KiB
TypeScript

"use client";
import { useMemo } from "react";
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle } from "@kandev/ui/drawer";
import { useAppStatusItems, type AppStatusItem } from "./app-status-items";
import { useAppStatusBarOrder } from "./use-app-status-bar-order";
type AppStatusDrawerProps = {
pathname: string;
activeWorkspaceId: string | null;
activeTaskId: string | null;
activeSessionId: string | null;
open: boolean;
onOpenChange: (open: boolean) => void;
};
export function AppStatusDrawer({
pathname,
activeWorkspaceId,
activeTaskId,
activeSessionId,
open,
onOpenChange,
}: AppStatusDrawerProps) {
const context = useMemo(
() => ({ pathname, activeWorkspaceId, activeTaskId, activeSessionId }),
[pathname, activeWorkspaceId, activeTaskId, activeSessionId],
);
const activeItems = useAppStatusItems(context);
const { projected } = useAppStatusBarOrder(activeItems);
const orderedItems = [...projected.left, ...projected.right];
return (
<Drawer open={open} onOpenChange={onOpenChange}>
<DrawerContent className="h-[min(32rem,calc(100dvh-16px))] max-h-[calc(100dvh-16px)] overflow-hidden pb-[max(0.5rem,env(safe-area-inset-bottom))]">
<div
data-testid="app-status-drawer"
className="flex min-h-0 flex-1 flex-col overflow-hidden rounded-xl bg-background"
>
<DrawerHeader className="shrink-0 border-b border-border/70 pb-3 text-left">
<DrawerTitle>Status</DrawerTitle>
</DrawerHeader>
<div className="min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-3">
<section className="space-y-1" aria-label="Application status items">
{orderedItems.map((item) => (
<DrawerStatusItem key={item.id} item={item} open={open} />
))}
</section>
</div>
</div>
</DrawerContent>
</Drawer>
);
}
function DrawerStatusItem({ item, open }: { item: AppStatusItem; open: boolean }) {
return (
<div
className="flex min-h-11 w-full min-w-0 items-center rounded-md px-3 hover:bg-muted/60 empty:hidden"
data-status-item-id={item.id}
>
{item.render({ presentation: "mobile-drawer", density: "full", drawerOpen: open })}
</div>
);
}