89 lines
3.5 KiB
JavaScript
89 lines
3.5 KiB
JavaScript
import PropTypes from 'prop-types';
|
|
|
|
import { HStack } from '@astryxdesign/core/HStack';
|
|
import { VStack } from '@astryxdesign/core/VStack';
|
|
import { Heading } from '@astryxdesign/core/Heading';
|
|
import { Text } from '@astryxdesign/core/Text';
|
|
import { StatusDot } from '@astryxdesign/core/StatusDot';
|
|
|
|
import { DT } from 'themes/dt/tokens';
|
|
|
|
// ==============================|| PAGE HEADER ||============================== //
|
|
//
|
|
// A plain, un-boxed page title + optional live indicator + an action slot
|
|
// (zone selector, primary button, etc.), so every operator page opens with a
|
|
// calm, corporate heading.
|
|
//
|
|
// The STRUCTURE follows KROW's page frame; the colours and the type are the
|
|
// console's own and are unchanged — `Heading level={1}` and `Text
|
|
// type="supporting"` resolve to exactly the same tokens they did before.
|
|
//
|
|
// Title · meta · ● Live [ actions ]
|
|
// subtitle
|
|
// ──────────────────────────────────────────────────────────────
|
|
//
|
|
// Two things the KROW work changed:
|
|
//
|
|
// - The bottom hairline. KROW closes every page header with a rule, and it
|
|
// is what makes the header read as a REGION of the page rather than as
|
|
// the first item in the content stack — without it, a page header and a
|
|
// section heading look identical and the page has no top.
|
|
//
|
|
// - `live` moved from beside the subtitle up onto the title row. It was
|
|
// putting the page's only motion cue on its quietest line; a live
|
|
// indicator belongs where people look for it. It is still the same
|
|
// pulsing `StatusDot variant="success"` — nothing about its colour moved.
|
|
//
|
|
// `meta` is new and optional: a real count that belongs beside the name
|
|
// ("1,248 orders"), with tabular figures so it doesn't jitter as it updates.
|
|
//
|
|
// `action` keeps its name and still wraps to its own line once it can't fit,
|
|
// which is the behaviour the old responsive `direction={{ xs: 'column', sm:
|
|
// 'row' }}` was approximating.
|
|
|
|
export default function PageHeader({ title, subtitle, meta, live = false, action }) {
|
|
return (
|
|
<VStack
|
|
gap={0}
|
|
padding={0}
|
|
style={{
|
|
paddingBottom: 16,
|
|
// The existing hairline at 50% alpha — a page header's rule should sit
|
|
// under the table borders it introduces, not match them.
|
|
borderBottom: `1px solid ${DT.borderSubtle}80`
|
|
}}
|
|
>
|
|
<HStack justify="between" vAlign="center" wrap="wrap" gap={2} paddingBlock={1}>
|
|
{/* minWidth in `style` — VStack has no such prop (see StatCard). */}
|
|
<VStack gap={0.5} padding={0} style={{ minWidth: 0 }}>
|
|
<HStack gap={2} vAlign="center" wrap="wrap">
|
|
<Heading level={1} maxLines={1}>
|
|
{title}
|
|
</Heading>
|
|
{meta != null && (
|
|
<Text type="supporting" hasTabularNumbers>
|
|
{meta}
|
|
</Text>
|
|
)}
|
|
{live && <StatusDot variant="success" label="Live" isPulsing />}
|
|
</HStack>
|
|
{subtitle && <Text type="supporting">{subtitle}</Text>}
|
|
</VStack>
|
|
{action && (
|
|
<HStack gap={1.5} vAlign="center" wrap="wrap" style={{ flexShrink: 0 }}>
|
|
{action}
|
|
</HStack>
|
|
)}
|
|
</HStack>
|
|
</VStack>
|
|
);
|
|
}
|
|
|
|
PageHeader.propTypes = {
|
|
title: PropTypes.node,
|
|
subtitle: PropTypes.node,
|
|
meta: PropTypes.node,
|
|
live: PropTypes.bool,
|
|
action: PropTypes.node
|
|
};
|