Files
dashfront/src/components/PageLayout.jsx
2026-09-22 07:59:00 +02:00

88 lines
2.4 KiB
JavaScript

import { createContext, useContext, useState, useLayoutEffect } from 'react';
import { createPortal } from 'react-dom';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import { GRID_COLUMNS } from 'dashgui/panels';
export const PageTitleRightContext = createContext(null);
export function PageTitleRight({ children }) {
const contextNode = useContext(PageTitleRightContext);
const [domNode, setDomNode] = useState(
() => (typeof document !== 'undefined' ? document.getElementById('page-title-right') : null)
);
useLayoutEffect(() => {
if (!contextNode && typeof document !== 'undefined') {
const el = document.getElementById('page-title-right');
if (el && el !== domNode) {
setDomNode(el);
}
}
}, [contextNode, domNode]);
const target = contextNode || domNode;
if (!target) return null;
return createPortal(children, target);
}
export default function PageLayout({
title,
showTitle = true,
titleAction,
titleRightAction,
titleWide = 3,
children,
}) {
const [rightNode, setRightNode] = useState(null);
return (
<PageTitleRightContext.Provider value={rightNode}>
<Box sx={{ minWidth: 0 }}>
{showTitle ? (
<Box
sx={{
display: 'grid',
gridTemplateColumns: {
xs: '1fr',
sm: 'repeat(2, 1fr)',
md: `repeat(${GRID_COLUMNS}, 1fr)`,
},
gap: 2,
mb: 2,
}}
>
<Box
sx={{
gridColumn: {
xs: '1 / -1',
sm: titleWide >= 2 ? 'span 2' : 'span 1',
md: `span ${Math.min(Math.max(titleWide, 1), GRID_COLUMNS)}`,
},
display: 'flex',
alignItems: 'center',
gap: 1.5,
minWidth: 0,
}}
>
<Typography variant="h5" sx={{ fontWeight: 700 }}>
{title}
</Typography>
{titleAction}
<Box
id="page-title-right"
ref={setRightNode}
sx={{ ml: 'auto', display: 'flex', alignItems: 'center', gap: 1 }}
>
{titleRightAction}
</Box>
</Box>
</Box>
) : null}
{children}
</Box>
</PageTitleRightContext.Provider>
);
}