1
0
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:
Thomas Heartman 2024-10-03 09:02:12 +02:00 committed by GitHub
parent 9b1d9f57d3
commit 35a73a5b8e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 187 additions and 98 deletions

View File

@ -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`,

View File

@ -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>
);
};