Skip to content
This repository has been archived by the owner on Nov 4, 2024. It is now read-only.

feature/COR-1597-contact-page-improved-design #4873

Merged
merged 12 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions packages/app/src/components/contact/contact-page-group.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { space } from '~/style/theme';
import { Box } from '../base/box';
import { Heading } from '../typography';
import { ContactPageGroupItem } from './contact-page-item';
import { PageGroup } from './types';

interface ContactPageGroupProps {
groups: PageGroup[];
}

export const ContactPageGroup = ({ groups }: ContactPageGroupProps) => {
return (
<Box as="section" flexBasis="50%">
{groups.map(({ id, title, items }) => (
<div key={id}>
<Heading marginBottom={space[3]} level={2}>
{title}
</Heading>

{items.map((item, index) => (
<ContactPageGroupItem key={item.id} item={item} index={index} groupItemsLength={items.length} />
))}
</div>
))}
</Box>
);
};
51 changes: 51 additions & 0 deletions packages/app/src/components/contact/contact-page-item-links.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { colors } from '@corona-dashboard/common';
import styled from 'styled-components';
import { mediaQueries, radii, space } from '~/style/theme';
import { Box } from '../base/box';
import { Text } from '../typography';
import { ContactPageLink } from './contact-page-link';
import { ItemLink } from './types';

interface ContactPageItemLinksProps {
links: ItemLink[];
}

export const ContactPageItemLinks = ({ links }: ContactPageItemLinksProps) => {
return (
<Box display="grid" gridTemplateColumns={{ _: '1fr', sm: '1fr 1fr' }} marginTop={space[3]} spacing={{ _: 3, sm: 0 }}>
{links.map(({ id, titleAboveLink, href, label, linkType }) => (
<div key={id}>
{titleAboveLink && (
<Text fontWeight="bold" marginBottom={space[3]}>
{titleAboveLink}
</Text>
)}

<LinkListItem>
<ContactPageLink href={href} label={label} linkType={linkType} />
</LinkListItem>
</div>
))}
</Box>
);
};

const LinkListItem = styled.div`
border-radius: ${radii[1]}px;
border: 1px solid ${colors.gray3};
display: block;
padding: ${space[2]} ${space[3]};
transition: all 0.2s;

&:hover {
background-color: ${colors.blue8};

a {
color: ${colors.white};
}
}

@media ${mediaQueries.sm} {
display: inline-block;
}
`;
35 changes: 35 additions & 0 deletions packages/app/src/components/contact/contact-page-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { colors } from '@corona-dashboard/common';
import styled from 'styled-components';
import { radii, space } from '~/style/theme';
import { Box } from '../base/box';
import { RichContent } from '../cms/rich-content';
import { Heading } from '../typography';
import { ContactPageLink } from './contact-page-link';
import { ContactPageItemLinks } from './contact-page-item-links';
import { GroupItem } from './types';

interface ContactPageGroupItemProps {
groupItemsLength: number;
index: number;
item: GroupItem;
}

export const ContactPageGroupItem = ({ item, index, groupItemsLength }: ContactPageGroupItemProps) => {
const { title, titleUrl, linkType, description, links } = item;

return (
<Box border={`1px solid ${colors.gray3}`} borderRadius={radii[2]} padding={space[3]} marginBottom={index === groupItemsLength - 1 ? space[4] : space[3]}>
<Heading marginBottom={space[2]} variant="h4" level={3}>
{titleUrl ? <ContactPageLink href={titleUrl} label={title} linkType={linkType} /> : title}
</Heading>

<RichContent blocks={description} contentWrapper={RichContentWrapper} />

{links && <ContactPageItemLinks links={links} />}
</Box>
);
};

const RichContentWrapper = styled.div`
width: 100%;
`;
56 changes: 56 additions & 0 deletions packages/app/src/components/contact/contact-page-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { ChevronRight, External, Telephone } from '@corona-dashboard/icons';
import styled from 'styled-components';
import { ExternalLink } from '~/components/external-link';
import { space } from '~/style/theme';
import { formatLinkAccordingToType } from '~/utils/format-link-according-to-type';
import { isInternalUrl } from '~/utils/is-internal-url';
import { Link } from '~/utils/link';
import { LinkType } from './types';

