diff --git a/README.md b/README.md index 2337b7c..8b00cf1 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ The package expects React 19 and Tailwind CSS 4. Install an exact release so a consumer upgrades deliberately: ```bash -pnpm add --save-exact @nextide/ui@2.1.0 +pnpm add --save-exact @nextide/ui@2.2.0 pnpm add --save-dev --save-exact tailwindcss@4.3.1 @tailwindcss/vite@4.3.1 ``` diff --git a/apps/playground/src/App.tsx b/apps/playground/src/App.tsx index cf5a162..1ee0841 100644 --- a/apps/playground/src/App.tsx +++ b/apps/playground/src/App.tsx @@ -14,12 +14,14 @@ import { BriefcaseBusiness, CalendarClock, Check, + Circle, Database, FileJson, FileText, Filter, Gauge, Layers3, + LoaderCircle, PanelRightClose, PanelRightOpen, PanelLeft, @@ -31,6 +33,7 @@ import { Sparkles, ServerCog, Video, + X, } from "lucide-react" import { AppShell } from "@nextide/ui/blocks/app-shell" @@ -2976,8 +2979,34 @@ function BlockPreview({ motionScale }: { motionScale: number }) { expanded: campaignsExpanded, action: { label: "Create campaign", icon: }, children: [ - { id: "summer-launch", label: "Summer launch" }, - { id: "partner-rollout", label: "Partner rollout" }, + { + id: "summer-launch", + label: "Summer launch", + status: "Completed", + tone: "success" as const, + statusIcon: , + }, + { + id: "partner-rollout", + label: "Partner rollout", + status: "Processing", + tone: "processing" as const, + statusIcon: , + }, + { + id: "creative-review", + label: "Creative review", + status: "Degraded", + tone: "neutral" as const, + statusIcon: , + }, + { + id: "failed-sync", + label: "Failed sync", + status: "Failed", + tone: "danger" as const, + statusIcon: , + }, ], } : item diff --git a/packages/ui/README.md b/packages/ui/README.md index 8866db7..72fa738 100644 --- a/packages/ui/README.md +++ b/packages/ui/README.md @@ -8,7 +8,7 @@ shadcn/ui, Base UI, Tailwind CSS 4, and React 19. Pin an exact release so upgrades remain deliberate: ```bash -pnpm add --save-exact @nextide/ui@2.1.0 +pnpm add --save-exact @nextide/ui@2.2.0 pnpm add --save-dev --save-exact tailwindcss@4.3.1 @tailwindcss/vite@4.3.1 ``` diff --git a/packages/ui/package.json b/packages/ui/package.json index 3f325a7..de64f7a 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@nextide/ui", - "version": "2.1.0", + "version": "2.2.0", "description": "Shared Nextide React components and product interface patterns.", "type": "module", "license": "UNLICENSED", diff --git a/packages/ui/src/blocks/navigation-panel.tsx b/packages/ui/src/blocks/navigation-panel.tsx index b53746a..eb956f5 100644 --- a/packages/ui/src/blocks/navigation-panel.tsx +++ b/packages/ui/src/blocks/navigation-panel.tsx @@ -27,7 +27,10 @@ import { AutocompletePositioner, } from "@nextide/ui/components/autocomplete" import { Kbd } from "@nextide/ui/components/kbd" -import { StatusBadge } from "@nextide/ui/components/status-badge" +import { + StatusBadge, + type StatusBadgeIndicator, +} from "@nextide/ui/components/status-badge" import { Surface } from "@nextide/ui/components/surface" import { useContainedScroll } from "@nextide/ui/hooks/use-contained-scroll" import { cn } from "@nextide/ui/lib/utils" @@ -45,6 +48,8 @@ type NavigationPanelItem = { meta?: string status?: string tone?: NavigationPanelStatusTone + statusIcon?: React.ReactNode + statusIndicator?: StatusBadgeIndicator icon?: React.ReactNode children?: NavigationPanelItem[] expanded?: boolean @@ -870,14 +875,7 @@ function NavigationPanelNav({ {item.meta} ) : null} - {item.status ? ( - - {item.status} - - ) : null} + ) : null} @@ -938,7 +936,7 @@ function NavigationPanelNav({ }} data-slot="navigation-panel-child" className={cn( - "group grid min-h-11 w-full grid-cols-[2rem_minmax(0,1fr)] items-center rounded-lg border border-transparent pr-2 text-left text-sm transition-colors max-lg:w-auto max-lg:min-w-max", + "group relative grid min-h-11 w-full grid-cols-[2rem_minmax(0,1fr)] items-center rounded-lg border border-transparent pr-8 text-left text-sm transition-colors max-lg:w-auto max-lg:min-w-max", childActive ? "bg-nextide-tide/[0.07] text-foreground" : "text-muted-foreground hover:bg-nextide-panel-strong/70 hover:text-foreground" @@ -966,14 +964,13 @@ function NavigationPanelNav({ {child.label} - {child.meta || child.status ? ( + {child.meta ? ( - {[child.meta, child.status] - .filter(Boolean) - .join(" ยท ")} + {child.meta} ) : null} + ) })} @@ -999,6 +996,32 @@ function NavigationPanelNav({ ) } +function NavigationPanelStatus({ + item, + iconOnly = false, +}: { + item: NavigationPanelItem + iconOnly?: boolean +}) { + if (!item.status) return null + + return ( + + {iconOnly ? {item.status} : item.status} + + ) +} + function NavigationPanelFooter({ collapsed, drawerCollapsed, diff --git a/packages/ui/src/components/status-badge.tsx b/packages/ui/src/components/status-badge.tsx index a2b02af..6563c81 100644 --- a/packages/ui/src/components/status-badge.tsx +++ b/packages/ui/src/components/status-badge.tsx @@ -38,10 +38,12 @@ function StatusBadge({ tone, size, children, + icon, indicator = "dot", ...props }: React.ComponentProps<"span"> & VariantProps & { + icon?: React.ReactNode indicator?: StatusBadgeIndicator }) { const pulse = indicator === "pulse" @@ -51,11 +53,22 @@ function StatusBadge({ data-slot="status-badge" data-tone={tone} data-size={size ?? "default"} - data-indicator={indicator} + data-indicator={icon ? "icon" : indicator} className={cn(statusBadgeVariants({ tone, size }), className)} {...props} > - {indicator !== "none" ? ( + {icon ? ( + + ) : indicator !== "none" ? ( processingIcon.evaluate((icon) => getComputedStyle(icon).animationName)) + .not.toBe("none") + await page.emulateMedia({ reducedMotion: "reduce" }) + await expect + .poll(() => processingIcon.evaluate((icon) => getComputedStyle(icon).animationName)) + .toBe("none") + await page.emulateMedia({ reducedMotion: "no-preference" }) await expect( navigation.getByRole("button", { name: "Collapse Campaigns" }) ).toBeVisible()