import * as React from 'react' import { ButtonWidget } from '../Button/ButtonWidget' import { ButtonArrayLayout } from '../Button/ButtonArrayLayout' import { ToggleField } from '../Toggle/ToggleField' import { ButtonToggle } from '../ButtonToggle/ButtonToggle' import type { SAILColorInput } from '../../types/sail' import { paletteHexMap, type SAILPaletteColor } from '../../types/palette-colors.generated' import { ICON_APP, ICON_INTERFACE, ICON_RECORD_TYPE, ICON_EXPRESSION_RULE, APPIAN_LOGO, } from './assets' type ObjectType = 'app' | 'interface' | 'record-type' | 'expression-rule' const DEFAULT_ICON_MAP: Record = { 'app': ICON_APP, 'interface': ICON_INTERFACE, 'record-type': ICON_RECORD_TYPE, 'expression-rule': ICON_EXPRESSION_RULE, } export interface ApplicationHeaderProps { /** Name of the application or object */ name?: string /** User initials to display in avatar */ userInitials?: string /** Show interface designer controls */ showDesignerControls?: boolean /** Type of object being displayed */ objectType?: ObjectType /** Path to custom icon image */ iconSrc?: string /** Preview mode enabled */ previewEnabled?: boolean /** Stories view enabled */ showStoriesView?: boolean /** Callback when preview toggle changes */ onPreviewToggle?: (enabled: boolean) => void /** Callback when stories toggle changes */ onStoryToggle?: () => void /** Callback when back button clicked */ onBackClick?: () => void /** Path to Appian logo image */ appianLogoSrc?: string /** Background color for the header (hex). Foreground colors auto-swap for contrast. */ backgroundColor?: string /** Additional buttons to display before the right-side controls */ additionalButtons?: Array<{ label: string style?: "SOLID" | "OUTLINE" | "GHOST" | "LINK" size?: "SMALL" | "STANDARD" | "MEDIUM" | "LARGE" color?: SAILColorInput onClick?: () => void }> /** Additional Tailwind classes for prototype-specific styling (not part of SAIL API) */ className?: string } /** * ApplicationHeader Component * Displays the main application header with navigation, controls, and user info * */ export const ApplicationHeader: React.FC = ({ name = "Application", userInitials = "U", showDesignerControls = false, objectType = 'app', iconSrc, previewEnabled = false, showStoriesView = false, onPreviewToggle, onStoryToggle, onBackClick, appianLogoSrc, backgroundColor, additionalButtons = [], className }) => { const displayIconSrc = iconSrc || DEFAULT_ICON_MAP[objectType] const isDefaultIcon = !iconSrc const resolvedLogoSrc = appianLogoSrc ?? APPIAN_LOGO // Only support full #rrggbb hex — anything else falls back to default gradient const isValidHex = (s: string) => /^#[0-9a-fA-F]{6}$/.test(s) const resolvedBgColor = backgroundColor && (backgroundColor in paletteHexMap) ? paletteHexMap[backgroundColor as SAILPaletteColor] : backgroundColor const validBgColor = resolvedBgColor && isValidHex(resolvedBgColor) ? resolvedBgColor : undefined // WCAG contrast helper — returns '#ffffff' or '#000000' for a hex bg const getContrastColor = (hex: string): string => { const r = parseInt(hex.slice(1, 3), 16) const g = parseInt(hex.slice(3, 5), 16) const b = parseInt(hex.slice(5, 7), 16) const toLinear = (c: number) => { const s = c / 255; return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4) } const L = 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b) return (1.05 / (L + 0.05)) >= ((L + 0.05) / 0.05) ? '#ffffff' : '#000000' } const fgColor = validBgColor ? getContrastColor(validBgColor) : undefined const isLight = fgColor === '#000000' // For ghost buttons: use a hex color so ButtonWidget applies inline styles const ghostButtonColor: SAILColorInput = fgColor ?? 'STANDARD' const headerClasses = [ !validBgColor && 'application-header-gradient border-b border-gray-200', className ].filter(Boolean).join(' ') const headerStyle: React.CSSProperties | undefined = validBgColor ? { backgroundColor: validBgColor, borderBottom: '1px solid rgba(0,0,0,0.1)' } : undefined return (
{/* Left section */}
{showDesignerControls && onBackClick && ( )}
{objectType} {name}
{showDesignerControls && ( <>
)}
{/* Center section */}
{showDesignerControls && ( <>
)}
{/* Right section */}
{additionalButtons.length > 0 && (
({ label: btn.label, style: btn.style || "OUTLINE", size: btn.size || "SMALL", color: btn.color || "STANDARD", onClick: btn.onClick, className: "border-1" }))} marginBelow="NONE" />
)} {showDesignerControls && ( <>
)}
{userInitials}
Appian
) }