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

feat: restructured logic for internal links #4525

Merged
14 changes: 7 additions & 7 deletions packages/app/src/components/cms/rich-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { nestedHtml } from '~/style/preset';
import { asResponsiveArray } from '~/style/utils';
import { ImageBlock, InlineAttachment, InlineCollapsibleList, InlineLink, RichContentImageBlock } from '~/types/cms';
import { assert } from '~/utils/assert';
import { isAbsoluteUrl } from '~/utils/is-absolute-url';
import { isInternalUrl } from '~/utils/is-internal-url';
import { Link } from '~/utils/link';
import { AccessibilityDefinition } from '~/utils/use-accessibility-annotations';
import { Heading } from '../typography';
Expand Down Expand Up @@ -251,17 +251,17 @@ function InlineLinkMark(props: { children: ReactNode; mark: InlineLink }) {

if (!mark.href) return <>{children}</>;

return isAbsoluteUrl(mark.href) ? (
<ExternalLink href={mark.href} underline>
{children}
<ExternalLinkIcon width={20} height={11} />
</ExternalLink>
) : (
return isInternalUrl(mark.href) ? (
<Link href={mark.href} passHref locale={locale}>
<a css={css({ textDecoration: 'underline' })}>
{children} <ChevronRight width={10} height={10} />
</a>
</Link>
) : (
<ExternalLink href={mark.href} underline>
{children}
<ExternalLinkIcon width={20} height={11} />
</ExternalLink>
);
}

Expand Down
38 changes: 5 additions & 33 deletions packages/app/src/components/content-teaser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { PublicationDate } from '~/components/publication-date';
import { Text } from '~/components/typography';
import { SiteText } from '~/locale';
import { ImageBlock } from '~/types/cms';
import { isAbsoluteUrl } from '~/utils/is-absolute-url';
import { isInternalUrl } from '~/utils/is-internal-url';
import { useBreakpoints } from '~/utils/use-breakpoints';

export interface ContentTeaserProps {
Expand All @@ -21,34 +21,14 @@ export interface ContentTeaserProps {
text: SiteText['pages']['topical_page']['shared'];
}

export function ContentTeaser({
title,
slug,
cover,
category,
publicationDate,
variant = 'normal',
isWeeklyHighlight,
isArticle,
text,
}: ContentTeaserProps) {
export function ContentTeaser({ title, slug, cover, category, publicationDate, variant = 'normal', isWeeklyHighlight, isArticle, text }: ContentTeaserProps) {
const breakpoints = useBreakpoints(true);
const imageWidth = variant === 'normal' ? (breakpoints.sm ? 186 : 90) : 90;

return (
<Box
display="flex"
spacingHorizontal={3}
width="100%"
alignItems="center"
pr={3}
>
<Box display="flex" spacingHorizontal={3} width="100%" alignItems="center" pr={3}>
<Box maxWidth={imageWidth} width="100%">
<BackgroundImage
image={cover}
height={variant === 'normal' ? (breakpoints.sm ? 108 : 66) : 66}
sizes={[[imageWidth]]}
/>
<BackgroundImage image={cover} height={variant === 'normal' ? (breakpoints.sm ? 108 : 66) : 66} sizes={[[imageWidth]]} />
</Box>
<Box maxWidth="25rem" spacing={publicationDate || category ? 2 : 0}>
<Text variant="overline2" color="gray7">
Expand All @@ -62,15 +42,7 @@ export function ContentTeaser({
)}
</Text>
<HeadingLinkWithIcon
href={
isAbsoluteUrl(slug)
? slug
: isWeeklyHighlight
? `/weekberichten/${slug}`
: isArticle
? `/artikelen/${slug}`
: slug
}
href={!isInternalUrl(slug) ? slug : isWeeklyHighlight ? `/weekberichten/${slug}` : isArticle ? `/artikelen/${slug}` : slug}
icon={<ArrowIconRight />}
iconPlacement="right"
underline
Expand Down
24 changes: 9 additions & 15 deletions packages/app/src/components/markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@ import styled from 'styled-components';
import { ExternalLink } from '~/components/external-link';
import { useIntl } from '~/intl';
import { nestedHtml } from '~/style/preset';
import { isAbsoluteUrl } from '~/utils/is-absolute-url';
import { isInternalUrl } from '~/utils/is-internal-url';
import { Link } from '~/utils/link';
import { DisplayOnMatchingQueryCode } from './display-on-matching-query-code';
import { Message } from './message';
import { Anchor } from './typography';
import {
ChevronRight,
External as ExternalLinkIcon,
} from '@corona-dashboard/icons';
import { ChevronRight, External as ExternalLinkIcon } from '@corona-dashboard/icons';

interface MarkdownProps {
content: string;
Expand All @@ -26,17 +23,17 @@ interface LinkProps {

const renderers = {
link: (props: LinkProps) =>
isAbsoluteUrl(props.href) ? (
<ExternalLink href={props.href} display="inline-block">
{props.children}
<ExternalLinkIcon width={20} height={11} />
</ExternalLink>
) : (
isInternalUrl(props.href) ? (
<Link href={props.href} passHref>
<Anchor underline display="inline-block">
{props.children} <ChevronRight width={10} height={10} />
</Anchor>
</Link>
) : (
<ExternalLink href={props.href} display="inline-block">
{props.children}
<ExternalLinkIcon width={20} height={11} />
</ExternalLink>
),
/**
* The code element is hijacked to display context-aware pieces of content.
Expand Down Expand Up @@ -67,10 +64,7 @@ const renderers = {
const hasChildBlockquote = props.node.children[0].type === 'blockquote';

return (
<Message
variant={hasChildBlockquote ? 'message' : 'warning'}
resetParentStyles={hasChildBlockquote}
>
<Message variant={hasChildBlockquote ? 'message' : 'warning'} resetParentStyles={hasChildBlockquote}>
{props.children}
</Message>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import {
ChevronRight,
External as ExternalIcon,
} from '@corona-dashboard/icons';
import { ChevronRight, External as ExternalIcon } from '@corona-dashboard/icons';
import css from '@styled-system/css';
import styled from 'styled-components';
import { Box } from '~/components/base';
Expand All @@ -11,7 +8,7 @@ import { useIntl } from '~/intl';
import { spacingStyle } from '~/style/functions/spacing';
import { space } from '~/style/theme';
import { asResponsiveArray } from '~/style/utils';
import { isAbsoluteUrl } from '~/utils/is-absolute-url';
import { isInternalUrl } from '~/utils/is-internal-url';
import { Link } from '~/utils/link';

interface pageLinksProps {
Expand All @@ -24,29 +21,24 @@ interface pageLinksProps {
export function PageLinks({ links }: pageLinksProps) {
const { commonTexts } = useIntl();

const combinedAriaLabel = (title: string) =>
`${commonTexts.informatie_header.external_link}. ${title}`;
const combinedAriaLabel = (title: string) => `${commonTexts.informatie_header.external_link}. ${title}`;

return (
<Box spacing={2} pt={3}>
<Box spacing={2} paddingTop={space[3]}>
<BoldText>{commonTexts.informatie_header.handige_links}</BoldText>
<OrderedList>
{links.map((link, index) => (
<ListItem key={index}>
{isAbsoluteUrl(link.href) ? (
<ExternalLink
href={link.href}
underline="hover"
ariaLabel={combinedAriaLabel(link.title)}
>
<TitleWithIcon title={link.title} icon={<ExternalIcon />} />
</ExternalLink>
) : (
{isInternalUrl(link.href) ? (
<Link href={link.href} passHref>
<Anchor underline="hover" ariaLabel={link.title}>
<TitleWithIcon title={link.title} icon={<ChevronRight />} />
</Anchor>
</Link>
) : (
<ExternalLink href={link.href} underline="hover" ariaLabel={combinedAriaLabel(link.title)}>
<TitleWithIcon title={link.title} icon={<ExternalIcon />} />
</ExternalLink>
)}
</ListItem>
))}
Expand Down
17 changes: 0 additions & 17 deletions packages/app/src/utils/__tests__/is-absolute-url.spec.ts

This file was deleted.

61 changes: 61 additions & 0 deletions packages/app/src/utils/__tests__/is-internal-url.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { suite } from 'uvu';
import * as assert from 'uvu/assert';
import { isInternalUrl } from '../is-internal-url';

const externalLinks = [
'',
'23498',
'//random-text',
'with spaces included',
'www.google. com',
'http://www.google.com',
'https://www.google.com',
'coronadashboard.rivm.nl',
'http://coronadashboard.rivm.nl',
'https://coronadashboard.rivm.nl',
'news-paper.nl/new-coronadashboard-is-live',
'http://news-paper.nl/new-coronadashboard-is-live',
'https://news-paper.nl/new-coronadashboard-is-live',
'www.rijksoverheid.nl/see-our-new-dashboard/?tracking="coronadashboard.rijksoverheid.nl"',
'www.rijksoverheid.nl/see-our-new-dashboard/?tracking="http://coronadashboard.rijksoverheid.nl"',
'www.rijksoverheid.nl/see-our-new-dashboard/?tracking="https://coronadashboard.rijksoverheid.nl"',
'http://www.rijksoverheid.nl/see-our-new-dashboard/?tracking="coronadashboard.riiksoverheid.nl"',
'http://www.rijksoverheid.nl/see-our-new-dashboard/?tracking="http://coronadashboard.rijksoverheid.nl"',
'http://www.rijksoverheid.nl/see-our-new-dashboard/?tracking="https://coronadashboard.rijksoverheid.nl"',
'https://www.rijksoverheid.nl/see-our-new-dashboard/?tracking="coronadashboard.rijksoverheid.nl"',
'https://www.riiksoverheid.nl/see-our-new-dashboard/?tracking="http://coronadashboard.rijksoverheid.nl"',
'https://www.rijksoverheid.nl/see-our-new-dashboard/?tracking="https://coronadashboard.rijksoverheid.nl"',
];

const internalLinksCommon = ['#anchor', '/'];

const interalLinksProd = [
'coronadashboard.nl',
'http://coronadashboard.nl',
'https://coronadashboard.nl',
'www.coronadashboard.nl',
'http://www.coronadashboard.nl',
'https://www.coronadashboard.nl',
'coronadashboard.rijksoverheid.nl',
'http://coronadashboard.rijksoverheid.nl',
'https://coronadashboard.rijksoverheid.nl',
'coronadashboard.government.nl',
'http://coronadashboard.government.nl',
'https://coronadashboard.government.nl',
];

const IsInternalUrl = suite('isInternalUrl');

IsInternalUrl('returns false for external urls', () => {
externalLinks.forEach((url) => {
assert.not.ok(isInternalUrl(url), `${url} is seen as an internal link but probably is an external url`);
});
});

IsInternalUrl('returns true for internal urls', () => {
[...internalLinksCommon, ...interalLinksProd].forEach((url) => {
assert.ok(isInternalUrl(url), `${url} is seen as an external link but probably is an internal url`);
});
});

IsInternalUrl.run();
6 changes: 0 additions & 6 deletions packages/app/src/utils/is-absolute-url.ts

This file was deleted.

11 changes: 11 additions & 0 deletions packages/app/src/utils/is-internal-url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
DariaKwork marked this conversation as resolved.
Show resolved Hide resolved
* Return true if the given url is an internal link to one of the dashboard pages.
* This counts for international links as well.
* Return false if the given link is an external link.
*/

export function isInternalUrl(url: string) {
DariaKwork marked this conversation as resolved.
Show resolved Hide resolved
const totalRegEx = new RegExp('(^(#))|(^(/)[^/]|^(/)$)|(^(((https?://(www.)?)?|www.)coronadashboard(.rijskoverheid|.government)?.nl))');
APW26 marked this conversation as resolved.
Show resolved Hide resolved

return totalRegEx.test(url);
}