SdcTopBar: move app-directory grid to the left of the app name
Some checks failed
Publish package to GitHub Packages / publish (push) Has been cancelled

Grid (suite menu) now sits left of the app name; optional hamburger before it
(new onMenuClick prop) for apps with side nav; API-settings cog + no-key badge
stay on the right. Bump to 0.2.1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 14:25:03 +10:00
parent ce1efd1c13
commit d02d64b61c
2 changed files with 63 additions and 44 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@richiesnitch/ads3-design-system",
"version": "0.2.0",
"version": "0.2.1",
"type": "module",
"repository": {
"type": "git",

View File

@@ -1,5 +1,5 @@
import { useState, type ReactNode } from 'react'
import { Settings, Grid3x3 } from 'lucide-react'
import { Settings, Grid3x3, Menu } from 'lucide-react'
import { TopBar } from '@/components/organisms/TopBar'
import { IconButton } from '@/components/atoms/IconButton'
import { Badge } from '@/components/atoms/Badge'
@@ -29,7 +29,7 @@ export const SDC_TOOLS: SdcTool[] = [
]
export interface SdcTopBarProps {
/** App name shown top-left. */
/** App name shown top-left, to the right of the app-directory grid. */
appName: string
/** Slug of the current tool, marked active and non-navigating in the menu. */
activeTool?: string
@@ -37,13 +37,19 @@ export interface SdcTopBarProps {
logo?: ReactNode
/** Override the tool list (defaults to the full SDC suite). */
tools?: SdcTool[]
/**
* If provided, renders a hamburger button at the very left (before the app-directory grid)
* that calls this on click — for apps that have a collapsible side navigation.
*/
onMenuClick?: () => void
}
/**
* Shared top bar for the SDC tool suite: app name (left), API settings (cog), and the
* suite app directory (grid). Wraps the ADS TopBar; uses the shared `sdc_*` credentials.
* Shared top bar for the SDC tool suite. Left → right: [optional hamburger] [app-directory grid]
* [app name] … [no-key badge] [API settings cog]. Wraps the ADS TopBar; uses the shared
* `sdc_*` credentials.
*/
export function SdcTopBar({ appName, activeTool, logo, tools = SDC_TOOLS }: SdcTopBarProps) {
export function SdcTopBar({ appName, activeTool, logo, tools = SDC_TOOLS, onMenuClick }: SdcTopBarProps) {
const [settingsOpen, setSettingsOpen] = useState(false)
const [toolsOpen, setToolsOpen] = useState(false)
const [hasCreds, setHasCreds] = useState(() => checkCredentials())
@@ -56,12 +62,61 @@ export function SdcTopBar({ appName, activeTool, logo, tools = SDC_TOOLS }: SdcT
g.items.push(t)
}
const leading = (
<div className="flex items-center gap-1 text-white">
{onMenuClick && (
<IconButton
icon={<Menu />}
aria-label="Toggle navigation"
variant="tertiary"
className="!text-white hover:!bg-white/10"
onClick={onMenuClick}
/>
)}
<Popover placement="bottom-start" open={toolsOpen} onOpenChange={setToolsOpen}>
<PopoverTrigger>
<IconButton
icon={<Grid3x3 />}
aria-label="SDC AI Tools"
variant="tertiary"
className="!text-white hover:!bg-white/10"
/>
</PopoverTrigger>
<PopoverContent>
<div className="w-64">
<List>
{groups.map((group) => (
<div key={group.name}>
<ListSubheader>{group.name}</ListSubheader>
{group.items.map((item) => {
const isActive = item.slug === activeTool
return (
<ListItem
key={item.slug}
active={isActive}
href={isActive ? undefined : item.href}
onClick={() => isActive && setToolsOpen(false)}
>
{item.label}
</ListItem>
)
})}
<ListDivider />
</div>
))}
</List>
</div>
</PopoverContent>
</Popover>
</div>
)
return (
<>
<TopBar title={appName} logo={logo}>
<TopBar title={appName} logo={logo} leading={leading}>
<div className="flex items-center gap-1 text-white">
{!hasCreds && <Badge variant="warning-light">No API key</Badge>}
<IconButton
icon={<Settings />}
aria-label="API settings"
@@ -69,42 +124,6 @@ export function SdcTopBar({ appName, activeTool, logo, tools = SDC_TOOLS }: SdcT
className="!text-white hover:!bg-white/10"
onClick={() => setSettingsOpen(true)}
/>
<Popover placement="bottom-end" open={toolsOpen} onOpenChange={setToolsOpen}>
<PopoverTrigger>
<IconButton
icon={<Grid3x3 />}
aria-label="SDC AI Tools"
variant="tertiary"
className="!text-white hover:!bg-white/10"
/>
</PopoverTrigger>
<PopoverContent>
<div className="w-64">
<List>
{groups.map((group) => (
<div key={group.name}>
<ListSubheader>{group.name}</ListSubheader>
{group.items.map((item) => {
const isActive = item.slug === activeTool
return (
<ListItem
key={item.slug}
active={isActive}
href={isActive ? undefined : item.href}
onClick={() => isActive && setToolsOpen(false)}
>
{item.label}
</ListItem>
)
})}
<ListDivider />
</div>
))}
</List>
</div>
</PopoverContent>
</Popover>
</div>
</TopBar>