interface ContactPageLinkProps {
href: string;
label: string;
linkType: LinkType | undefined;
}

export const ContactPageLink = ({ href, label, linkType }: ContactPageLinkProps) => {
if (isInternalUrl(href)) {
return (
<LinkWrapper iconMargin={`0 0 0 ${space[2]}`}>
<Link passHref href={formatLinkAccordingToType(href, linkType)}>
<a>
{label}
<ChevronRight />
</a>
</Link>
</LinkWrapper>
);
}

return (
<LinkWrapper iconMargin={linkType === 'phone' ? `0 ${space[2]} 0 0` : `0 0 0 ${space[2]}`}>
<ExternalLink href={formatLinkAccordingToType(href, linkType)}>
{linkType === 'phone' && <Telephone />}
{label}
{linkType !== 'phone' && <External />}
</ExternalLink>
</LinkWrapper>
);
};

interface LinkWrapperProps {
iconMargin: string;
}

const LinkWrapper = styled.div<LinkWrapperProps>`
a {
align-items: center;
display: flex;
}

svg {
height: 16px;
margin: ${({ iconMargin }) => iconMargin};
width: 16px;
}
`;
31 changes: 31 additions & 0 deletions packages/app/src/components/contact/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { RichContentBlock } from '~/types/cms';

export type LinkType = 'regular' | 'email' | 'phone';

interface Base {
title: string;
id: string;
}

export interface ItemLink {
id: string;
href: string;
label: string;
linkType: LinkType;
titleAboveLink?: string;
}

export interface GroupItem extends Base {
description: RichContentBlock[];
links?: ItemLink[];
titleUrl?: string;
linkType?: LinkType;
}

export interface PageGroup extends Base {
items: GroupItem[];
}

export interface ContactPage {
groups: PageGroup[];
}
13 changes: 12 additions & 1 deletion packages/app/src/components/typography.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import css, { CSSProperties } from '@styled-system/css';
import styled, { DefaultTheme } from 'styled-components';
import { Preset, preset } from '~/style/preset';

export interface TextProps {
interface AllMarginProps {
margin?: CSSProperties['margin'];
marginRight?: CSSProperties['marginRight'];
marginBottom?: CSSProperties['marginBottom'];
marginLeft?: CSSProperties['marginLeft'];
}

export interface TextProps extends AllMarginProps {
variant?: keyof Preset['typography'];
fontWeight?: keyof DefaultTheme['fontWeights'];
textTransform?: CSSProperties['textTransform'];
Expand Down Expand Up @@ -32,6 +39,10 @@ export const textStyle = (props: TextProps & { as?: string }) => {
...(props.textTransform ? { textTransform: props.textTransform } : undefined),
...(props.textAlign ? { textAlign: props.textAlign } : undefined),
...(props.hyphens ? { hyphens: props.hyphens } : undefined),
...(props.margin ? { margin: props.margin } : undefined),
...(props.marginRight ? { marginRight: props.marginRight } : undefined),
...(props.marginBottom ? { marginBottom: props.marginBottom } : undefined),
...(props.marginLeft ? { marginLeft: props.marginLeft } : undefined),
});
};

Expand Down
14 changes: 14 additions & 0 deletions packages/app/src/domain/layout/content-layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Box } from '~/components/base/box';
import { sizes, space } from '~/style/theme';

interface ContentLayoutProps {
children?: React.ReactNode;
}

