mirror of
https://github.com/Unleash/unleash.git
synced 2024-10-28 19:06:12 +01:00
fix: add grid w/container query for projects (#8344)
The main goals of this are: 1. Make it so that the layout grid doesn't break on small screens 2. Fix an issue where the border of the box didn't fit the outline 3. (Bonus): make the layout of the info box depend on the **box's** size, not the screen size. To achieve those goals, this PR: 1. Switches to using a native CSS grid instead of MUI's grid component. This gives us more power over the layout in various different sizes. 2. Switches from putting borders on the boxes inside the grid, instead makes the grid container the color of the border and uses gaps to create borders. 3. If your browser supports it, it will use container queries to determine whether we should display the layout as a multi-column grid or in a single column. Container query demo (both with the same screen sizes): Sidebar closed: ![image](https://github.com/user-attachments/assets/9a7d9a78-de92-4429-bf06-8e98fbf40ed0) Sidebar open: ![image](https://github.com/user-attachments/assets/90e790ba-13db-485c-8f5e-ee60fe36dabb)
This commit is contained in:
parent
9b1d9f57d3
commit
35a73a5b8e
@ -1,6 +1,68 @@
|
||||
import { Box, Grid, styled } from '@mui/material';
|
||||
import type { Theme } from '@mui/material/styles/createTheme';
|
||||
|
||||
export const ContentGridContainer = styled('div')({
|
||||
containerType: 'inline-size',
|
||||
});
|
||||
|
||||
const ContentGrid2 = styled('article')(({ theme }) => {
|
||||
return {
|
||||
backgroundColor: theme.palette.divider,
|
||||
borderRadius: `${theme.shape.borderRadiusLarge}px`,
|
||||
overflow: 'hidden',
|
||||
border: `0.5px solid ${theme.palette.divider}`,
|
||||
gap: `2px`,
|
||||
display: 'flex',
|
||||
flexFlow: 'column nowrap',
|
||||
|
||||
'&>*': {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export const ProjectGrid = styled(ContentGrid2)(({ theme }) => ({
|
||||
'@container (min-width: 1000px)': {
|
||||
gridTemplateColumns: '1fr 1fr 1fr',
|
||||
display: 'grid',
|
||||
gridTemplateAreas: `
|
||||
"title onboarding onboarding"
|
||||
"projects box1 box2"
|
||||
". owners owners"
|
||||
`,
|
||||
},
|
||||
|
||||
'@supports not (container-type: inline-size)': {
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
gridTemplateColumns: '1fr 1fr 1fr',
|
||||
display: 'grid',
|
||||
gridTemplateAreas: `
|
||||
"title onboarding onboarding"
|
||||
"projects box1 box2"
|
||||
". owners owners"
|
||||
`,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export const SpacedGridItem2 = styled('div')(({ theme }) => ({
|
||||
padding: theme.spacing(4),
|
||||
}));
|
||||
|
||||
export const EmptyGridItem = styled('div')(({ theme }) => ({
|
||||
display: 'none',
|
||||
|
||||
'@container (min-width: 1000px)': {
|
||||
display: 'block',
|
||||
},
|
||||
|
||||
'@supports not (container-type: inline-size)': {
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
display: 'block',
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export const ContentGrid = styled(Grid)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
borderRadius: `${theme.shape.borderRadiusLarge}px`,
|
||||
|
@ -21,10 +21,12 @@ import type {
|
||||
PersonalDashboardSchemaProjectsItem,
|
||||
} from '../../openapi';
|
||||
import {
|
||||
ContentGrid,
|
||||
ContentGridContainer,
|
||||
EmptyGridItem,
|
||||
ListItemBox,
|
||||
listItemStyle,
|
||||
SpacedGridItem,
|
||||
ProjectGrid,
|
||||
SpacedGridItem2,
|
||||
} from './Grid';
|
||||
|
||||
const ActiveProjectDetails: FC<{
|
||||
@ -78,104 +80,129 @@ export const MyProjects: FC<{
|
||||
activeProjectStage === 'first-flag-created';
|
||||
|
||||
return (
|
||||
<ContentGrid container columns={{ lg: 12, md: 1 }}>
|
||||
<SpacedGridItem item lg={4} md={1}>
|
||||
<Typography variant='h3'>My projects</Typography>
|
||||
</SpacedGridItem>
|
||||
<SpacedGridItem
|
||||
item
|
||||
lg={8}
|
||||
md={1}
|
||||
sx={{ display: 'flex', justifyContent: 'flex-end' }}
|
||||
>
|
||||
{setupIncomplete ? (
|
||||
<Badge color='warning'>Setup incomplete</Badge>
|
||||
) : null}
|
||||
</SpacedGridItem>
|
||||
<SpacedGridItem item lg={4} md={1}>
|
||||
<List
|
||||
disablePadding={true}
|
||||
sx={{ maxHeight: '400px', overflow: 'auto' }}
|
||||
<ContentGridContainer>
|
||||
<ProjectGrid>
|
||||
<SpacedGridItem2
|
||||
sx={{
|
||||
gridArea: 'title',
|
||||
}}
|
||||
>
|
||||
{projects.map((project) => {
|
||||
return (
|
||||
<ListItem
|
||||
key={project.id}
|
||||
disablePadding={true}
|
||||
sx={{ mb: 1 }}
|
||||
>
|
||||
<ListItemButton
|
||||
sx={listItemStyle}
|
||||
selected={project.id === activeProject}
|
||||
onClick={() => setActiveProject(project.id)}
|
||||
<Typography variant='h3'>My projects</Typography>
|
||||
</SpacedGridItem2>
|
||||
<SpacedGridItem2
|
||||
sx={{
|
||||
gridArea: 'onboarding',
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
}}
|
||||
>
|
||||
{setupIncomplete ? (
|
||||
<Badge color='warning'>Setup incomplete</Badge>
|
||||
) : null}
|
||||
</SpacedGridItem2>
|
||||
<SpacedGridItem2
|
||||
sx={{
|
||||
gridArea: 'projects',
|
||||
}}
|
||||
>
|
||||
<List
|
||||
disablePadding={true}
|
||||
sx={{ maxHeight: '400px', overflow: 'auto' }}
|
||||
>
|
||||
{projects.map((project) => {
|
||||
return (
|
||||
<ListItem
|
||||
key={project.id}
|
||||
disablePadding={true}
|
||||
sx={{ mb: 1 }}
|
||||
>
|
||||
<ListItemBox>
|
||||
<ProjectIcon color='primary' />
|
||||
<StyledCardTitle>
|
||||
{project.name}
|
||||
</StyledCardTitle>
|
||||
<IconButton
|
||||
component={Link}
|
||||
href={`projects/${project.id}`}
|
||||
size='small'
|
||||
sx={{ ml: 'auto' }}
|
||||
>
|
||||
<LinkIcon
|
||||
titleAccess={`projects/${project.id}`}
|
||||
<ListItemButton
|
||||
sx={listItemStyle}
|
||||
selected={project.id === activeProject}
|
||||
onClick={() =>
|
||||
setActiveProject(project.id)
|
||||
}
|
||||
>
|
||||
<ListItemBox>
|
||||
<ProjectIcon color='primary' />
|
||||
<StyledCardTitle>
|
||||
{project.name}
|
||||
</StyledCardTitle>
|
||||
<IconButton
|
||||
component={Link}
|
||||
href={`projects/${project.id}`}
|
||||
size='small'
|
||||
sx={{ ml: 'auto' }}
|
||||
>
|
||||
<LinkIcon
|
||||
titleAccess={`projects/${project.id}`}
|
||||
/>
|
||||
</IconButton>
|
||||
</ListItemBox>
|
||||
{project.id === activeProject ? (
|
||||
<ActiveProjectDetails
|
||||
project={project}
|
||||
/>
|
||||
</IconButton>
|
||||
</ListItemBox>
|
||||
{project.id === activeProject ? (
|
||||
<ActiveProjectDetails
|
||||
project={project}
|
||||
/>
|
||||
) : null}
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
</SpacedGridItem>
|
||||
<SpacedGridItem item lg={4} md={1}>
|
||||
{activeProjectStage === 'onboarded' &&
|
||||
personalDashboardProjectDetails ? (
|
||||
<ProjectSetupComplete
|
||||
project={activeProject}
|
||||
insights={personalDashboardProjectDetails.insights}
|
||||
/>
|
||||
) : null}
|
||||
{activeProjectStage === 'onboarding-started' ||
|
||||
activeProjectStage === 'loading' ? (
|
||||
<CreateFlag project={activeProject} />
|
||||
) : null}
|
||||
{activeProjectStage === 'first-flag-created' ? (
|
||||
<ExistingFlag project={activeProject} />
|
||||
) : null}
|
||||
</SpacedGridItem>
|
||||
<SpacedGridItem item lg={4} md={1} sx={{ pr: 4 }}>
|
||||
{activeProjectStage === 'onboarded' &&
|
||||
personalDashboardProjectDetails ? (
|
||||
<LatestProjectEvents
|
||||
latestEvents={
|
||||
personalDashboardProjectDetails.latestEvents
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{setupIncomplete || activeProjectStage === 'loading' ? (
|
||||
<ConnectSDK project={activeProject} />
|
||||
) : null}
|
||||
</SpacedGridItem>
|
||||
<SpacedGridItem item lg={4} md={1} />
|
||||
<SpacedGridItem item lg={8} md={1}>
|
||||
{personalDashboardProjectDetails ? (
|
||||
<RoleAndOwnerInfo
|
||||
roles={personalDashboardProjectDetails.roles.map(
|
||||
(role) => role.name,
|
||||
)}
|
||||
owners={personalDashboardProjectDetails.owners}
|
||||
/>
|
||||
) : null}
|
||||
</SpacedGridItem>
|
||||
</ContentGrid>
|
||||
) : null}
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
</SpacedGridItem2>
|
||||
<SpacedGridItem2
|
||||
sx={{
|
||||
gridArea: 'box1',
|
||||
}}
|
||||
>
|
||||
{activeProjectStage === 'onboarded' &&
|
||||
personalDashboardProjectDetails ? (
|
||||
<ProjectSetupComplete
|
||||
project={activeProject}
|
||||
insights={personalDashboardProjectDetails.insights}
|
||||
/>
|
||||
) : null}
|
||||
{activeProjectStage === 'onboarding-started' ||
|
||||
activeProjectStage === 'loading' ? (
|
||||
<CreateFlag project={activeProject} />
|
||||
) : null}
|
||||
{activeProjectStage === 'first-flag-created' ? (
|
||||
<ExistingFlag project={activeProject} />
|
||||
) : null}
|
||||
</SpacedGridItem2>
|
||||
<SpacedGridItem2
|
||||
sx={{
|
||||
gridArea: 'box2',
|
||||
}}
|
||||
>
|
||||
{activeProjectStage === 'onboarded' &&
|
||||
personalDashboardProjectDetails ? (
|
||||
<LatestProjectEvents
|
||||
latestEvents={
|
||||
personalDashboardProjectDetails.latestEvents
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{setupIncomplete || activeProjectStage === 'loading' ? (
|
||||
<ConnectSDK project={activeProject} />
|
||||
) : null}
|
||||
</SpacedGridItem2>
|
||||
<EmptyGridItem />
|
||||
<SpacedGridItem2
|
||||
sx={{
|
||||
gridArea: 'owners',
|
||||
}}
|
||||
>
|
||||
{personalDashboardProjectDetails ? (
|
||||
<RoleAndOwnerInfo
|
||||
roles={personalDashboardProjectDetails.roles.map(
|
||||
(role) => role.name,
|
||||
)}
|
||||
owners={personalDashboardProjectDetails.owners}
|
||||
/>
|
||||
) : null}
|
||||
</SpacedGridItem2>
|
||||
</ProjectGrid>
|
||||
</ContentGridContainer>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user