1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-22 01:16:07 +02:00

Projects archive UI (#7842)

Closes
[issue/1-2666](https://linear.app/unleash/issue/1-2666/archived-projects-view)
This commit is contained in:
Tymoteusz Czech 2024-08-13 14:33:11 +02:00 committed by GitHub
parent 3c45a4b2a9
commit f2b7e0278d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 437 additions and 77 deletions

View File

@ -32,7 +32,7 @@ const BreadcrumbNav = () => {
const { isAdmin } = useContext(AccessContext); const { isAdmin } = useContext(AccessContext);
const location = useLocation(); const location = useLocation();
const paths = location.pathname let paths = location.pathname
.split('/') .split('/')
.filter((item) => item) .filter((item) => item)
.filter( .filter(
@ -55,9 +55,15 @@ const BreadcrumbNav = () => {
.map(decodeURI); .map(decodeURI);
if (location.pathname === '/insights') { if (location.pathname === '/insights') {
// Because of sticky header in Insights
return null; return null;
} }
if (paths.length === 1 && paths[0] === 'projects-archive') {
// It's not possible to use `projects/archive`, because it's :projectId path
paths = ['projects', 'archive'];
}
return ( return (
<StyledBreadcrumbContainer> <StyledBreadcrumbContainer>
<ConditionallyRender <ConditionallyRender

View File

@ -1,6 +1,7 @@
import type { ComponentProps, FC } from 'react';
import { SvgIcon } from '@mui/material'; import { SvgIcon } from '@mui/material';
import { ReactComponent as Svg } from 'assets/icons/projectIconSmall.svg'; import { ReactComponent as Svg } from 'assets/icons/projectIconSmall.svg';
export const ProjectIcon = () => ( export const ProjectIcon: FC<ComponentProps<typeof SvgIcon>> = ({
<SvgIcon component={Svg} viewBox={'0 0 14 10'} /> ...props
); }) => <SvgIcon component={Svg} viewBox={'0 0 14 10'} {...props} />;

View File

@ -98,6 +98,13 @@ exports[`returns all baseRoutes 1`] = `
"title": "Projects", "title": "Projects",
"type": "protected", "type": "protected",
}, },
{
"component": [Function],
"menu": {},
"path": "/projects-archive",
"title": "Projects archive",
"type": "protected",
},
{ {
"component": [Function], "component": [Function],
"menu": { "menu": {

View File

@ -9,6 +9,7 @@ import { NewUser } from 'component/user/NewUser/NewUser';
import ResetPassword from 'component/user/ResetPassword/ResetPassword'; import ResetPassword from 'component/user/ResetPassword/ResetPassword';
import ForgottenPassword from 'component/user/ForgottenPassword/ForgottenPassword'; import ForgottenPassword from 'component/user/ForgottenPassword/ForgottenPassword';
import { ProjectListNew } from 'component/project/ProjectList/ProjectList'; import { ProjectListNew } from 'component/project/ProjectList/ProjectList';
import { ArchiveProjectList } from 'component/project/ProjectList/ArchiveProjectList';
import RedirectArchive from 'component/archive/RedirectArchive'; import RedirectArchive from 'component/archive/RedirectArchive';
import CreateEnvironment from 'component/environments/CreateEnvironment/CreateEnvironment'; import CreateEnvironment from 'component/environments/CreateEnvironment/CreateEnvironment';
import EditEnvironment from 'component/environments/EditEnvironment/EditEnvironment'; import EditEnvironment from 'component/environments/EditEnvironment/EditEnvironment';
@ -125,6 +126,13 @@ export const routes: IRoute[] = [
type: 'protected', type: 'protected',
menu: { mobile: true }, menu: { mobile: true },
}, },
{
path: '/projects-archive',
title: 'Projects archive',
component: ArchiveProjectList,
type: 'protected',
menu: {},
},
// Features // Features
{ {

View File

@ -4,7 +4,8 @@ import Delete from '@mui/icons-material/Delete';
import Edit from '@mui/icons-material/Edit'; import Edit from '@mui/icons-material/Edit';
import { flexRow } from 'themes/themeStyles'; import { flexRow } from 'themes/themeStyles';
export const StyledProjectCard = styled(Card)(({ theme }) => ({ export const StyledProjectCard = styled(Card)<{ disabled?: boolean }>(
({ theme, disabled = false }) => ({
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
justifyContent: 'space-between', justifyContent: 'space-between',
@ -14,12 +15,16 @@ export const StyledProjectCard = styled(Card)(({ theme }) => ({
[theme.breakpoints.down('sm')]: { [theme.breakpoints.down('sm')]: {
justifyContent: 'center', justifyContent: 'center',
}, },
'&:hover': {
transition: 'background-color 0.2s ease-in-out', transition: 'background-color 0.2s ease-in-out',
backgroundColor: disabled
? theme.palette.neutral.light
: theme.palette.background.default,
'&:hover': {
backgroundColor: theme.palette.neutral.light, backgroundColor: theme.palette.neutral.light,
}, },
borderRadius: theme.shape.borderRadiusMedium, borderRadius: theme.shape.borderRadiusMedium,
})); }),
);
export const StyledProjectCardBody = styled(Box)(({ theme }) => ({ export const StyledProjectCardBody = styled(Box)(({ theme }) => ({
padding: theme.spacing(1, 2, 2, 2), padding: theme.spacing(1, 2, 2, 2),
@ -72,11 +77,13 @@ export const StyledDivInfo = styled('div')(({ theme }) => ({
padding: theme.spacing(0, 1), padding: theme.spacing(0, 1),
})); }));
export const StyledParagraphInfo = styled('p')(({ theme }) => ({ export const StyledParagraphInfo = styled('p')<{ disabled?: boolean }>(
color: theme.palette.primary.dark, ({ theme, disabled = false }) => ({
fontWeight: 'bold', color: disabled ? 'inherit' : theme.palette.primary.dark,
fontWeight: disabled ? 'normal' : 'bold',
fontSize: theme.typography.body1.fontSize, fontSize: theme.typography.body1.fontSize,
})); }),
);
export const StyledIconBox = styled(Box)(({ theme }) => ({ export const StyledIconBox = styled(Box)(({ theme }) => ({
display: 'grid', display: 'grid',
@ -87,3 +94,8 @@ export const StyledIconBox = styled(Box)(({ theme }) => ({
color: theme.palette.primary.main, color: theme.palette.primary.main,
height: '100%', height: '100%',
})); }));
export const StyledActions = styled(Box)(({ theme }) => ({
display: 'flex',
marginRight: theme.spacing(2),
}));

View File

@ -20,7 +20,7 @@ interface IProjectCardProps {
name: string; name: string;
featureCount: number; featureCount: number;
health: number; health: number;
memberCount: number; memberCount?: number;
id: string; id: string;
onHover: () => void; onHover: () => void;
isFavorite?: boolean; isFavorite?: boolean;
@ -32,7 +32,7 @@ export const ProjectCard = ({
name, name,
featureCount, featureCount,
health, health,
memberCount, memberCount = 0,
onHover, onHover,
id, id,
mode, mode,

View File

@ -0,0 +1,140 @@
import type { FC } from 'react';
import {
StyledProjectCard,
StyledDivHeader,
StyledBox,
StyledCardTitle,
StyledDivInfo,
StyledParagraphInfo,
StyledProjectCardBody,
StyledIconBox,
StyledActions,
} from './NewProjectCard.styles';
import { ProjectCardFooter } from './ProjectCardFooter/ProjectCardFooter';
import { ProjectModeBadge } from './ProjectModeBadge/ProjectModeBadge';
import { ProjectOwners } from './ProjectOwners/ProjectOwners';
import type { ProjectSchemaOwners } from 'openapi';
import { ProjectIcon } from 'component/common/ProjectIcon/ProjectIcon';
import { formatDateYMDHM } from 'utils/formatDate';
import { useLocationSettings } from 'hooks/useLocationSettings';
import { parseISO } from 'date-fns';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import TimeAgo from 'react-timeago';
import { Box, Link, Tooltip } from '@mui/material';
import { Link as RouterLink } from 'react-router-dom';
import {
CREATE_PROJECT,
DELETE_PROJECT,
} from 'component/providers/AccessProvider/permissions';
import Undo from '@mui/icons-material/Undo';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
import Delete from '@mui/icons-material/Delete';
interface IProjectArchiveCardProps {
id: string;
name: string;
createdAt?: string;
archivedAt?: string;
featureCount: number;
onRevive: () => void;
onDelete: () => void;
mode: string;
owners?: ProjectSchemaOwners;
}
export const ProjectArchiveCard: FC<IProjectArchiveCardProps> = ({
id,
name,
archivedAt,
featureCount = 0,
onRevive,
onDelete,
mode,
owners,
}) => {
const { locationSettings } = useLocationSettings();
const Actions: FC<{
id: string;
}> = ({ id }) => (
<StyledActions>
<PermissionIconButton
onClick={onRevive}
projectId={id}
permission={CREATE_PROJECT}
tooltipProps={{ title: 'Restore project' }}
data-testid={`revive-feature-flag-button`}
>
<Undo />
</PermissionIconButton>
<PermissionIconButton
permission={DELETE_PROJECT}
projectId={id}
tooltipProps={{ title: 'Permanently delete project' }}
onClick={onDelete}
>
<Delete />
</PermissionIconButton>
</StyledActions>
);
return (
<StyledProjectCard disabled>
<StyledProjectCardBody>
<StyledDivHeader>
<StyledIconBox>
<ProjectIcon color='action' />
</StyledIconBox>
<StyledBox data-loading>
<StyledCardTitle>{name}</StyledCardTitle>
</StyledBox>
<ProjectModeBadge mode={mode} />
</StyledDivHeader>
<StyledDivInfo>
<Link
component={RouterLink}
to={`/archive?search=project%3A${encodeURI(id)}`}
>
<StyledParagraphInfo disabled data-loading>
{featureCount}
</StyledParagraphInfo>
<p data-loading>
archived {featureCount === 1 ? 'flag' : 'flags'}
</p>
</Link>
<ConditionallyRender
condition={Boolean(archivedAt)}
show={
<Tooltip
title={formatDateYMDHM(
parseISO(archivedAt as string),
locationSettings.locale,
)}
arrow
>
<Box
sx={(theme) => ({
color: theme.palette.text.secondary,
})}
>
<StyledParagraphInfo disabled data-loading>
Archived
</StyledParagraphInfo>
<p data-loading>
<TimeAgo
date={
new Date(archivedAt as string)
}
/>
</p>
</Box>
</Tooltip>
}
/>
</StyledDivInfo>
</StyledProjectCardBody>
<ProjectCardFooter id={id} Actions={Actions} disabled>
<ProjectOwners owners={owners} />
</ProjectCardFooter>
</StyledProjectCard>
);
};

View File

@ -10,26 +10,36 @@ interface IProjectCardFooterProps {
id: string; id: string;
isFavorite?: boolean; isFavorite?: boolean;
children?: React.ReactNode; children?: React.ReactNode;
Actions?: FC<{ id: string; isFavorite?: boolean }>;
disabled?: boolean;
} }
const StyledFooter = styled(Box)(({ theme }) => ({ const StyledFooter = styled(Box)<{ disabled: boolean }>(
display: 'grid', ({ theme, disabled }) => ({
gridTemplateColumns: 'auto 1fr auto', display: 'flex',
alignItems: 'center', background: disabled
padding: theme.spacing(1.5, 3, 2.5, 3), ? theme.palette.background.paper
background: theme.palette.envAccordion.expanded, : theme.palette.envAccordion.expanded,
boxShadow: theme.boxShadows.accordionFooter, boxShadow: theme.boxShadows.accordionFooter,
alignItems: 'center',
justifyContent: 'space-between',
borderTop: `1px solid ${theme.palette.divider}`,
}),
);
const StyledContainer = styled(Box)(({ theme }) => ({
padding: theme.spacing(1.5, 0, 2.5, 3),
display: 'flex',
alignItems: 'center',
})); }));
const StyledFavoriteIconButton = styled(FavoriteIconButton)(({ theme }) => ({ const StyledFavoriteIconButton = styled(FavoriteIconButton)(({ theme }) => ({
marginRight: theme.spacing(-1), margin: theme.spacing(1, 2, 0, 0),
marginBottom: theme.spacing(-1),
})); }));
export const ProjectCardFooter: FC<IProjectCardFooterProps> = ({ const FavoriteAction: FC<{ id: string; isFavorite?: boolean }> = ({
children,
id, id,
isFavorite = false, isFavorite,
}) => { }) => {
const { setToastApiError } = useToast(); const { setToastApiError } = useToast();
const { favorite, unfavorite } = useFavoriteProjectsApi(); const { favorite, unfavorite } = useFavoriteProjectsApi();
@ -48,14 +58,27 @@ export const ProjectCardFooter: FC<IProjectCardFooterProps> = ({
setToastApiError('Something went wrong, could not update favorite'); setToastApiError('Something went wrong, could not update favorite');
} }
}; };
return ( return (
<StyledFooter>
{children}
<StyledFavoriteIconButton <StyledFavoriteIconButton
onClick={onFavorite} onClick={onFavorite}
isFavorite={isFavorite} isFavorite={Boolean(isFavorite)}
size='medium' size='medium'
/> />
);
};
export const ProjectCardFooter: FC<IProjectCardFooterProps> = ({
children,
id,
isFavorite = false,
Actions = FavoriteAction,
disabled = false,
}) => {
return (
<StyledFooter disabled={disabled}>
<StyledContainer>{children}</StyledContainer>
<Actions id={id} isFavorite={isFavorite} />
</StyledFooter> </StyledFooter>
); );
}; };

View File

@ -1,4 +1,4 @@
import type { VFC } from 'react'; import type { FC } from 'react';
import LockIcon from '@mui/icons-material/Lock'; import LockIcon from '@mui/icons-material/Lock';
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip'; import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
@ -8,7 +8,7 @@ interface IProjectModeBadgeProps {
mode: 'private' | 'protected' | 'public' | string; mode: 'private' | 'protected' | 'public' | string;
} }
export const ProjectModeBadge: VFC<IProjectModeBadgeProps> = ({ mode }) => { export const ProjectModeBadge: FC<IProjectModeBadgeProps> = ({ mode }) => {
if (mode === 'private') { if (mode === 'private') {
return ( return (
<HtmlTooltip <HtmlTooltip

View File

@ -0,0 +1,99 @@
import { type FC, useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import useProjectsArchive from 'hooks/api/getters/useProjectsArchive/useProjectsArchive';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { PageContent } from 'component/common/PageContent/PageContent';
import { PageHeader } from 'component/common/PageHeader/PageHeader';
import ApiError from 'component/common/ApiError/ApiError';
import { styled, useMediaQuery } from '@mui/material';
import theme from 'themes/theme';
import { Search } from 'component/common/Search/Search';
import { ProjectGroup } from './ProjectGroup';
import { ProjectArchiveCard } from '../NewProjectCard/ProjectArchiveCard';
const StyledApiError = styled(ApiError)(({ theme }) => ({
maxWidth: '500px',
marginBottom: theme.spacing(2),
}));
const StyledContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(4),
}));
type PageQueryType = Partial<Record<'search', string>>;
export const ArchiveProjectList: FC = () => {
const { projects, loading, error, refetch } = useProjectsArchive();
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
const [searchParams, setSearchParams] = useSearchParams();
const [searchValue, setSearchValue] = useState(
searchParams.get('search') || '',
);
useEffect(() => {
const tableState: PageQueryType = {};
if (searchValue) {
tableState.search = searchValue;
}
setSearchParams(tableState, {
replace: true,
});
}, [searchValue, setSearchParams]);
return (
<PageContent
isLoading={loading}
header={
<PageHeader
title={`Projects archive (${projects.length || 0})`}
actions={
<ConditionallyRender
condition={!isSmallScreen}
show={
<Search
initialValue={searchValue}
onChange={setSearchValue}
/>
}
/>
}
>
<ConditionallyRender
condition={isSmallScreen}
show={
<Search
initialValue={searchValue}
onChange={setSearchValue}
/>
}
/>
</PageHeader>
}
>
<StyledContainer>
<ConditionallyRender
condition={error}
show={() => (
<StyledApiError
onClick={refetch}
text='Error fetching projects'
/>
)}
/>
<ProjectGroup
loading={loading}
searchValue={searchValue}
projects={projects}
placeholder='No archived projects found'
ProjectCardComponent={ProjectArchiveCard}
link={false}
/>
</StyledContainer>
</PageContent>
);
};

View File

@ -1,3 +1,4 @@
import type { ComponentType } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { ProjectCard } from '../NewProjectCard/NewProjectCard'; import { ProjectCard } from '../NewProjectCard/NewProjectCard';
@ -23,12 +24,25 @@ const StyledCardLink = styled(Link)(({ theme }) => ({
pointer: 'cursor', pointer: 'cursor',
})); }));
export const ProjectGroup: React.FC<{ type ProjectGroupProps<T extends { id: string } = IProjectCard> = {
sectionTitle?: string; sectionTitle?: string;
projects: IProjectCard[]; projects: T[];
loading: boolean; loading: boolean;
searchValue: string; searchValue: string;
}> = ({ sectionTitle, projects, loading, searchValue }) => { placeholder?: string;
ProjectCardComponent?: ComponentType<T & any>;
link?: boolean;
};
export const ProjectGroup = <T extends { id: string }>({
sectionTitle,
projects,
loading,
searchValue,
placeholder = 'No projects available.',
ProjectCardComponent = ProjectCard,
link = true,
}: ProjectGroupProps<T>) => {
return ( return (
<article> <article>
<ConditionallyRender <ConditionallyRender
@ -56,9 +70,7 @@ export const ProjectGroup: React.FC<{
</TablePlaceholder> </TablePlaceholder>
} }
elseShow={ elseShow={
<TablePlaceholder> <TablePlaceholder>{placeholder}</TablePlaceholder>
No projects available.
</TablePlaceholder>
} }
/> />
} }
@ -87,28 +99,24 @@ export const ProjectGroup: React.FC<{
)} )}
elseShow={() => ( elseShow={() => (
<> <>
{projects.map((project: IProjectCard) => ( {projects.map((project: T) =>
link ? (
<StyledCardLink <StyledCardLink
key={project.id} key={project.id}
to={`/projects/${project.id}`} to={`/projects/${project.id}`}
> >
<ProjectCard <ProjectCardComponent
onHover={() => {}} onHover={() => {}}
name={project.name} {...project}
mode={project.mode}
memberCount={
project.memberCount ?? 0
}
health={project.health}
id={project.id}
featureCount={
project.featureCount
}
isFavorite={project.favorite}
owners={project.owners}
/> />
</StyledCardLink> </StyledCardLink>
))} ) : (
<ProjectCardComponent
onHover={() => {}}
{...project}
/>
),
)}
</> </>
)} )}
/> />

View File

@ -11,7 +11,8 @@ import { CREATE_PROJECT } from 'component/providers/AccessProvider/permissions';
import Add from '@mui/icons-material/Add'; import Add from '@mui/icons-material/Add';
import ApiError from 'component/common/ApiError/ApiError'; import ApiError from 'component/common/ApiError/ApiError';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { styled, useMediaQuery } from '@mui/material'; import { Link, styled, useMediaQuery } from '@mui/material';
import { Link as RouterLink } from 'react-router-dom';
import theme from 'themes/theme'; import theme from 'themes/theme';
import { Search } from 'component/common/Search/Search'; import { Search } from 'component/common/Search/Search';
import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature'; import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature';
@ -24,6 +25,7 @@ import { useProfile } from 'hooks/api/getters/useProfile/useProfile';
import { groupProjects } from './group-projects'; import { groupProjects } from './group-projects';
import { ProjectGroup } from './ProjectGroup'; import { ProjectGroup } from './ProjectGroup';
import { CreateProjectDialog } from '../Project/CreateProject/NewCreateProjectForm/CreateProjectDialog'; import { CreateProjectDialog } from '../Project/CreateProject/NewCreateProjectForm/CreateProjectDialog';
import { useUiFlag } from 'hooks/useUiFlag';
const StyledApiError = styled(ApiError)(({ theme }) => ({ const StyledApiError = styled(ApiError)(({ theme }) => ({
maxWidth: '500px', maxWidth: '500px',
@ -38,10 +40,6 @@ const StyledContainer = styled('div')(({ theme }) => ({
type PageQueryType = Partial<Record<'search', string>>; type PageQueryType = Partial<Record<'search', string>>;
type projectMap = {
[index: string]: boolean;
};
interface ICreateButtonData { interface ICreateButtonData {
disabled: boolean; disabled: boolean;
tooltip?: Omit<ITooltipResolverProps, 'children'>; tooltip?: Omit<ITooltipResolverProps, 'children'>;
@ -128,6 +126,7 @@ export const ProjectListNew = () => {
const [searchValue, setSearchValue] = useState( const [searchValue, setSearchValue] = useState(
searchParams.get('search') || '', searchParams.get('search') || '',
); );
const archiveProjectsEnabled = useUiFlag('archiveProjects');
const myProjects = new Set(useProfile().profile?.projects || []); const myProjects = new Set(useProfile().profile?.projects || []);
@ -201,6 +200,21 @@ export const ProjectListNew = () => {
</> </>
} }
/> />
<ConditionallyRender
condition={Boolean(archiveProjectsEnabled)}
show={
<>
<Link
component={RouterLink}
to='/projects-archive'
>
Archived projects
</Link>
<PageHeader.Divider />
</>
}
/>
<ProjectCreationButton /> <ProjectCreationButton />
</> </>
} }

View File

@ -0,0 +1,39 @@
import type { ProjectSchema } from 'openapi';
// FIXME: import tpye
interface IProjectArchiveCard {
name: string;
id: string;
createdAt: string;
archivedAt: string;
description: string;
featureCount: number;
owners?: ProjectSchema['owners'];
}
// TODO: implement data fetching
const useProjectsArchive = () => {
return {
projects: [
{
name: 'Archived something',
id: 'archi',
createdAt: new Date('2024-08-10 16:06').toISOString(),
archivedAt: new Date('2024-08-12 17:07').toISOString(),
owners: [{ ownerType: 'system' }],
},
{
name: 'Second example',
id: 'pid',
createdAt: new Date('2024-08-10 16:06').toISOString(),
archivedAt: new Date('2024-08-12 17:07').toISOString(),
owners: [{ ownerType: 'system' }],
},
],
error: undefined as any,
loading: false,
refetch: () => {},
};
};
export default useProjectsArchive;

View File

@ -29,6 +29,7 @@ const theme = {
primaryHeader: '0px 8px 24px rgba(97, 91, 194, 0.2)', primaryHeader: '0px 8px 24px rgba(97, 91, 194, 0.2)',
separator: '0px 2px 4px rgba(32, 32, 33, 0.12)', // Notifications header separator: '0px 2px 4px rgba(32, 32, 33, 0.12)', // Notifications header
accordionFooter: 'inset 0px 2px 4px rgba(32, 32, 33, 0.05)', accordionFooter: 'inset 0px 2px 4px rgba(32, 32, 33, 0.05)',
reverseFooter: 'inset 0px -2px 4px rgba(32, 32, 33, 0.05)',
}, },
typography: { typography: {
fontFamily: 'Sen, Roboto, sans-serif', fontFamily: 'Sen, Roboto, sans-serif',

View File

@ -21,6 +21,7 @@ export const theme = {
primaryHeader: '0px 8px 24px rgba(97, 91, 194, 0.2)', primaryHeader: '0px 8px 24px rgba(97, 91, 194, 0.2)',
separator: '0px 2px 4px rgba(32, 32, 33, 0.12)', // Notifications header separator: '0px 2px 4px rgba(32, 32, 33, 0.12)', // Notifications header
accordionFooter: 'inset 0px 2px 4px rgba(32, 32, 33, 0.05)', accordionFooter: 'inset 0px 2px 4px rgba(32, 32, 33, 0.05)',
reverseFooter: 'inset 0px -2px 4px rgba(32, 32, 33, 0.05)',
}, },
typography: { typography: {
fontFamily: 'Sen, Roboto, sans-serif', fontFamily: 'Sen, Roboto, sans-serif',

View File

@ -35,6 +35,7 @@ declare module '@mui/material/styles' {
primaryHeader: string; primaryHeader: string;
separator: string; separator: string;
accordionFooter: string; accordionFooter: string;
reverseFooter: string;
}; };
} }