@ -0,0 +1,43 @@
|
|||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { SettingsNavigationCard } from '@/settings/components/SettingsNavigationCard';
|
||||||
|
import { IconCalendarEvent, IconMailCog } from '@/ui/display/icon';
|
||||||
|
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
||||||
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
|
|
||||||
|
const StyledCardsContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
gap: ${({ theme }) => theme.spacing(4)};
|
||||||
|
margin-top: ${({ theme }) => theme.spacing(6)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const SettingsAccountsSettingsSection = () => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Section>
|
||||||
|
<H2Title
|
||||||
|
title="Settings"
|
||||||
|
description="Configure your emails and calendar settings."
|
||||||
|
/>
|
||||||
|
<StyledCardsContainer>
|
||||||
|
<SettingsNavigationCard
|
||||||
|
Icon={IconMailCog}
|
||||||
|
title="Emails"
|
||||||
|
onClick={() => navigate('/settings/accounts/emails')}
|
||||||
|
>
|
||||||
|
Set email visibility, manage your blocklist and more.
|
||||||
|
</SettingsNavigationCard>
|
||||||
|
<SettingsNavigationCard
|
||||||
|
Icon={IconCalendarEvent}
|
||||||
|
title="Calendar"
|
||||||
|
disabled
|
||||||
|
hasSoonPill
|
||||||
|
>
|
||||||
|
Configure and customize your calendar preferences.
|
||||||
|
</SettingsNavigationCard>
|
||||||
|
</StyledCardsContainer>
|
||||||
|
</Section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { IconChevronRight } from '@/ui/display/icon';
|
||||||
|
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||||
|
import { SoonPill } from '@/ui/display/pill/components/SoonPill';
|
||||||
|
import { Card } from '@/ui/layout/card/components/Card';
|
||||||
|
|
||||||
|
type SettingsNavigationCardProps = {
|
||||||
|
children: ReactNode;
|
||||||
|
disabled?: boolean;
|
||||||
|
hasSoonPill?: boolean;
|
||||||
|
Icon: IconComponent;
|
||||||
|
onClick?: () => void;
|
||||||
|
title: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const StyledCard = styled(Card)<{
|
||||||
|
disabled?: boolean;
|
||||||
|
onClick?: () => void;
|
||||||
|
}>`
|
||||||
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
|
cursor: ${({ disabled, onClick }) =>
|
||||||
|
disabled ? 'not-allowed' : onClick ? 'pointer' : 'default'};
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
|
padding-bottom: ${({ theme }) => theme.spacing(4)};
|
||||||
|
padding-top: ${({ theme }) => theme.spacing(4)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledHeader = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
gap: ${({ theme }) => theme.spacing(3)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTitle = styled.div`
|
||||||
|
color: ${({ theme }) => theme.font.color.secondary};
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 auto;
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
|
justify-content: flex-start;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledIconChevronRight = styled(IconChevronRight)`
|
||||||
|
color: ${({ theme }) => theme.font.color.light};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledDescription = styled.div`
|
||||||
|
padding-left: ${({ theme }) => theme.spacing(8)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const SettingsNavigationCard = ({
|
||||||
|
children,
|
||||||
|
disabled,
|
||||||
|
hasSoonPill,
|
||||||
|
Icon,
|
||||||
|
onClick,
|
||||||
|
title,
|
||||||
|
}: SettingsNavigationCardProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledCard disabled={disabled} onClick={onClick}>
|
||||||
|
<StyledHeader>
|
||||||
|
<Icon size={theme.icon.size.lg} stroke={theme.icon.stroke.sm} />
|
||||||
|
<StyledTitle>
|
||||||
|
{title}
|
||||||
|
{hasSoonPill && <SoonPill />}
|
||||||
|
</StyledTitle>
|
||||||
|
<StyledIconChevronRight size={theme.icon.size.sm} />
|
||||||
|
</StyledHeader>
|
||||||
|
<StyledDescription>{children}</StyledDescription>
|
||||||
|
</StyledCard>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,16 +1,16 @@
|
|||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { Card } from '@/ui/layout/card/components/Card';
|
||||||
|
|
||||||
type SettingsObjectFieldTypeCardProps = {
|
type SettingsObjectFieldTypeCardProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
preview: ReactNode;
|
preview: ReactNode;
|
||||||
form?: ReactNode;
|
form?: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledPreviewContainer = styled.div`
|
const StyledPreviewContainer = styled(Card)`
|
||||||
background-color: ${({ theme }) => theme.background.transparent.lighter};
|
background-color: ${({ theme }) => theme.background.transparent.lighter};
|
||||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
|
||||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
|
||||||
padding: ${({ theme }) => theme.spacing(4)};
|
padding: ${({ theme }) => theme.spacing(4)};
|
||||||
|
|
||||||
&:not(:last-child) {
|
&:not(:last-child) {
|
||||||
@ -32,14 +32,12 @@ const StyledPreviewContent = styled.div`
|
|||||||
gap: 6px;
|
gap: 6px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledFormContainer = styled.div`
|
const StyledFormContainer = styled(Card)`
|
||||||
background-color: ${({ theme }) => theme.background.secondary};
|
|
||||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
|
||||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const SettingsObjectFieldTypeCard = ({
|
export const SettingsObjectFieldTypeCard = ({
|
||||||
|
|||||||
@ -37,6 +37,10 @@ const StyledIconCheck = styled(IconCheck)`
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const StyledSoonPill = styled(SoonPill)`
|
||||||
|
margin-left: auto;
|
||||||
|
`;
|
||||||
|
|
||||||
type SettingsObjectTypeCardProps = {
|
type SettingsObjectTypeCardProps = {
|
||||||
prefixIcon?: React.ReactNode;
|
prefixIcon?: React.ReactNode;
|
||||||
title: string;
|
title: string;
|
||||||
@ -68,7 +72,7 @@ export const SettingsObjectTypeCard = ({
|
|||||||
>
|
>
|
||||||
{prefixIcon}
|
{prefixIcon}
|
||||||
<StyledTag color={color} text={title} />
|
<StyledTag color={color} text={title} />
|
||||||
{soon && <SoonPill />}
|
{soon && <StyledSoonPill />}
|
||||||
{!disabled && selected && <StyledIconCheck size={theme.icon.size.md} />}
|
{!disabled && selected && <StyledIconCheck size={theme.icon.size.md} />}
|
||||||
</StyledObjectTypeCard>
|
</StyledObjectTypeCard>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { Tag } from '@/ui/display/tag/components/Tag';
|
|||||||
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
||||||
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
|
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
|
||||||
import { useLazyLoadIcon } from '@/ui/input/hooks/useLazyLoadIcon';
|
import { useLazyLoadIcon } from '@/ui/input/hooks/useLazyLoadIcon';
|
||||||
|
import { Card } from '@/ui/layout/card/components/Card';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@ -22,11 +23,8 @@ type SettingsAboutSectionProps = {
|
|||||||
onEdit: () => void;
|
onEdit: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledCard = styled.div`
|
const StyledCard = styled(Card)`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: ${({ theme }) => theme.background.secondary};
|
|
||||||
border: ${({ theme }) => `1px solid ${theme.border.color.medium}`};
|
|
||||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: ${({ theme }) => theme.spacing(2)};
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
padding: ${({ theme }) => theme.spacing(2)};
|
padding: ${({ theme }) => theme.spacing(2)};
|
||||||
|
|||||||
@ -60,6 +60,7 @@ export {
|
|||||||
IconList,
|
IconList,
|
||||||
IconLogout,
|
IconLogout,
|
||||||
IconMail,
|
IconMail,
|
||||||
|
IconMailCog,
|
||||||
IconMap,
|
IconMap,
|
||||||
IconMinus,
|
IconMinus,
|
||||||
IconMoneybag,
|
IconMoneybag,
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
type SoonPillProps = {
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
const StyledSoonPill = styled.span`
|
const StyledSoonPill = styled.span`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: ${({ theme }) => theme.background.transparent.light};
|
background: ${({ theme }) => theme.background.transparent.light};
|
||||||
@ -13,8 +17,9 @@ const StyledSoonPill = styled.span`
|
|||||||
height: ${({ theme }) => theme.spacing(4)};
|
height: ${({ theme }) => theme.spacing(4)};
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
line-height: ${({ theme }) => theme.text.lineHeight.lg};
|
line-height: ${({ theme }) => theme.text.lineHeight.lg};
|
||||||
margin-left: auto;
|
|
||||||
padding: ${({ theme }) => `0 ${theme.spacing(2)}`};
|
padding: ${({ theme }) => `0 ${theme.spacing(2)}`};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const SoonPill = () => <StyledSoonPill>Soon</StyledSoonPill>;
|
export const SoonPill = ({ className }: SoonPillProps) => (
|
||||||
|
<StyledSoonPill className={className}>Soon</StyledSoonPill>
|
||||||
|
);
|
||||||
|
|||||||
@ -277,6 +277,10 @@ const StyledButton = styled.button<
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const StyledSoonPill = styled(SoonPill)`
|
||||||
|
margin-left: auto;
|
||||||
|
`;
|
||||||
|
|
||||||
export const Button = ({
|
export const Button = ({
|
||||||
className,
|
className,
|
||||||
Icon,
|
Icon,
|
||||||
@ -307,7 +311,7 @@ export const Button = ({
|
|||||||
>
|
>
|
||||||
{Icon && <Icon size={theme.icon.size.sm} />}
|
{Icon && <Icon size={theme.icon.size.sm} />}
|
||||||
{title}
|
{title}
|
||||||
{soon && <SoonPill />}
|
{soon && <StyledSoonPill />}
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
10
front/src/modules/ui/layout/card/components/Card.tsx
Normal file
10
front/src/modules/ui/layout/card/components/Card.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
const StyledCard = styled.div`
|
||||||
|
background-color: ${({ theme }) => theme.background.secondary};
|
||||||
|
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||||
|
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||||
|
padding: ${({ theme }) => theme.spacing(3)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export { StyledCard as Card };
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
|
import { Card } from '../Card';
|
||||||
|
|
||||||
|
const meta: Meta<typeof Card> = {
|
||||||
|
title: 'UI/Layout/Card/Card',
|
||||||
|
component: Card,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof Card>;
|
||||||
|
|
||||||
|
export const Default: Story = {};
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { SettingsAccountsSettingsSection } from '@/settings/accounts/components/SettingsAccountsSettingsSection';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { IconSettings } from '@/ui/display/icon';
|
import { IconSettings } from '@/ui/display/icon';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
@ -7,6 +8,7 @@ export const SettingsAccounts = () => (
|
|||||||
<SubMenuTopBarContainer Icon={IconSettings} title="Settings">
|
<SubMenuTopBarContainer Icon={IconSettings} title="Settings">
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<Breadcrumb links={[{ children: 'Accounts' }]} />
|
<Breadcrumb links={[{ children: 'Accounts' }]} />
|
||||||
|
<SettingsAccountsSettingsSection />
|
||||||
</SettingsPageContainer>
|
</SettingsPageContainer>
|
||||||
</SubMenuTopBarContainer>
|
</SubMenuTopBarContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user