97 lines
3.0 KiB
TypeScript
97 lines
3.0 KiB
TypeScript
import type { HTMLAttributes, ReactNode } from "react";
|
|
import { cn } from "./cn";
|
|
import { Icon } from "./Icon";
|
|
|
|
export interface ApplicationShellProps extends Omit<HTMLAttributes<HTMLDivElement>, "content"> {
|
|
header: ReactNode;
|
|
stage: ReactNode;
|
|
navigation?: ReactNode;
|
|
content?: ReactNode;
|
|
navigationOpen?: boolean;
|
|
contentOpen?: boolean;
|
|
contentExpanded?: boolean;
|
|
}
|
|
|
|
export function ApplicationShell({
|
|
header,
|
|
stage,
|
|
navigation,
|
|
content,
|
|
navigationOpen = false,
|
|
contentOpen = false,
|
|
contentExpanded = false,
|
|
className,
|
|
...props
|
|
}: ApplicationShellProps) {
|
|
return (
|
|
<div
|
|
className={cn("nodedc-app-shell", className)}
|
|
data-navigation-open={navigationOpen ? "true" : undefined}
|
|
data-content-open={contentOpen ? "true" : undefined}
|
|
data-content-expanded={contentOpen && contentExpanded ? "true" : undefined}
|
|
{...props}
|
|
>
|
|
{header}
|
|
<main className="nodedc-app-shell__main">
|
|
<div className="nodedc-app-shell__stage">{stage}</div>
|
|
{navigationOpen && navigation ? <div className="nodedc-app-shell__navigation">{navigation}</div> : null}
|
|
{contentOpen && content ? <div className="nodedc-app-shell__content">{content}</div> : null}
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export interface ApplicationPanelProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
|
|
eyebrow?: ReactNode;
|
|
title: ReactNode;
|
|
description?: ReactNode;
|
|
expanded?: boolean;
|
|
expandLabel?: string;
|
|
closeLabel?: string;
|
|
onExpandedChange?: (expanded: boolean) => void;
|
|
onClose: () => void;
|
|
children: ReactNode;
|
|
}
|
|
|
|
export function ApplicationPanel({
|
|
eyebrow,
|
|
title,
|
|
description,
|
|
expanded = false,
|
|
expandLabel = "Развернуть окно",
|
|
closeLabel = "Закрыть окно",
|
|
onExpandedChange,
|
|
onClose,
|
|
children,
|
|
className,
|
|
...props
|
|
}: ApplicationPanelProps) {
|
|
return (
|
|
<section className={cn("nodedc-application-panel", className)} data-expanded={expanded ? "true" : undefined} {...props}>
|
|
<header className="nodedc-application-panel__head">
|
|
<div className="nodedc-application-panel__titles">
|
|
{eyebrow ? <span>{eyebrow}</span> : null}
|
|
<h1>{title}</h1>
|
|
{description ? <p>{description}</p> : null}
|
|
</div>
|
|
<div className="nodedc-application-panel__actions">
|
|
{onExpandedChange ? (
|
|
<button
|
|
type="button"
|
|
className="nodedc-application-panel__action"
|
|
aria-label={expanded ? "Свернуть окно" : expandLabel}
|
|
onClick={() => onExpandedChange(!expanded)}
|
|
>
|
|
<Icon name={expanded ? "minimize" : "expand"} />
|
|
</button>
|
|
) : null}
|
|
<button type="button" className="nodedc-application-panel__action" aria-label={closeLabel} onClick={onClose}>
|
|
<Icon name="close" />
|
|
</button>
|
|
</div>
|
|
</header>
|
|
<div className="nodedc-application-panel__body">{children}</div>
|
|
</section>
|
|
);
|
|
}
|