Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save brandonbryant12/f010ff2bccef59ebdc74e1a2c08c0b16 to your computer and use it in GitHub Desktop.

Select an option

Save brandonbryant12/f010ff2bccef59ebdc74e1a2c08c0b16 to your computer and use it in GitHub Desktop.
import React, { useState } from 'react';
import {
Box,
IconButton,
styled,
Stack,
Typography,
} from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
import CustomInfoCard, { CustomInfoCardProps } from './CustomInfoCard';
const PeruseWrapper = styled(Box)<{ expanded: boolean }>(({ theme, expanded }) => ({
position: 'relative',
cursor: !expanded ? 'pointer' : 'default',
transition: 'background-color 0.2s ease',
'&:hover': {
backgroundColor: !expanded ? theme.palette.action.hover : 'transparent',
},
'& .expand-button': {
position: 'absolute',
top: theme.spacing(2),
left: theme.spacing(2),
zIndex: 1,
backgroundColor: theme.palette.background.paper,
boxShadow: theme.shadows[1],
'&:hover': {
backgroundColor: theme.palette.background.paper,
boxShadow: theme.shadows[2],
},
},
'& .MuiCardHeader-root': {
paddingLeft: theme.spacing(9),
transition: 'padding 0.2s ease',
},
}));
interface PeruseCustomInfoCardProps extends CustomInfoCardProps {
skimContent: React.ReactNode;
}
export const PeruseCustomInfoCard: React.FC<PeruseCustomInfoCardProps> = ({
skimContent,
title,
children,
dataSources = [],
footerButtonsComponent,
menuActions = [],
...restProps
}) => {
const [expanded, setExpanded] = useState(false);
const handleToggle = () => setExpanded(!expanded);
const handleExpand = () => setExpanded(true);
return (
<PeruseWrapper
expanded={expanded}
onClick={!expanded ? handleExpand : undefined}
role={!expanded ? "button" : undefined}
tabIndex={!expanded ? 0 : undefined}
onKeyDown={!expanded ? (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleExpand();
}
} : undefined}
>
<IconButton
className="expand-button"
size="small"
aria-label={expanded ? "Collapse card" : "Expand card"}
aria-expanded={expanded}
onClick={(e) => {
e.stopPropagation();
handleToggle();
}}
>
{expanded ? <ExpandLessIcon fontSize="inherit" /> : <ExpandMoreIcon fontSize="inherit" />}
</IconButton>
<CustomInfoCard
title={title}
dataSources={expanded ? dataSources : []}
footerButtonsComponent={expanded ? footerButtonsComponent : undefined}
menuActions={expanded ? menuActions : []}
{...restProps}
>
{expanded ? (
children
) : (
<Box sx={{ px: 2, py: 1 }}>
{skimContent}
</Box>
)}
</CustomInfoCard>
</PeruseWrapper>
);
};
export interface SkimMetricProps {
label: string;
value: React.ReactNode;
color?: string;
}
export const SkimMetric: React.FC<SkimMetricProps> = ({
label,
value,
color = 'grey.800',
}) => (
<Stack
spacing={0.5}
sx={{
px: 1.5,
py: 1,
bgcolor: color,
borderRadius: 1,
minWidth: 90,
flex: 1,
}}
>
<Typography variant="caption" color="text.secondary">
{label}
</Typography>
<Typography variant="body2" fontWeight={600}>
{value}
</Typography>
</Stack>
);
// Helper component for creating skim content with consistent spacing
export const SkimContent: React.FC<{ children: React.ReactNode }> = ({ children }) => (
<Stack
direction="row"
spacing={1}
sx={{
width: '100%',
'& > *': {
flexBasis: 0,
flexGrow: 1,
}
}}
>
{children}
</Stack>
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment