|
|
|
|
@@ -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,21 +62,19 @@ export function SdcTopBar({ appName, activeTool, logo, tools = SDC_TOOLS }: SdcT
|
|
|
|
|
g.items.push(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<TopBar title={appName} logo={logo}>
|
|
|
|
|
const leading = (
|
|
|
|
|
<div className="flex items-center gap-1 text-white">
|
|
|
|
|
{!hasCreds && <Badge variant="warning-light">No API key</Badge>}
|
|
|
|
|
|
|
|
|
|
{onMenuClick && (
|
|
|
|
|
<IconButton
|
|
|
|
|
icon={<Settings />}
|
|
|
|
|
aria-label="API settings"
|
|
|
|
|
icon={<Menu />}
|
|
|
|
|
aria-label="Toggle navigation"
|
|
|
|
|
variant="tertiary"
|
|
|
|
|
className="!text-white hover:!bg-white/10"
|
|
|
|
|
onClick={() => setSettingsOpen(true)}
|
|
|
|
|
onClick={onMenuClick}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<Popover placement="bottom-end" open={toolsOpen} onOpenChange={setToolsOpen}>
|
|
|
|
|
<Popover placement="bottom-start" open={toolsOpen} onOpenChange={setToolsOpen}>
|
|
|
|
|
<PopoverTrigger>
|
|
|
|
|
<IconButton
|
|
|
|
|
icon={<Grid3x3 />}
|
|
|
|
|
@@ -106,6 +110,21 @@ export function SdcTopBar({ appName, activeTool, logo, tools = SDC_TOOLS }: SdcT
|
|
|
|
|
</PopoverContent>
|
|
|
|
|
</Popover>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<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"
|
|
|
|
|
variant="tertiary"
|
|
|
|
|
className="!text-white hover:!bg-white/10"
|
|
|
|
|
onClick={() => setSettingsOpen(true)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</TopBar>
|
|
|
|
|
|
|
|
|
|
<ApiSettings
|
|
|
|
|
|