Files
portainer/app/react/components/HeaderLayout/HeaderLayout.tsx
T
2026-04-15 05:12:52 +03:00

107 lines
2.7 KiB
TypeScript

import { ReactNode } from 'react';
import clsx from 'clsx';
import { InlineLoader } from '@@/InlineLoader';
import { Alert } from '@@/Alert';
import { Widget } from '@@/Widget';
interface Props {
// Data states
isLoading: boolean;
errorMessage?: string;
// Icon section
icon: ReactNode;
iconBackgroundClassName?: string;
// Header section
subtitleLabel?: string;
subtitleClassName?: string;
title: string;
badge?: ReactNode;
description?: ReactNode;
// Right side info
rightInfo?: ReactNode;
// Customization
containerClassName?: string;
widgetClassName?: string;
}
export function HeaderLayout({
isLoading,
errorMessage,
icon,
iconBackgroundClassName = 'bg-group-accent-3 th-dark:bg-group-accent-10',
subtitleLabel,
subtitleClassName = 'text-group-accent-10 th-dark:text-group-accent-8',
title,
badge,
description,
rightInfo,
containerClassName = 'flex items-center gap-4 p-4',
widgetClassName = '!border border-solid border-gray-4 th-dark:border-widget th-highcontrast:border-gray-11',
}: Props) {
if (isLoading) {
return (
<Widget className={widgetClassName}>
<div className={containerClassName}>
<InlineLoader>Loading details...</InlineLoader>
</div>
</Widget>
);
}
if (errorMessage) {
return (
<Widget className={widgetClassName}>
<div className={containerClassName}>
<Alert color="error" title="Error">
{errorMessage}
</Alert>
</div>
</Widget>
);
}
return (
<Widget className={widgetClassName}>
<div className={containerClassName}>
{/* Icon container */}
<div
className={clsx(
'flex h-14 w-14 shrink-0 items-center justify-center rounded-lg text-3xl',
iconBackgroundClassName
)}
>
{icon}
</div>
{/* Header info */}
<div className="flex flex-1 flex-col gap-0">
{subtitleLabel && (
<div className="flex items-center gap-2">
<span className={clsx('text-xs font-medium', subtitleClassName)}>
{subtitleLabel}
</span>
</div>
)}
<div className="flex items-center gap-2">
<span className="text-lg font-bold">{title}</span>
{badge && <div className="flex flex-wrap gap-1">{badge}</div>}
</div>
{description && (
<span className="text-muted text-xs">{description}</span>
)}
</div>
{/* Right-side info */}
{rightInfo && (
<div className="flex items-center gap-6">{rightInfo}</div>
)}
</div>
</Widget>
);
}