export const ContentLayout = ({ children }: ContentLayoutProps) => {
return (
<Box margin={`${space[5]} auto`} maxWidth={`${sizes.maxWidth}px`} padding={`0 ${space[3]}`}>
{children}
</Box>
);
};
112 changes: 54 additions & 58 deletions packages/app/src/pages/contact.tsx
Original file line number Diff line number Diff line change
@@ -1,86 +1,82 @@
import css from '@styled-system/css';
import Head from 'next/head';
import styled from 'styled-components';
import { RichContent } from '~/components/cms/rich-content';
import { VisuallyHidden } from '~/components';
import { ContactPageGroup } from '~/components/contact/contact-page-group';
import { ContactPage } from '~/components/contact/types';
import { Heading } from '~/components/typography';
import { Content } from '~/domain/layout/content';
import { ContentLayout } from '~/domain/layout/content-layout';
import { Layout } from '~/domain/layout/layout';
import { useIntl } from '~/intl';
import {
createGetStaticProps,
StaticProps,
} from '~/static-props/create-get-static-props';
import {
createGetContent,
getLastGeneratedDate,
} from '~/static-props/get-data';
import { RichContentBlock } from '~/types/cms';

interface ContactData {
title: string | null;
description: RichContentBlock[] | null;
}
import { StaticProps, createGetStaticProps } from '~/static-props/create-get-static-props';
import { createGetContent, getLastGeneratedDate } from '~/static-props/get-data';
import { mediaQueries, space } from '~/style/theme';

export const getStaticProps = createGetStaticProps(
getLastGeneratedDate,
createGetContent<ContactData>((context) => {
createGetContent<ContactPage>((context) => {
const { locale } = context;

return `*[_type == 'contact']{
title,
"description": {
"_type": description._type,
"${locale}": [
...description.${locale}[]
{
...,
"asset": asset->
},
]
return `// groq
*[_type == 'contact'] {
'groups': contactPageGroups[]->{
'id': _id,
'title': title.${locale},
'items': contactPageGroupItems[]->{
'id': _id,
'title': title.${locale},
'titleUrl': itemTitleUrl,
'linkType': linkType.linkType,
'description': description.${locale},
'links': contactPageItemLinks[] {
'id': _id,
'titleAboveLink': title.${locale},
'linkType': linkType.linkType,
'label': link.title.${locale},
'href': link.href
}
}
}
}[0]
`;
}[0]`;
})
);

const Contact = (props: StaticProps<typeof getStaticProps>) => {
const { commonTexts } = useIntl();
const { content, lastGenerated } = props;
const {
content: { groups },
lastGenerated,
} = props;

const middleIndexOfGroups = Math.ceil(groups.length / 2);
const firstHalf = groups.slice(0, middleIndexOfGroups);
const secondHalf = groups.slice(middleIndexOfGroups);

return (
<Layout {...commonTexts.contact_metadata} lastGenerated={lastGenerated}>
<Head>
<link
key="dc-type"
rel="dcterms:type"
href="https://standaarden.overheid.nl/owms/terms/webpagina"
/>
<link
key="dc-type-title"
rel="dcterms:type"
href="https://standaarden.overheid.nl/owms/terms/webpagina"
title="webpagina"
/>
<link key="dc-type" rel="dcterms:type" href="https://standaarden.overheid.nl/owms/terms/webpagina" />
<link key="dc-type-title" rel="dcterms:type" href="https://standaarden.overheid.nl/owms/terms/webpagina" title="webpagina" />
</Head>

<Content>
{content.title && <Heading level={1}>{content.title}</Heading>}
{content.description && (
<RichContent
blocks={content.description}
contentWrapper={RichContentWrapper}
/>
)}
</Content>
<VisuallyHidden>
<Heading level={1}>Contact</Heading>
</VisuallyHidden>
APW26 marked this conversation as resolved.
Show resolved Hide resolved

<ContentLayout>
<ContactLayout>
<ContactPageGroup groups={firstHalf} />
<ContactPageGroup groups={secondHalf} />
</ContactLayout>
</ContentLayout>
</Layout>
);
};

const RichContentWrapper = styled.div(
css({
maxWidth: 'maxWidthText',
width: '100%',
})
);
const ContactLayout = styled.div`
@media ${mediaQueries.sm} {
display: flex;
gap: ${space[4]} ${space[5]};
}
`;

export default Contact;
Loading
Loading