From b443fc787e727119a04d4d760c91a07f275403b5 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Fri, 10 Apr 2026 17:00:57 +0200 Subject: [PATCH] refactor: decompose TopBar into composable shell with children slot TopBar was a monolith that hardcoded server-specific controls (status filters, time range, auto-refresh, search trigger). Extract these into standalone SearchTrigger and AutoRefreshToggle components. TopBar now accepts children for the center slot, letting consumers compose their own controls. Fixes cameleer/cameleer-saas#53. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../layout/TopBar/AutoRefreshToggle.tsx | 22 ++++++ .../layout/TopBar/SearchTrigger.tsx | 24 +++++++ src/design-system/layout/TopBar/TopBar.tsx | 67 ++----------------- src/design-system/layout/index.ts | 2 + .../Inventory/sections/LayoutSection.tsx | 10 ++- 5 files changed, 61 insertions(+), 64 deletions(-) create mode 100644 src/design-system/layout/TopBar/AutoRefreshToggle.tsx create mode 100644 src/design-system/layout/TopBar/SearchTrigger.tsx diff --git a/src/design-system/layout/TopBar/AutoRefreshToggle.tsx b/src/design-system/layout/TopBar/AutoRefreshToggle.tsx new file mode 100644 index 0000000..67dca51 --- /dev/null +++ b/src/design-system/layout/TopBar/AutoRefreshToggle.tsx @@ -0,0 +1,22 @@ +import styles from './TopBar.module.css' + +interface AutoRefreshToggleProps { + active: boolean + onChange: (active: boolean) => void + className?: string +} + +export function AutoRefreshToggle({ active, onChange, className }: AutoRefreshToggleProps) { + return ( + + ) +} diff --git a/src/design-system/layout/TopBar/SearchTrigger.tsx b/src/design-system/layout/TopBar/SearchTrigger.tsx new file mode 100644 index 0000000..a5f853d --- /dev/null +++ b/src/design-system/layout/TopBar/SearchTrigger.tsx @@ -0,0 +1,24 @@ +import { Search } from 'lucide-react' +import styles from './TopBar.module.css' + +interface SearchTriggerProps { + onClick: () => void + className?: string +} + +export function SearchTrigger({ onClick, className }: SearchTriggerProps) { + return ( + + ) +} diff --git a/src/design-system/layout/TopBar/TopBar.tsx b/src/design-system/layout/TopBar/TopBar.tsx index 17bf51d..bc41e7c 100644 --- a/src/design-system/layout/TopBar/TopBar.tsx +++ b/src/design-system/layout/TopBar/TopBar.tsx @@ -1,14 +1,9 @@ import { type ReactNode } from 'react' -import { Search, Moon, Sun, Power } from 'lucide-react' +import { Moon, Sun, Power } from 'lucide-react' import styles from './TopBar.module.css' import { Breadcrumb } from '../../composites/Breadcrumb/Breadcrumb' import { Dropdown } from '../../composites/Dropdown/Dropdown' import { Avatar } from '../../primitives/Avatar/Avatar' -import { ButtonGroup } from '../../primitives/ButtonGroup/ButtonGroup' -import type { ButtonGroupItem } from '../../primitives/ButtonGroup/ButtonGroup' -import { TimeRangeDropdown } from '../../primitives/TimeRangeDropdown/TimeRangeDropdown' -import { useGlobalFilters } from '../../providers/GlobalFilterProvider' -import { useCommandPalette } from '../../providers/CommandPaletteProvider' import { useTheme } from '../../providers/ThemeProvider' import { useBreadcrumbOverride } from '../../providers/BreadcrumbProvider' import type { BreadcrumbItem } from '../../providers/BreadcrumbProvider' @@ -20,15 +15,9 @@ interface TopBarProps { userMenuItems?: import('../../composites/Dropdown/Dropdown').DropdownItem[] onLogout?: () => void className?: string + children?: ReactNode } -const STATUS_ITEMS: ButtonGroupItem[] = [ - { value: 'completed', label: 'OK', color: 'var(--success)' }, - { value: 'warning', label: 'Warn', color: 'var(--warning)' }, - { value: 'failed', label: 'Error', color: 'var(--error)' }, - { value: 'running', label: 'Running', color: 'var(--running)' }, -] - export function TopBar({ breadcrumb, environment, @@ -36,9 +25,8 @@ export function TopBar({ userMenuItems, onLogout, className, + children, }: TopBarProps) { - const globalFilters = useGlobalFilters() - const commandPalette = useCommandPalette() const { theme, toggleTheme } = useTheme() const breadcrumbOverride = useBreadcrumbOverride() @@ -47,54 +35,11 @@ export function TopBar({ {/* Left: Breadcrumb */} - {/* Search trigger */} - + {/* Center: consumer-provided controls */} + {children} - {/* Status filter group */} - { - // Sync with global filter by toggling the diff - const current = globalFilters.statusFilters - for (const v of selected) { - if (!current.has(v)) globalFilters.toggleStatus(v as 'completed' | 'warning' | 'failed' | 'running') - } - for (const v of current) { - if (!selected.has(v)) globalFilters.toggleStatus(v as 'completed' | 'warning' | 'failed' | 'running') - } - }} - /> - - {/* Time range pills */} - - - {/* Right: auto-refresh toggle, theme toggle, env badge, user */} + {/* Right: theme toggle, env badge, user */}
-