Detail-page headers put their action buttons in a flex row with flexWrap:"wrap", so on a phone the 2-4 buttons (Potvrzení / Zahájit realizaci / Smazat, etc.) wrapped into a ragged grid. New shared `headerActionsSx` (ui/PageHeader): on xs it's a full-width column (each button its own full-width row); from sm up it's the usual right-aligned wrapping row — desktop unchanged. A StatusChip kept in the same group stays its natural size (alignSelf) instead of stretching. Applied to PageHeader's own actions slot and every detail-page header action group: Order/Offer/Invoice (both views)/Project + the Warehouse Receipt/Issue/Item/Inventory detail headers. Verified in Chrome at 430px on OrderDetail: the group is flexDirection column with all three buttons at the same x, full-width, stacked. tsc -b --noEmit, npm run build, vitest 152/152 clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
64 lines
1.9 KiB
TypeScript
64 lines
1.9 KiB
TypeScript
import type { ReactNode } from "react";
|
|
import Box from "@mui/material/Box";
|
|
import Typography from "@mui/material/Typography";
|
|
import type { SxProps, Theme } from "@mui/material/styles";
|
|
|
|
export interface PageHeaderProps {
|
|
title: string;
|
|
subtitle?: string;
|
|
actions?: ReactNode;
|
|
}
|
|
|
|
/**
|
|
* Shared sx for a header action-button group. On mobile each button gets its
|
|
* own full-width row (column + stretch); from `sm` up it's the usual right-
|
|
* aligned wrapping row. Use on the Box that wraps the header's action Buttons
|
|
* (page headers + detail-page headers) so the mobile layout is identical
|
|
* everywhere — no more buttons wrapping into a ragged grid on phones.
|
|
*/
|
|
export const headerActionsSx: SxProps<Theme> = {
|
|
display: "flex",
|
|
flexDirection: { xs: "column", sm: "row" },
|
|
alignItems: { xs: "stretch", sm: "center" },
|
|
justifyContent: { sm: "flex-end" },
|
|
flexWrap: { sm: "wrap" },
|
|
gap: 1,
|
|
width: { xs: "100%", sm: "auto" },
|
|
// Some detail-page headers keep a StatusChip in this same group — keep it at
|
|
// its natural size on mobile instead of stretching it into a full-width bar.
|
|
"& > .MuiChip-root": { alignSelf: { xs: "flex-start", sm: "auto" } },
|
|
};
|
|
|
|
/**
|
|
* Standard page header: title (+ optional subtitle) on the left,
|
|
* action controls on the right. No framer-motion — pages add their own entrance.
|
|
*/
|
|
export default function PageHeader({
|
|
title,
|
|
subtitle,
|
|
actions,
|
|
}: PageHeaderProps) {
|
|
return (
|
|
<Box
|
|
sx={{
|
|
display: "flex",
|
|
alignItems: "flex-start",
|
|
justifyContent: "space-between",
|
|
flexWrap: "wrap",
|
|
gap: 2,
|
|
mb: 3,
|
|
}}
|
|
>
|
|
<Box>
|
|
<Typography variant="h4">{title}</Typography>
|
|
{subtitle && (
|
|
<Typography variant="body2" color="text.secondary" sx={{ mt: 0.5 }}>
|
|
{subtitle}
|
|
</Typography>
|
|
)}
|
|
</Box>
|
|
{actions && <Box sx={headerActionsSx}>{actions}</Box>}
|
|
</Box>
|
|
);
|
|
}
|