@petrarca/sonnet-shell 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +190 -0
- package/dist/auth/index.d.ts +117 -0
- package/dist/auth/index.js +305 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/index.d.ts +597 -0
- package/dist/index.js +1194 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/AppShell.tsx","../src/ConfirmDialog.tsx","../src/TopBar.tsx","../src/IconRail.tsx","../src/shellModules.ts","../src/SubNavPanel.tsx","../src/hooks.ts","../src/api.ts","../src/eventBus.ts","../src/SidePane.tsx","../src/sidePaneState.ts","../src/CommandMenu.tsx","../src/shellConfig.ts","../src/RootLayout.tsx","../src/ShellConfigProvider.tsx","../src/PlaceholderPage.tsx","../src/SearchTrigger.tsx","../src/UserMenu.tsx","../src/createModuleRegistry.ts","../src/OverviewCard.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useRef, useMemo } from \"react\";\nimport { Outlet, useLocation, useNavigate } from \"react-router-dom\";\nimport { TooltipProvider } from \"@petrarca/sonnet-ui\";\nimport { ScrollArea } from \"@petrarca/sonnet-ui\";\nimport {\n Sheet,\n SheetContent,\n SheetHeader,\n SheetTitle,\n SheetDescription,\n SheetBody,\n} from \"@petrarca/sonnet-ui\";\nimport { ConfirmDialog } from \"./ConfirmDialog\";\nimport TopBar from \"./TopBar\";\nimport IconRail from \"./IconRail\";\nimport SubNavPanel from \"./SubNavPanel\";\nimport SidePane from \"./SidePane\";\nimport CommandMenu from \"./CommandMenu\";\nimport {\n initNavigation,\n initFeatureNav,\n initPanel,\n initDialog,\n initFullscreen,\n initSidePane,\n type PanelOptions,\n type ConfirmOptions,\n type FullscreenOptions,\n} from \"./api\";\nimport type { ModuleRegistry } from \"./createModuleRegistry\";\nimport { ShellModulesContext } from \"./shellModules\";\nimport { useShellConfig } from \"./shellConfig\";\nimport { SidePaneContext, type SidePaneOptions } from \"./sidePaneState\";\n\n// Maps PanelOptions.width tokens to Tailwind width classes.\nconst PANEL_WIDTH_CLASS: Record<string, string> = {\n narrow: \"w-[480px]\",\n default: \"w-[640px]\",\n wide: \"w-[800px]\",\n half: \"w-[50vw]\",\n full: \"w-screen\",\n // legacy aliases\n lg: \"w-[640px]\",\n \"1/3\": \"w-[33vw]\",\n \"1/2\": \"w-[50vw]\",\n};\n\n// -- Helpers extracted to reduce AppShell complexity --\n\nfunction isSidePaneModule(service: {\n sidePane?: unknown;\n navigation: unknown[];\n}): boolean {\n return !!service.sidePane && service.navigation.length === 0;\n}\n\nfunction selectSidePaneModule(\n service: {\n id: string;\n basePath: string;\n sidePane?: { defaultWidth?: number; minWidth?: number; maxWidth?: number };\n },\n current: SidePaneOptions | null,\n setSidePaneState: (s: SidePaneOptions | null) => void,\n navigate: (path: string) => void,\n): void {\n if (current?.moduleId === service.id) {\n setSidePaneState(null);\n } else {\n setSidePaneState({\n moduleId: service.id,\n content: null,\n defaultWidth: service.sidePane?.defaultWidth,\n minWidth: service.sidePane?.minWidth,\n maxWidth: service.sidePane?.maxWidth,\n });\n navigate(service.basePath);\n }\n}\n\nfunction selectNavModule(\n service: {\n basePath: string;\n navigation: Array<{ links: Array<{ path: string }> }>;\n },\n navigate: (path: string) => void,\n setSubNavCollapsed: (v: boolean) => void,\n): void {\n setSubNavCollapsed(false);\n const target = service.navigation[0]?.links[0]?.path ?? service.basePath;\n navigate(target);\n}\n\n// Wire all imperative shell APIs once on mount.\nfunction useShellApiInit(deps: {\n navigate: ReturnType<typeof useNavigate>;\n openCommandMenu: () => void;\n handlePanelOpen: (opts: PanelOptions) => void;\n handlePanelClose: () => void;\n handleFullscreenEnter: (opts: FullscreenOptions) => void;\n handleFullscreenExit: () => void;\n handleSidePaneOpen: (opts: SidePaneOptions) => void;\n handleSidePaneClose: () => void;\n handleSidePaneIsOpen: () => boolean;\n handleSidePaneActiveModuleId: () => string | null;\n setDialogState: React.Dispatch<React.SetStateAction<DialogState | null>>;\n featureLookup: (featureId: string) => string | null;\n}) {\n const stableRefs = useRef(deps);\n useEffect(() => {\n const r = stableRefs.current;\n initNavigation(r.navigate, r.openCommandMenu);\n initFeatureNav(r.featureLookup);\n initPanel(r.handlePanelOpen, r.handlePanelClose);\n initFullscreen(r.handleFullscreenEnter, r.handleFullscreenExit);\n initSidePane(\n r.handleSidePaneOpen,\n r.handleSidePaneClose,\n r.handleSidePaneIsOpen,\n r.handleSidePaneActiveModuleId,\n );\n initDialog(\n (opts: ConfirmOptions) =>\n new Promise<boolean>((resolve) => r.setDialogState({ opts, resolve })),\n );\n }, []);\n}\n\ninterface AppShellProps {\n registry: ModuleRegistry;\n}\n\ninterface DialogState {\n opts: ConfirmOptions;\n resolve: (confirmed: boolean) => void;\n}\n\n/**\n * AppShell -- the main layout skeleton.\n *\n * Owns the panel (slide-over) -- modules request it via panel.open(),\n * the shell renders the provided content inside a Sheet.\n *\n * Receives its module registry as a prop so it has no dependency on\n * app-specific module lists.\n */\n// Hook: track which service is active based on URL.\nfunction useActiveService(modules: ModuleRegistry[\"modules\"]) {\n const location = useLocation();\n const serviceByBasePath = useMemo(\n () =>\n new Map(\n modules\n .filter((m) => !m.hidden && m.basePath !== \"/\")\n .map((m) => [m.basePath, m.id]),\n ),\n [modules],\n );\n const resolveServiceFromPath = useCallback(\n (pathname: string): string | null => {\n for (const [basePath, id] of serviceByBasePath) {\n if (pathname.startsWith(basePath)) return id;\n }\n return null;\n },\n [serviceByBasePath],\n );\n const [selectedServiceId, setSelectedServiceId] = useState<string | null>(\n () => resolveServiceFromPath(location.pathname),\n );\n useEffect(\n () => setSelectedServiceId(resolveServiceFromPath(location.pathname)),\n [location.pathname, resolveServiceFromPath],\n );\n const activeService = selectedServiceId\n ? (modules.find((s) => s.id === selectedServiceId) ?? null)\n : null;\n return { activeService, selectedServiceId, setSelectedServiceId };\n}\n\n// Hook: side pane state and handlers.\nfunction useSidePaneState() {\n const [sidePaneState, setSidePaneState] = useState<SidePaneOptions | null>(\n null,\n );\n const handleOpen = useCallback(\n (opts: SidePaneOptions) => setSidePaneState(opts),\n [],\n );\n const handleClose = useCallback(() => setSidePaneState(null), []);\n const handleIsOpen = useCallback(\n () => sidePaneState !== null,\n [sidePaneState],\n );\n const handleActiveModuleId = useCallback(\n () => sidePaneState?.moduleId ?? null,\n [sidePaneState],\n );\n return {\n sidePaneState,\n setSidePaneState,\n handleOpen,\n handleClose,\n handleIsOpen,\n handleActiveModuleId,\n };\n}\n\n// Hook: slide-over panel state and handlers.\nfunction usePanelState() {\n const [panelState, setPanelState] = useState<PanelOptions | null>(null);\n const panelOnCloseRef = useRef<(() => void) | undefined>(undefined);\n const handleOpen = useCallback(\n (opts: PanelOptions) => setPanelState(opts),\n [],\n );\n const handleClose = useCallback(() => {\n panelOnCloseRef.current = panelState?.onClose;\n setPanelState(null);\n }, [panelState]);\n const panelWidth =\n PANEL_WIDTH_CLASS[panelState?.width ?? \"default\"] ??\n PANEL_WIDTH_CLASS.default;\n const panelOffsetTop = panelState?.coverage === \"full\" ? \"0px\" : \"3rem\";\n return {\n panelState,\n panelOnCloseRef,\n handleOpen,\n handleClose,\n panelWidth,\n panelOffsetTop,\n };\n}\n\n// Hook: confirm dialog state and handlers.\nfunction useDialogState() {\n const [dialogState, setDialogState] = useState<DialogState | null>(null);\n const handleConfirm = useCallback(() => {\n dialogState?.resolve(true);\n setDialogState(null);\n }, [dialogState]);\n const handleCancel = useCallback(() => {\n dialogState?.resolve(false);\n setDialogState(null);\n }, [dialogState]);\n return { dialogState, setDialogState, handleConfirm, handleCancel };\n}\n\n// Build a stable feature id -> path lookup from the module registry.\nfunction useFeatureLookup(modules: ModuleRegistry[\"modules\"]) {\n return useMemo(() => {\n const map = new Map<string, string>();\n for (const m of modules) {\n for (const group of m.navigation) {\n for (const link of group.links) {\n if (link.id) map.set(link.id, link.path);\n }\n }\n }\n return (featureId: string) => map.get(featureId) ?? null;\n }, [modules]);\n}\n\nexport default function AppShell({ registry }: AppShellProps) {\n const navigate = useNavigate();\n const config = useShellConfig();\n const { modules } = registry;\n\n const { activeService, setSelectedServiceId } = useActiveService(modules);\n const [subNavCollapsed, setSubNavCollapsed] = useState(false);\n const [commandMenuOpen, setCommandMenuOpen] = useState(false);\n const openCommandMenu = useCallback(() => setCommandMenuOpen(true), []);\n const [fullscreenState, setFullscreenState] =\n useState<FullscreenOptions | null>(null);\n const handleFullscreenEnter = useCallback(\n (opts: FullscreenOptions) => setFullscreenState(opts),\n [],\n );\n const handleFullscreenExit = useCallback(() => setFullscreenState(null), []);\n\n const sidePane = useSidePaneState();\n const panel = usePanelState();\n const dialog = useDialogState();\n const featureLookup = useFeatureLookup(modules);\n\n useShellApiInit({\n navigate,\n openCommandMenu,\n handlePanelOpen: panel.handleOpen,\n handlePanelClose: panel.handleClose,\n handleFullscreenEnter,\n handleFullscreenExit,\n handleSidePaneOpen: sidePane.handleOpen,\n handleSidePaneClose: sidePane.handleClose,\n handleSidePaneIsOpen: sidePane.handleIsOpen,\n handleSidePaneActiveModuleId: sidePane.handleActiveModuleId,\n setDialogState: dialog.setDialogState,\n featureLookup,\n });\n\n const handleServiceSelect = useCallback(\n (serviceId: string) => {\n const service = modules.find((s) => s.id === serviceId);\n if (!service) return;\n if (isSidePaneModule(service)) {\n selectSidePaneModule(\n service,\n sidePane.sidePaneState,\n sidePane.setSidePaneState,\n navigate,\n );\n } else {\n selectNavModule(service, navigate, setSubNavCollapsed);\n }\n setSelectedServiceId(serviceId);\n },\n [\n modules,\n sidePane.sidePaneState,\n sidePane.setSidePaneState,\n navigate,\n setSelectedServiceId,\n ],\n );\n\n const sidePaneContextValue = useMemo(\n () => ({\n pane: sidePane.sidePaneState,\n open: sidePane.handleOpen,\n close: sidePane.handleClose,\n toggle: (opts: SidePaneOptions) => {\n if (sidePane.sidePaneState?.moduleId === opts.moduleId) {\n sidePane.setSidePaneState(null);\n } else {\n sidePane.setSidePaneState(opts);\n }\n },\n }),\n [sidePane],\n );\n\n return (\n <ShellModulesContext.Provider value={registry}>\n <SidePaneContext.Provider value={sidePaneContextValue}>\n <TooltipProvider>\n <div className=\"flex h-screen w-screen flex-col overflow-hidden\">\n {/* TopBar */}\n <TopBar>{config.topBar}</TopBar>\n\n {/* CommandMenu (Cmd+K) */}\n <CommandMenu\n open={commandMenuOpen}\n onOpenChange={setCommandMenuOpen}\n />\n\n {/* Body: IconRail + SubNavPanel + SidePane + Content Area */}\n <div className=\"flex flex-1 overflow-hidden\">\n <IconRail\n activeServiceId={activeService?.id ?? null}\n activeSidePaneModuleId={\n sidePane.sidePaneState?.moduleId ?? null\n }\n onServiceSelect={handleServiceSelect}\n />\n\n {activeService && activeService.navigation.length > 0 && (\n <SubNavPanel\n service={activeService}\n collapsed={subNavCollapsed}\n onToggleCollapse={() => setSubNavCollapsed((c) => !c)}\n />\n )}\n\n {/* Side Pane — inline, shrinks the content area */}\n <SidePane />\n\n {/* Content Area */}\n <div className=\"flex-1 min-w-0 overflow-hidden\">\n <ScrollArea className=\"h-full\">\n <main className=\"p-6\">\n <Outlet />\n </main>\n </ScrollArea>\n </div>\n </div>\n\n {/* Confirm Dialog */}\n {dialog.dialogState && (\n <ConfirmDialog\n open={true}\n title={dialog.dialogState.opts.title}\n description={dialog.dialogState.opts.description}\n confirmLabel={dialog.dialogState.opts.confirmLabel}\n cancelLabel={dialog.dialogState.opts.cancelLabel}\n variant={dialog.dialogState.opts.variant}\n onConfirm={dialog.handleConfirm}\n onCancel={dialog.handleCancel}\n />\n )}\n\n {/* Fullscreen overlay -- covers all shell chrome */}\n {fullscreenState && (\n <div className=\"fixed inset-0 z-50 bg-background overflow-auto\">\n {fullscreenState.content}\n </div>\n )}\n\n {/* Slide-over Panel */}\n <SlideOverPanel\n panelState={panel.panelState}\n panelWidth={panel.panelWidth}\n panelOffsetTop={panel.panelOffsetTop}\n panelOnCloseRef={panel.panelOnCloseRef}\n onClose={panel.handleClose}\n />\n </div>\n </TooltipProvider>\n </SidePaneContext.Provider>\n </ShellModulesContext.Provider>\n );\n}\n\n// -- Sub-components extracted to reduce AppShell complexity --\n\ninterface SlideOverPanelProps {\n panelState: PanelOptions | null;\n panelWidth: string;\n panelOffsetTop: string;\n panelOnCloseRef: React.MutableRefObject<(() => void) | undefined>;\n onClose: () => void;\n}\n\nfunction SlideOverPanel({\n panelState,\n panelWidth,\n panelOffsetTop,\n panelOnCloseRef,\n onClose,\n}: SlideOverPanelProps) {\n return (\n <Sheet\n open={panelState !== null}\n onOpenChange={(open) => {\n if (!open) onClose();\n }}\n >\n <SheetContent\n side=\"right\"\n className={`${panelWidth} max-w-[90vw]`}\n offsetTop={panelOffsetTop}\n onCloseAutoFocus={(e) => {\n if (panelOnCloseRef.current) {\n e.preventDefault();\n panelOnCloseRef.current();\n }\n }}\n {...(!panelState?.description && {\n \"aria-describedby\": undefined,\n })}\n >\n {panelState && <PanelContent state={panelState} />}\n </SheetContent>\n </Sheet>\n );\n}\n\nfunction PanelContent({ state }: { state: PanelOptions }) {\n return (\n <>\n {state.title ? (\n <SheetHeader>\n <SheetTitle>{state.title}</SheetTitle>\n {state.description && (\n <SheetDescription>{state.description}</SheetDescription>\n )}\n </SheetHeader>\n ) : (\n <SheetTitle className=\"sr-only\">Panel</SheetTitle>\n )}\n <SheetBody>{state.content}</SheetBody>\n </>\n );\n}\n","/**\n * Confirm Dialog\n *\n * Reusable confirmation dialog for actions that require user confirmation.\n * Used for discard changes, delete actions, etc.\n *\n * Wired into the shell via `initDialog` in `shell/api.ts` so modules can\n * trigger it imperatively with `dialog.confirm(opts)`.\n *\n * @module components/Common/ConfirmDialog\n */\n\nimport React from \"react\";\nimport { AlertTriangle } from \"lucide-react\";\nimport { Button } from \"@petrarca/sonnet-ui\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"@petrarca/sonnet-ui\";\n\nexport interface ConfirmDialogProps {\n /** Whether the dialog is open */\n open: boolean;\n\n /** Dialog title */\n title: string;\n\n /** Description shown below the title */\n description?: string;\n\n /** Confirm button label (default: \"Confirm\") */\n confirmLabel?: string;\n\n /** Cancel button label (default: \"Cancel\") */\n cancelLabel?: string;\n\n /**\n * Controls confirm button appearance.\n * \"destructive\" for irreversible actions (delete, revoke, etc.)\n */\n variant?: \"default\" | \"destructive\";\n\n /** Callback when user confirms */\n onConfirm: () => void;\n\n /** Callback when user cancels or closes dialog */\n onCancel: () => void;\n}\n\n/**\n * ConfirmDialog Component\n *\n * A reusable confirmation dialog backed by shadcn Dialog primitives.\n */\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = \"Confirm\",\n cancelLabel = \"Cancel\",\n variant = \"default\",\n onConfirm,\n onCancel,\n}: ConfirmDialogProps): React.ReactElement {\n return (\n <Dialog open={open} onOpenChange={(isOpen) => !isOpen && onCancel()}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{title}</DialogTitle>\n {description && <DialogDescription>{description}</DialogDescription>}\n </DialogHeader>\n\n {variant === \"destructive\" && (\n <div className=\"flex gap-2 items-start\">\n <AlertTriangle\n size={20}\n className=\"text-destructive flex-shrink-0 mt-0.5\"\n />\n <p className=\"flex-1 text-sm text-muted-foreground\">\n This action cannot be undone.\n </p>\n </div>\n )}\n\n <DialogFooter>\n <Button variant=\"outline\" onClick={onCancel}>\n {cancelLabel}\n </Button>\n <Button variant={variant} onClick={onConfirm}>\n {confirmLabel}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n","import type { ReactNode } from \"react\";\n\n/**\n * TopBar -- persistent header across the entire application.\n *\n * A pure layout container. The shell provides the `<header>` element with\n * its sizing, background, and border. The consumer owns all content via\n * the `children` prop (composed through `ShellConfig.topBar`).\n */\ninterface TopBarProps {\n children?: ReactNode;\n}\n\nexport default function TopBar({ children }: TopBarProps) {\n return (\n <header className=\"h-12 shrink-0 border-b border-blue-200 flex items-center justify-between px-3 bg-blue-100/70 z-20\">\n {children}\n </header>\n );\n}\n","import { cn } from \"@petrarca/sonnet-core\";\nimport { Button } from \"@petrarca/sonnet-ui\";\nimport { Separator } from \"@petrarca/sonnet-ui\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@petrarca/sonnet-ui\";\nimport { useShellModules } from \"./shellModules\";\nimport type { ServiceModule } from \"./types\";\n\ninterface IconRailProps {\n activeServiceId: string | null;\n /** moduleId of the module whose side pane is currently open, or null. */\n activeSidePaneModuleId: string | null;\n onServiceSelect: (serviceId: string) => void;\n}\n\n/**\n * IconRail -- narrow vertical bar with service domain icons.\n *\n * Main services scroll in the center, settings/playground pinned at bottom.\n * Tooltips show service labels on hover.\n */\nexport default function IconRail({\n activeServiceId,\n activeSidePaneModuleId,\n onServiceSelect,\n}: IconRailProps) {\n const { mainModules, bottomModules } = useShellModules();\n\n const isActive = (id: string) =>\n activeServiceId === id || activeSidePaneModuleId === id;\n\n return (\n <nav className=\"w-12 shrink-0 border-r bg-muted/30 flex flex-col items-center py-2 gap-1\">\n {/* Main service icons */}\n <div className=\"flex-1 flex flex-col items-center gap-1 overflow-y-auto\">\n {mainModules.map((service) => (\n <RailIcon\n key={service.id}\n service={service}\n isActive={isActive(service.id)}\n onClick={() => onServiceSelect(service.id)}\n />\n ))}\n </div>\n\n {/* Bottom-pinned icons */}\n <Separator className=\"w-6 my-1\" />\n <div className=\"flex flex-col items-center gap-1\">\n {bottomModules.map((service) => (\n <RailIcon\n key={service.id}\n service={service}\n isActive={isActive(service.id)}\n onClick={() => onServiceSelect(service.id)}\n />\n ))}\n </div>\n </nav>\n );\n}\n\n// Single rail icon button\n\ninterface RailIconProps {\n service: ServiceModule;\n isActive: boolean;\n onClick: () => void;\n}\n\nfunction RailIcon({ service, isActive, onClick }: RailIconProps) {\n const Icon = service.icon;\n\n return (\n <Tooltip delayDuration={0}>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"compact\"\n onClick={onClick}\n className={cn(\n \"h-9 w-9 rounded-lg transition-colors\",\n isActive\n ? \"bg-accent text-accent-foreground\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n >\n <Icon className=\"h-[18px] w-[18px]\" />\n <span className=\"sr-only\">{service.label}</span>\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"right\" sideOffset={8}>\n {service.label}\n </TooltipContent>\n </Tooltip>\n );\n}\n","/**\n * Shell modules context.\n *\n * Provides the module registry to shell components (IconRail,\n * CommandMenu, hooks) without requiring them to import from the\n * app-specific modules/registry.ts. AppShell injects the registry;\n * children consume it via useShellModules().\n */\nimport { createContext, useContext } from \"react\";\nimport type { ModuleRegistry } from \"./createModuleRegistry\";\n\nexport const ShellModulesContext = createContext<ModuleRegistry | null>(null);\n\n/**\n * Read the module registry from context.\n * Must be called within an AppShell (which provides the context).\n */\nexport function useShellModules(): ModuleRegistry {\n const registry = useContext(ShellModulesContext);\n if (!registry) {\n throw new Error(\"useShellModules must be used within an AppShell\");\n }\n return registry;\n}\n","import { useMemo } from \"react\";\nimport { useLocation, Link } from \"react-router-dom\";\nimport { ChevronsLeft, ChevronsRight } from \"lucide-react\";\nimport { cn } from \"@petrarca/sonnet-core\";\nimport { ScrollArea } from \"@petrarca/sonnet-ui\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@petrarca/sonnet-ui\";\nimport type { ServiceModule, NavGroup } from \"./types\";\nimport { useExtensionPoint } from \"./hooks\";\n\ninterface SubNavPanelProps {\n service: ServiceModule;\n collapsed: boolean;\n onToggleCollapse: () => void;\n}\n\n/**\n * Merge contributed nav links from other modules.\n *\n * Contributions targeting \"<moduleId>.nav\" are appended as an additional\n * nav group after the module's own groups, sorted by contribution order.\n * The contribution mechanism is pre-sorted by createModuleRegistry.\n */\nfunction useMergedNavigation(service: ServiceModule): NavGroup[] {\n const contributions = useExtensionPoint(`${service.id}.nav`);\n return useMemo(() => {\n if (contributions.length === 0) return service.navigation;\n\n const contributed: NavGroup = {\n id: `${service.id}-contributed`,\n links: contributions.map((c) => ({\n id: c.extensionPoint + \".\" + c.label.toLowerCase().replace(/\\s+/g, \"-\"),\n label: c.label,\n path: c.path,\n })),\n };\n\n return [...service.navigation, contributed];\n }, [service, contributions]);\n}\n\n/**\n * SubNavPanel -- contextual secondary navigation for the selected service domain.\n *\n * Shows the service label at top, then grouped nav links. If other modules\n * contribute links via the \"<moduleId>.nav\" extension point, they are\n * appended as an additional group.\n */\nexport default function SubNavPanel({\n service,\n collapsed,\n onToggleCollapse,\n}: SubNavPanelProps) {\n const { pathname } = useLocation();\n const mergedNavigation = useMergedNavigation(service);\n\n if (collapsed) {\n return (\n <aside className=\"shrink-0 border-r bg-background flex flex-col items-center pt-2.5\">\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n className=\"text-muted-foreground/50 hover:text-muted-foreground transition-colors p-1\"\n onClick={onToggleCollapse}\n >\n <ChevronsRight className=\"h-4 w-4\" />\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"right\">Expand navigation</TooltipContent>\n </Tooltip>\n </aside>\n );\n }\n\n return (\n <aside className=\"w-52 shrink-0 border-r bg-background flex flex-col\">\n {/* Service header with collapse toggle */}\n <div className=\"h-10 shrink-0 flex items-center justify-between px-4\">\n <span className=\"heading-compact text-muted-foreground uppercase tracking-wider\">\n {service.label}\n </span>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n className=\"text-muted-foreground/40 hover:text-muted-foreground transition-colors p-0.5\"\n onClick={onToggleCollapse}\n >\n <ChevronsLeft className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"right\">Collapse navigation</TooltipContent>\n </Tooltip>\n </div>\n\n {/* Nav groups */}\n <ScrollArea className=\"flex-1\">\n <nav className=\"px-2 pb-4\">\n {mergedNavigation.map((group, gi) => (\n <div key={group.id} className={cn(gi > 0 && \"mt-4\")}>\n {group.heading && (\n <h6 className=\"heading-meta px-2 mb-1\">{group.heading}</h6>\n )}\n <ul className=\"space-y-0.5\">\n {group.links.map((link) => {\n const isActive = pathname === link.path;\n return (\n <li key={link.path}>\n <Link\n to={link.path}\n className={cn(\n \"flex items-center rounded-md px-2 py-1.5 text-sm transition-colors\",\n isActive\n ? \"bg-accent text-accent-foreground font-medium\"\n : \"text-muted-foreground hover:text-foreground hover:bg-accent/50\",\n )}\n >\n {link.label}\n </Link>\n </li>\n );\n })}\n </ul>\n </div>\n ))}\n </nav>\n </ScrollArea>\n </aside>\n );\n}\n","/**\n * Shell hooks -- reactive APIs for modules.\n *\n * Import path: @/shell/hooks\n */\nimport { useEffect, useMemo, useRef } from \"react\";\nimport { events } from \"./api\";\nimport { useShellModules } from \"./shellModules\";\nimport type { Contribution, ServiceModule, ShellEventMap } from \"./types\";\n\n/**\n * Get sorted contributions for a named extension point.\n *\n * Returns all contributions registered by any module for the given\n * extension point, sorted by `order` (ascending).\n *\n * @example\n * ```tsx\n * const tabs = useExtensionPoint(\"organization-detail\");\n * ```\n */\nexport function useExtensionPoint(name: string): Contribution[] {\n const { getExtensionPoint } = useShellModules();\n return useMemo(() => getExtensionPoint(name), [getExtensionPoint, name]);\n}\n\n/**\n * Get the list of visible service modules (excludes hidden and bottom-pinned).\n *\n * Useful for building overviews like the home page.\n */\nexport function useMainModules(): ServiceModule[] {\n const { mainModules } = useShellModules();\n return mainModules;\n}\n\n/**\n * Subscribe to a shell event, auto-unsubscribing on unmount.\n *\n * The handler reference is stabilized via useRef so that the\n * subscription is not torn down and recreated on every render.\n *\n * @example\n * ```tsx\n * useShellEvent(\"schema-definition:changed\", (payload) => {\n * queryClient.invalidateQueries({ queryKey: [\"my-key\"] });\n * });\n * ```\n */\nexport function useShellEvent<K extends keyof ShellEventMap>(\n key: K,\n handler: (payload: ShellEventMap[K]) => void,\n): void {\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n useEffect(() => {\n return events.on(key, (payload) => handlerRef.current(payload));\n }, [key]);\n}\n","/**\n * Shell API -- imperative domain capabilities for modules.\n *\n * Import path: @/shell/api\n *\n * Grouped by domain: notification, dialog, navigation, panel, events.\n */\nimport type { ReactNode } from \"react\";\nimport { toast } from \"sonner\";\nimport { warnLog } from \"@petrarca/sonnet-core\";\nimport type { ShellEventMap } from \"./types\";\nimport * as eventBus from \"./eventBus\";\n\n// notification\n\ninterface PromiseOptions<T> {\n loading: string;\n success: string | ((data: T) => string);\n error: string | ((err: unknown) => string);\n}\n\nexport const notification = {\n success(message: string) {\n toast.success(message);\n },\n error(message: string) {\n toast.error(message);\n },\n warning(message: string) {\n toast.warning(message);\n },\n info(message: string) {\n toast.info(message);\n },\n promise<T>(promise: Promise<T>, opts: PromiseOptions<T>) {\n return toast.promise(promise, opts);\n },\n dismiss(id?: string | number) {\n toast.dismiss(id);\n },\n};\n\n// dialog\n\n// The shell mounts a single ConfirmDialog instance in AppShell and injects\n// its open function here via initDialog(). Modules call dialog.confirm()\n// without knowing where the implementation lives -- federation-safe, same\n// pattern as navigation and panel.\n\nexport interface ConfirmOptions {\n title: string;\n description?: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: \"default\" | \"destructive\";\n}\n\ntype DialogConfirmFn = (opts: ConfirmOptions) => Promise<boolean>;\n\nlet _dialogConfirm: DialogConfirmFn | null = null;\n\n/**\n * Called by the shell during initialization to inject the confirm dialog.\n * Not part of the public module API -- only the shell calls this.\n */\nexport function initDialog(confirmFn: DialogConfirmFn) {\n _dialogConfirm = confirmFn;\n}\n\nexport const dialog = {\n /**\n * Show a confirmation dialog. Returns true if confirmed, false if cancelled.\n */\n confirm(opts: ConfirmOptions): Promise<boolean> {\n if (_dialogConfirm) {\n return _dialogConfirm(opts);\n }\n warnLog(\"dialog.confirm: shell not initialized yet.\");\n return Promise.resolve(false);\n },\n};\n\n// navigation\n\n// The shell injects the navigate function and command menu opener at startup\n// via initNavigation(). Modules call navigation.goTo() etc. without knowing\n// where the implementation comes from -- works with both monorepo and\n// Module Federation (host provides the injector, remotes consume the API).\n\ntype NavigateFn = (path: string) => void;\ntype CommandMenuFn = () => void;\ntype FeatureLookupFn = (featureId: string) => string | null;\n\nlet _navigate: NavigateFn | null = null;\nlet _openCommandMenu: CommandMenuFn | null = null;\nlet _lookupFeature: FeatureLookupFn | null = null;\n\n/**\n * Called by the shell during initialization to inject router + command menu.\n * Not part of the public module API -- only the shell calls this.\n */\nexport function initNavigation(\n navigateFn: NavigateFn,\n openCommandMenuFn: CommandMenuFn,\n) {\n _navigate = navigateFn;\n _openCommandMenu = openCommandMenuFn;\n}\n\n/**\n * Called by the shell during initialization to inject the feature lookup.\n * Resolves a stable feature id (e.g. \"auditing.audit-events\") to a path.\n * Not part of the public module API -- only the shell calls this.\n */\nexport function initFeatureNav(lookupFn: FeatureLookupFn) {\n _lookupFeature = lookupFn;\n}\n\nexport const navigation = {\n /** Navigate to a path within the shell. */\n goTo(path: string) {\n if (_navigate) {\n _navigate(path);\n } else {\n warnLog(\"navigation.goTo: shell not initialized yet.\");\n }\n },\n /**\n * Navigate to a feature by its stable identifier (e.g. \"auditing.audit-events\").\n * The path is resolved from the module registry at call time, so it stays\n * correct even if routes are reorganised.\n */\n goToFeature(featureId: string) {\n if (!_navigate || !_lookupFeature) {\n warnLog(\"navigation.goToFeature: shell not initialized yet.\");\n return;\n }\n const path = _lookupFeature(featureId);\n if (path) {\n _navigate(path);\n } else {\n warnLog(\"navigation.goToFeature: unknown feature id '{}'.\", featureId);\n }\n },\n /** Open the Cmd+K command menu. */\n openCommandMenu() {\n if (_openCommandMenu) {\n _openCommandMenu();\n } else {\n warnLog(\"navigation.openCommandMenu: shell not initialized yet.\");\n }\n },\n /** Go back in browser history. */\n back() {\n window.history.back();\n },\n};\n\n// panel\n\n// The shell owns the slide-over panel (Sheet). Modules request it via\n// panel.open() with content to render. The shell renders that content inside\n// the panel. Same injection pattern as navigation -- federation-safe.\n\nexport interface PanelOptions {\n /**\n * Title shown in the panel header. When omitted the header is visually\n * hidden (the content owns its own header) but a screen-reader-only\n * title is still rendered for accessibility.\n */\n title?: string;\n /** React content to render inside the panel */\n content: ReactNode;\n /** Optional description below the title */\n description?: string;\n /**\n * Panel width token.\n *\n * - \"narrow\" -- 480px -- quick actions, simple single-field forms\n * - \"default\" -- 640px -- standard entity forms (default when omitted)\n * - \"wide\" -- 800px -- forms with embedded tables or complex layouts\n * - \"half\" -- 50vw -- split-screen inspection, side-by-side context\n * - \"full\" -- 100vw -- immersive editing, full-width canvases\n *\n * Legacy values \"lg\", \"1/3\", \"1/2\" are kept for backward compatibility\n * and map to \"default\" (640px), 33vw, and \"half\" (50vw) respectively.\n */\n width?:\n | \"narrow\"\n | \"default\"\n | \"wide\"\n | \"half\"\n | \"full\"\n | \"lg\"\n | \"1/3\"\n | \"1/2\";\n /**\n * Vertical coverage of the panel.\n * - \"below-header\" (default): panel starts below the TopBar, keeping it visible.\n * - \"full\": panel covers the full viewport height including the TopBar.\n */\n coverage?: \"below-header\" | \"full\";\n /** Called after the panel finishes closing. Use to restore focus to the triggering element. */\n onClose?: () => void;\n}\n\ntype PanelOpenFn = (opts: PanelOptions) => void;\ntype PanelCloseFn = () => void;\n\nlet _panelOpen: PanelOpenFn | null = null;\nlet _panelClose: PanelCloseFn | null = null;\n\n/**\n * Called by the shell during initialization to inject panel controls.\n * Not part of the public module API -- only the shell calls this.\n */\nexport function initPanel(openFn: PanelOpenFn, closeFn: PanelCloseFn) {\n _panelOpen = openFn;\n _panelClose = closeFn;\n}\n\nexport const panel = {\n /** Open the shell panel with content rendered inside. */\n open(opts: PanelOptions) {\n if (_panelOpen) {\n _panelOpen(opts);\n } else {\n warnLog(\"panel.open: shell not initialized yet.\");\n }\n },\n /** Close the panel. */\n close() {\n if (_panelClose) {\n _panelClose();\n } else {\n warnLog(\"panel.close: shell not initialized yet.\");\n }\n },\n};\n\n// sidePane\n\n// The shell owns the side pane (SidePane component in AppShell). Modules\n// request it via sidePane.open() with content and sizing options. The pane\n// sits inline beside the content area -- the main view shrinks rather than\n// being overlaid. Same injection pattern as panel -- federation-safe.\n\nimport type { SidePaneOptions } from \"./sidePaneState\";\nexport type { SidePaneOptions };\n\ntype SidePaneOpenFn = (opts: SidePaneOptions) => void;\ntype SidePaneCloseFn = () => void;\ntype SidePaneIsOpenFn = () => boolean;\ntype SidePaneActiveModuleIdFn = () => string | null;\n\nlet _sidePaneOpen: SidePaneOpenFn | null = null;\nlet _sidePaneClose: SidePaneCloseFn | null = null;\nlet _sidePaneIsOpen: SidePaneIsOpenFn | null = null;\nlet _sidePaneActiveModuleId: SidePaneActiveModuleIdFn | null = null;\n\n/**\n * Called by the shell during initialization to inject side pane controls.\n * Not part of the public module API -- only the shell calls this.\n */\nexport function initSidePane(\n openFn: SidePaneOpenFn,\n closeFn: SidePaneCloseFn,\n isOpenFn: SidePaneIsOpenFn,\n activeModuleIdFn: SidePaneActiveModuleIdFn,\n) {\n _sidePaneOpen = openFn;\n _sidePaneClose = closeFn;\n _sidePaneIsOpen = isOpenFn;\n _sidePaneActiveModuleId = activeModuleIdFn;\n}\n\nexport const sidePane = {\n /** Open the side pane with the given content and sizing options. */\n open(opts: SidePaneOptions) {\n if (_sidePaneOpen) {\n _sidePaneOpen(opts);\n } else {\n warnLog(\"sidePane.open: shell not initialized yet.\");\n }\n },\n /** Close the side pane. */\n close() {\n if (_sidePaneClose) {\n _sidePaneClose();\n } else {\n warnLog(\"sidePane.close: shell not initialized yet.\");\n }\n },\n /**\n * Toggle the side pane.\n *\n * If the pane is closed, opens it with opts.\n * If the pane is open with the same moduleId, closes it.\n * If the pane is open with a different moduleId, replaces it with opts.\n */\n toggle(opts: SidePaneOptions) {\n if (\n !_sidePaneIsOpen ||\n !_sidePaneActiveModuleId ||\n !_sidePaneOpen ||\n !_sidePaneClose\n ) {\n warnLog(\"sidePane.toggle: shell not initialized yet.\");\n return;\n }\n if (_sidePaneIsOpen() && _sidePaneActiveModuleId() === opts.moduleId) {\n _sidePaneClose();\n } else {\n _sidePaneOpen(opts);\n }\n },\n /** Returns true when the pane is currently open. */\n isOpen(): boolean {\n return _sidePaneIsOpen ? _sidePaneIsOpen() : false;\n },\n /** Returns the moduleId of the currently open pane, or null. */\n activeModuleId(): string | null {\n return _sidePaneActiveModuleId ? _sidePaneActiveModuleId() : null;\n },\n};\n\n// fullscreen\n\n// The shell owns the fullscreen overlay. Modules request it via\n// fullscreen.enter(content) and exit via fullscreen.exit(). The shell renders\n// the content in a fixed inset-0 z-50 overlay, covering all shell chrome.\n// Same injection pattern as panel -- federation-safe.\n\nexport interface FullscreenOptions {\n /** React content to render inside the fullscreen overlay. */\n content: ReactNode;\n}\n\ntype FullscreenEnterFn = (opts: FullscreenOptions) => void;\ntype FullscreenExitFn = () => void;\n\nlet _fullscreenEnter: FullscreenEnterFn | null = null;\nlet _fullscreenExit: FullscreenExitFn | null = null;\n\n/**\n * Called by the shell during initialization to inject fullscreen controls.\n * Not part of the public module API -- only the shell calls this.\n */\nexport function initFullscreen(\n enterFn: FullscreenEnterFn,\n exitFn: FullscreenExitFn,\n) {\n _fullscreenEnter = enterFn;\n _fullscreenExit = exitFn;\n}\n\nexport const fullscreen = {\n /** Enter fullscreen mode, rendering content over all shell chrome. */\n enter(opts: FullscreenOptions) {\n if (_fullscreenEnter) {\n _fullscreenEnter(opts);\n } else {\n warnLog(\"fullscreen.enter: shell not initialized yet.\");\n }\n },\n /** Exit fullscreen mode, restoring the normal shell layout. */\n exit() {\n if (_fullscreenExit) {\n _fullscreenExit();\n } else {\n warnLog(\"fullscreen.exit: shell not initialized yet.\");\n }\n },\n};\n\n// events\n\ntype Unsubscribe = () => void;\n\nexport const events = {\n /** Subscribe to an event. Returns an unsubscribe function. */\n on<K extends keyof ShellEventMap>(\n key: K,\n handler: (payload: ShellEventMap[K]) => void,\n ): Unsubscribe {\n return eventBus.on(key as string, handler as (payload: unknown) => void);\n },\n\n /** Subscribe, auto-unsubscribing after the first emission. */\n once<K extends keyof ShellEventMap>(\n key: K,\n handler: (payload: ShellEventMap[K]) => void,\n ): Unsubscribe {\n return eventBus.once(key as string, handler as (payload: unknown) => void);\n },\n\n /** Emit an event. Handlers run asynchronously (microtask). */\n emit<K extends keyof ShellEventMap>(key: K, payload: ShellEventMap[K]): void {\n eventBus.emit(key as string, payload);\n },\n};\n","/**\n * Shell event bus -- in-memory pub/sub for cross-module communication.\n *\n * The bus is untyped internally (operates on strings and unknown payloads).\n * Type safety is provided by the public API layer in shell/api.ts, which\n * constrains keys and payloads via the ShellEventMap interface.\n *\n * Mirrors the server-side EventBus pattern (fire-and-forget, error isolation)\n * adapted for the browser's single-threaded model.\n */\nimport { devLog, warnLog } from \"@petrarca/sonnet-core\";\n\ntype Handler = (payload: unknown) => void;\ntype Unsubscribe = () => void;\n\nconst listeners = new Map<string, Set<Handler>>();\n\n/** Subscribe to an event key. Returns an unsubscribe function. */\nexport function on(key: string, handler: Handler): Unsubscribe {\n let set = listeners.get(key);\n if (!set) {\n set = new Set();\n listeners.set(key, set);\n }\n set.add(handler);\n devLog(`[shell:event] on \"${key}\" (${set.size} handler(s))`);\n return () => {\n set!.delete(handler);\n if (set!.size === 0) listeners.delete(key);\n devLog(`[shell:event] off \"${key}\" (${set!.size} handler(s))`);\n };\n}\n\n/** Subscribe to an event key, auto-unsubscribing after the first emission. */\nexport function once(key: string, handler: Handler): Unsubscribe {\n const unsubscribe = on(key, (payload) => {\n unsubscribe();\n handler(payload);\n });\n return unsubscribe;\n}\n\n/** Emit an event. Handlers run in microtasks (non-blocking, error-isolated). */\nexport function emit(key: string, payload: unknown): void {\n const set = listeners.get(key);\n const count = set?.size ?? 0;\n devLog(`[shell:event] emit \"${key}\"`, payload, `(${count} handler(s))`);\n if (!set || count === 0) return;\n for (const handler of set) {\n Promise.resolve().then(() => {\n try {\n handler(payload);\n } catch (err) {\n warnLog(`[shell:event] handler error \"${key}\":`, err);\n }\n });\n }\n}\n","/**\n * SidePane -- persistent resizable inline panel.\n *\n * Sits between SubNavPanel and the main content area in the AppShell flex row.\n * When open it takes a fixed pixel width; the content area (flex-1) shrinks to\n * fill the remainder. The main view remains fully visible and interactive.\n *\n * Opened/closed imperatively via sidePane.open() / sidePane.close() / sidePane.toggle()\n * from api.ts. State is provided by SidePaneContext (owned by AppShell).\n */\nimport { X } from \"lucide-react\";\nimport { cn } from \"@petrarca/sonnet-core\";\nimport { useResizablePanel } from \"@petrarca/sonnet-core/hooks\";\nimport { useSidePaneState } from \"./sidePaneState\";\n\nconst DEFAULT_WIDTH = 320;\nconst DEFAULT_MIN = 240;\nconst DEFAULT_MAX = 800;\n\n/**\n * SidePane renders nothing when no pane is open.\n * When open it renders a bordered panel with a drag handle on its right edge.\n * Double-clicking the handle resets to defaultWidth.\n */\nexport default function SidePane() {\n const { pane, close } = useSidePaneState();\n\n const { panelWidth, handlePointerDown, handleDoubleClick, separatorProps } =\n useResizablePanel({\n defaultWidth: pane?.defaultWidth ?? DEFAULT_WIDTH,\n minWidth: pane?.minWidth ?? DEFAULT_MIN,\n maxWidth: pane?.maxWidth ?? DEFAULT_MAX,\n direction: \"right-edge\",\n });\n\n if (!pane) return null;\n\n return (\n <div\n className=\"relative flex shrink-0 flex-col border-r bg-background\"\n style={{ width: panelWidth }}\n >\n {/* Header */}\n <div className=\"flex h-10 shrink-0 items-center justify-end border-b px-2\">\n <button\n onClick={close}\n className={cn(\n \"flex h-6 w-6 items-center justify-center rounded text-muted-foreground\",\n \"hover:bg-accent hover:text-foreground transition-colors\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n )}\n aria-label=\"Close side pane\"\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-auto\">{pane.content}</div>\n\n {/* Drag handle — right edge, full height */}\n <div\n {...separatorProps}\n onPointerDown={handlePointerDown}\n onDoubleClick={handleDoubleClick}\n className={cn(\n \"absolute right-0 top-0 h-full w-1 cursor-col-resize\",\n \"hover:bg-primary/40 active:bg-primary/60 transition-colors\",\n )}\n />\n </div>\n );\n}\n","/**\n * Side pane state types and context.\n *\n * The side pane is a persistent, resizable inline panel that sits between\n * the SubNavPanel and the main content area. It shrinks the content area\n * rather than overlaying it -- the main view stays visible and interactive.\n *\n * Modules open/close/toggle it via the imperative sidePane API in api.ts.\n * AppShell owns the state and injects it here via SidePaneContext so that\n * SidePane.tsx can read it without coupling to AppShell directly.\n */\nimport { createContext, useContext, type ReactNode } from \"react\";\n\nexport interface SidePaneOptions {\n /** Content to render inside the side pane. */\n content: ReactNode;\n /**\n * Stable key identifying which module/tool owns this pane instance.\n * Used by IconRail to highlight the active pane module and by toggle()\n * to detect whether the same content is already open.\n */\n moduleId: string;\n /** Initial width in pixels. Defaults to 320. */\n defaultWidth?: number;\n /** Minimum draggable width in pixels. Defaults to 240. */\n minWidth?: number;\n /**\n * Maximum draggable width in pixels.\n * Omit or pass Infinity for unlimited (fills remaining space up to viewport).\n */\n maxWidth?: number;\n}\n\nexport interface SidePaneState {\n /** Currently open pane options, or null when closed. */\n pane: SidePaneOptions | null;\n open: (opts: SidePaneOptions) => void;\n close: () => void;\n toggle: (opts: SidePaneOptions) => void;\n}\n\nexport const SidePaneContext = createContext<SidePaneState | null>(null);\n\n/**\n * Read the side pane state from context.\n * Must be called within an AppShell (which provides the context).\n */\nexport function useSidePaneState(): SidePaneState {\n const ctx = useContext(SidePaneContext);\n if (!ctx) {\n throw new Error(\"useSidePaneState must be used within an AppShell\");\n }\n return ctx;\n}\n","import { useEffect, useCallback } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport {\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n} from \"@petrarca/sonnet-ui\";\nimport { useShellModules } from \"./shellModules\";\nimport type { ServiceModule } from \"./types\";\n\ninterface CommandMenuProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\n/**\n * CommandMenu -- Cmd+K command menu.\n *\n * Indexes all navigation items from the service domains so users can\n * quickly jump to any page by typing.\n */\nexport default function CommandMenu({ open, onOpenChange }: CommandMenuProps) {\n const navigate = useNavigate();\n const { mainModules, bottomModules } = useShellModules();\n\n // Global Cmd+K / Ctrl+K shortcut\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"k\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n onOpenChange(!open);\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, onOpenChange]);\n\n const handleSelect = useCallback(\n (path: string) => {\n navigate(path);\n onOpenChange(false);\n },\n [navigate, onOpenChange],\n );\n\n const renderNavGroup = (service: ServiceModule) => {\n if (service.navigation.length === 0) return null;\n const Icon = service.icon;\n return (\n <CommandGroup key={`nav-${service.id}`} heading={service.label}>\n {service.navigation.flatMap((group) =>\n group.links.map((link) => (\n <CommandItem\n key={link.path}\n value={`${service.label} ${group.heading ?? \"\"} ${link.label}`}\n onSelect={() => handleSelect(link.path)}\n >\n <Icon className=\"mr-2 h-4 w-4 text-muted-foreground\" />\n <span>{link.label}</span>\n {group.heading && (\n <span className=\"ml-auto text-xs text-muted-foreground\">\n {group.heading}\n </span>\n )}\n </CommandItem>\n )),\n )}\n </CommandGroup>\n );\n };\n\n const renderCommandGroup = (service: ServiceModule) => {\n if (!service.commands?.length) return null;\n const Icon = service.icon;\n return (\n <CommandGroup\n key={`cmd-${service.id}`}\n heading={service.commands[0].group ?? service.label}\n >\n {service.commands.map((cmd) => {\n const CmdIcon = cmd.icon ?? Icon;\n return (\n <CommandItem\n key={cmd.id}\n value={`${service.label} ${cmd.label}`}\n onSelect={() => {\n cmd.action();\n onOpenChange(false);\n }}\n >\n <CmdIcon className=\"mr-2 h-4 w-4 text-muted-foreground\" />\n <span>{cmd.label}</span>\n </CommandItem>\n );\n })}\n </CommandGroup>\n );\n };\n\n const allModules = [...mainModules, ...bottomModules];\n\n return (\n <CommandDialog open={open} onOpenChange={onOpenChange}>\n <CommandInput placeholder=\"Search pages, services, actions...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n\n {mainModules.map(renderNavGroup)}\n\n <CommandSeparator />\n\n {bottomModules.map(renderNavGroup)}\n\n {allModules.some((m) => m.commands?.length) && (\n <>\n <CommandSeparator />\n {allModules.map(renderCommandGroup)}\n </>\n )}\n </CommandList>\n </CommandDialog>\n );\n}\n","/**\n * Shell configuration types and context.\n *\n * ShellConfig is intentionally minimal. The shell provides layout chrome\n * (TopBar header, IconRail, SubNavPanel, CommandMenu) but does not own\n * any app-specific content. The consumer composes the TopBar content --\n * logo, environment selector, search trigger, user menu -- via the\n * `topBar` ReactNode slot using building blocks exported from the shell.\n */\nimport { createContext, useContext, type ReactNode } from \"react\";\n\n// Top-level shell configuration.\n\nexport interface ShellConfig {\n /**\n * Content rendered inside the TopBar header. The shell provides the\n * `<header>` element with its sizing and border; the consumer owns\n * everything inside it.\n *\n * Compose this using building blocks like `SearchTrigger` and\n * `UserMenu` (exported from the shell) alongside any app-specific\n * components.\n */\n topBar?: ReactNode;\n}\n\n// Context\n\nexport const ShellConfigContext = createContext<ShellConfig | null>(null);\n\n/**\n * Read the shell configuration from context.\n * Must be called within a ShellConfigProvider.\n */\nexport function useShellConfig(): ShellConfig {\n const config = useContext(ShellConfigContext);\n if (!config) {\n throw new Error(\"useShellConfig must be used within a ShellConfigProvider\");\n }\n return config;\n}\n","import { Toaster } from \"sonner\";\nimport AppShell from \"./AppShell\";\nimport { ShellConfigProvider } from \"./ShellConfigProvider\";\nimport type { ShellConfig } from \"./shellConfig\";\nimport type { ModuleRegistry } from \"./createModuleRegistry\";\n\n/**\n * RootLayout -- top-level layout that wraps the entire authenticated app.\n * Renders the Toaster for notifications and the AppShell (icon rail + sub-nav + content).\n */\n\ninterface RootLayoutProps {\n config: ShellConfig;\n registry: ModuleRegistry;\n}\n\nexport default function RootLayout({ config, registry }: RootLayoutProps) {\n return (\n <ShellConfigProvider config={config}>\n <Toaster position=\"top-right\" richColors closeButton />\n <AppShell registry={registry} />\n </ShellConfigProvider>\n );\n}\n","/**\n * ShellConfigProvider -- wraps the shell with configuration context.\n */\nimport type { ReactNode } from \"react\";\nimport { ShellConfigContext, type ShellConfig } from \"./shellConfig\";\n\ninterface ShellConfigProviderProps {\n config: ShellConfig;\n children: ReactNode;\n}\n\nexport function ShellConfigProvider({\n config,\n children,\n}: ShellConfigProviderProps) {\n return (\n <ShellConfigContext.Provider value={config}>\n {children}\n </ShellConfigContext.Provider>\n );\n}\n","import { useLocation } from \"react-router-dom\";\n\n/**\n * PlaceholderPage — generic wireframe page for routes not yet implemented.\n * Shows the current path and a placeholder content area.\n */\nexport default function PlaceholderPage() {\n const { pathname } = useLocation();\n\n return (\n <div>\n <h1 className=\"mb-1\">{pathToTitle(pathname)}</h1>\n <p className=\"text-sm text-muted-foreground mb-6\">{pathname}</p>\n\n {/* Wireframe content placeholder */}\n <div className=\"rounded-lg border-2 border-dashed border-border p-12 flex items-center justify-center\">\n <span className=\"text-sm text-muted-foreground\">\n Content area — not yet implemented\n </span>\n </div>\n </div>\n );\n}\n\n/** Convert a path like \"/healthcare/patients\" to \"Patients\" */\nfunction pathToTitle(path: string): string {\n const last = path.split(\"/\").filter(Boolean).pop();\n if (!last) return \"Dashboard\";\n return last\n .split(\"-\")\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(\" \");\n}\n","import { Search } from \"lucide-react\";\nimport { Button } from \"@petrarca/sonnet-ui\";\nimport { navigation } from \"./api\";\n\n/**\n * SearchTrigger -- Cmd+K search button for the TopBar.\n *\n * Opens the shell CommandMenu via the imperative navigation API.\n * Generic building block, no app-specific dependencies.\n */\nexport function SearchTrigger() {\n return (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-7 gap-2 text-xs text-muted-foreground w-52 justify-start\"\n onClick={() => navigation.openCommandMenu()}\n >\n <Search className=\"h-3.5 w-3.5\" />\n <span>Search...</span>\n <kbd className=\"ml-auto pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground\">\n <span className=\"text-xs\">⌘</span>K\n </kbd>\n </Button>\n );\n}\n","import { LogOut, User } from \"lucide-react\";\nimport { Button } from \"@petrarca/sonnet-ui\";\nimport { Avatar, AvatarFallback } from \"@petrarca/sonnet-ui\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@petrarca/sonnet-ui\";\n\n/**\n * UserMenu -- avatar dropdown for the TopBar.\n *\n * Shows the user's initials in an avatar. The dropdown displays name,\n * email, a profile link, and a sign-out action. Generic building block,\n * no app-specific dependencies.\n */\n\nexport interface UserMenuUser {\n name: string;\n email: string;\n initials: string;\n}\n\ninterface UserMenuProps {\n user: UserMenuUser;\n onSignOut?: () => void;\n}\n\nexport function UserMenu({ user, onSignOut }: UserMenuProps) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"compact\" className=\"rounded-full\">\n <Avatar className=\"h-7 w-7\">\n <AvatarFallback className=\"text-xs\">{user.initials}</AvatarFallback>\n </Avatar>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-48\">\n <DropdownMenuLabel className=\"font-normal\">\n <div className=\"flex flex-col gap-1\">\n <p className=\"text-sm font-medium\">{user.name}</p>\n <p className=\"text-xs text-muted-foreground\">{user.email}</p>\n </div>\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n <DropdownMenuItem>\n <User className=\"mr-2 h-4 w-4\" />\n Profile\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem onSelect={onSignOut}>\n <LogOut className=\"mr-2 h-4 w-4\" />\n Sign out\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n","/**\n * Module registry factory.\n *\n * Accepts a list of ServiceModules and returns derived data structures\n * consumed by the shell (icon rail groups, flattened routes, extension\n * point lookup). This is the reusable core; the app-specific module\n * list lives in the consumer (e.g. modules/registry.ts).\n */\nimport type { RouteObject } from \"react-router-dom\";\nimport type { ServiceModule, Contribution } from \"./types\";\n\nexport interface ModuleRegistry {\n /** All modules in registration order. */\n modules: ServiceModule[];\n\n /** Visible modules shown in the main area of the icon rail. */\n mainModules: ServiceModule[];\n\n /** Modules pinned to the bottom of the icon rail. */\n bottomModules: ServiceModule[];\n\n /** All routes from all modules, flattened. */\n allRoutes: RouteObject[];\n\n /** Get contributions for a named extension point, sorted by order. */\n getExtensionPoint: (name: string) => Contribution[];\n}\n\nexport function createModuleRegistry(modules: ServiceModule[]): ModuleRegistry {\n const visible = modules.filter((m) => !m.hidden);\n const mainModules = visible.filter((m) => !m.pinBottom);\n const bottomModules = visible.filter((m) => m.pinBottom);\n const allRoutes = modules.flatMap((m) => m.routes);\n\n // Pre-collect all contributions for O(n) lookup per call.\n const contributionsByPoint = new Map<string, Contribution[]>();\n for (const m of modules) {\n for (const c of m.contributions ?? []) {\n const list = contributionsByPoint.get(c.extensionPoint) ?? [];\n list.push(c);\n contributionsByPoint.set(c.extensionPoint, list);\n }\n }\n // Sort each group once.\n for (const list of contributionsByPoint.values()) {\n list.sort((a, b) => a.order - b.order);\n }\n\n function getExtensionPoint(name: string): Contribution[] {\n return contributionsByPoint.get(name) ?? [];\n }\n\n return { modules, mainModules, bottomModules, allRoutes, getExtensionPoint };\n}\n","/**\n * OverviewCard and FeatureLink -- building blocks for module overview pages.\n *\n * OverviewCard presents a feature with icon, title, description, and optional\n * navigation via a stable feature id.\n *\n * FeatureLink is an inline text link for use in descriptions or prose,\n * also navigating via stable feature id.\n *\n * Part of the shell -- extracts to @petrarca/sonnet-shell.\n */\n\nimport React from \"react\";\nimport { cn } from \"@petrarca/sonnet-core\";\nimport { navigation } from \"./api\";\n\ninterface OverviewCardProps {\n /** Lucide icon component. */\n icon: React.ComponentType<{ className?: string }>;\n /** Card title. */\n title: string;\n /** Description -- plain string or React nodes (e.g. with FeatureLink). */\n description: React.ReactNode;\n /**\n * Stable feature identifier (e.g. \"auditing.audit-events\").\n * Resolved to a path via the shell registry at click time.\n * Omit for non-navigable cards.\n */\n feature?: string;\n /** Additional CSS class names. */\n className?: string;\n}\n\n/**\n * FeatureLink -- inline text link navigating to a feature by stable id.\n *\n * Use inside OverviewCard descriptions or overview page prose to link\n * to a feature without hardcoding paths.\n *\n * @example\n * <FeatureLink feature=\"auditing.audit-log\">Audit Log</FeatureLink>\n */\nexport function FeatureLink({\n feature,\n children,\n}: {\n feature: string;\n children: React.ReactNode;\n}): React.ReactElement {\n return (\n <span\n role=\"link\"\n tabIndex={0}\n onClick={(e) => {\n e.stopPropagation();\n navigation.goToFeature(feature);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n e.stopPropagation();\n navigation.goToFeature(feature);\n }\n }}\n className=\"underline underline-offset-2 hover:text-foreground transition-colors cursor-pointer\"\n >\n {children}\n </span>\n );\n}\n\n/** Feature card for module overview pages. Navigates via the shell API. */\nexport function OverviewCard({\n icon: Icon,\n title,\n description,\n feature,\n className,\n}: OverviewCardProps): React.ReactElement {\n return (\n <button\n onClick={feature ? () => navigation.goToFeature(feature) : undefined}\n disabled={!feature}\n className={cn(\n \"rounded-lg border bg-card p-5 text-left flex flex-col gap-3\",\n \"disabled:cursor-default\",\n feature && \"hover:bg-accent/50 transition-colors\",\n className,\n )}\n >\n <div className=\"h-9 w-9 rounded-md bg-blue-50 flex items-center justify-center shrink-0\">\n <Icon className=\"h-5 w-5 text-blue-600\" />\n </div>\n <div>\n <p className=\"text-sm font-medium mb-1\">{title}</p>\n <p className=\"text-xs text-muted-foreground leading-relaxed\">\n {description}\n </p>\n </div>\n </button>\n );\n}\n"],"mappings":"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","names":["useEffect","useCallback","useRef","useMemo","useLocation","useNavigate","ScrollArea","jsx","Button","jsx","jsxs","Button","useMemo","cn","Tooltip","TooltipContent","TooltipTrigger","warnLog","warnLog","jsx","jsxs","useMemo","Tooltip","TooltipTrigger","TooltipContent","cn","cn","createContext","useContext","jsx","jsxs","cn","useEffect","jsx","jsxs","useEffect","createContext","useContext","Fragment","jsx","jsxs","useRef","useEffect","useLocation","useMemo","useCallback","useSidePaneState","useNavigate","sidePane","panel","dialog","ScrollArea","jsx","jsx","jsxs","useLocation","jsx","jsxs","Button","jsx","jsxs","Button","Button","jsx","jsxs","cn","jsx","jsxs","cn"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@petrarca/sonnet-shell",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Application shell, layout, navigation, auth flow, and imperative API for the Petrarca Sonnet component library",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./auth": {
|
|
18
|
+
"import": "./dist/auth/index.js",
|
|
19
|
+
"types": "./dist/auth/index.d.ts"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"lucide-react": "^0.553.0",
|
|
27
|
+
"sonner": "^2.0.7",
|
|
28
|
+
"@petrarca/sonnet-core": "0.1.0",
|
|
29
|
+
"@petrarca/sonnet-ui": "0.1.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"react": ">=18",
|
|
33
|
+
"react-dom": ">=18",
|
|
34
|
+
"react-router-dom": ">=7",
|
|
35
|
+
"tailwindcss": ">=3"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/react": "^19.0.0",
|
|
39
|
+
"@types/react-dom": "^19.0.0",
|
|
40
|
+
"tsup": "^8.4.0",
|
|
41
|
+
"typescript": "^5.9.2"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsup",
|
|
45
|
+
"dev": "tsup --watch",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"lint": "tsc --noEmit",
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"clean": "rm -rf dist *.tsbuildinfo"
|
|
50
|
+
}
|
|
51
|
+
}
|