Skip to content

Commit

Permalink
Open all external links in a new tab (#870)
Browse files Browse the repository at this point in the history
Closes #873
  • Loading branch information
j08lue authored Apr 2, 2024
2 parents 5d2e318 + 58c89ec commit 9412b06
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 11 deletions.
8 changes: 4 additions & 4 deletions app/scripts/components/common/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { variableBaseType, variableGlsp } from '$styles/variable-utils';
import { ElementInteractive } from '$components/common/element-interactive';
import { VarHeading } from '$styles/variable-components';
import { Figure } from '$components/common/figure';
import { getLinkProps } from '$utils/url';

type CardType = 'classic' | 'cover' | 'featured';

Expand Down Expand Up @@ -354,10 +355,9 @@ function CardComponent(props: CardComponentProps) {
onLinkClick
} = props;

const isExternalLink = linkTo.match(/^https?:\/\//);
const linkProps = isExternalLink
? { href: linkTo, onClick: onLinkClick }
: { as: Link, to: linkTo, onClick: onLinkClick };
const isExternalLink = /^https?:\/\//.test(linkTo);
const linkProps = getLinkProps(linkTo, Link, onLinkClick);


return (
<ElementInteractive
Expand Down
3 changes: 2 additions & 1 deletion app/scripts/components/common/mdx-content.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
LazyEmbed
} from '$components/common/blocks/lazy-components';
import { NotebookConnectCalloutBlock } from '$components/common/notebook-connect';
import SmartLink from '$components/common/smart-link';
import SmartLink, { CustomLink } from '$components/common/smart-link';

function MdxContent(props) {
const pageMdx = useMdxPageLoader(props.loader);
Expand All @@ -44,6 +44,7 @@ function MdxContent(props) {
CompareImage: LazyCompareImage,
NotebookConnectCallout: NotebookConnectCalloutBlock,
Link: SmartLink,
a: CustomLink,
Table: LazyTable,
Embed: LazyEmbed
}}
Expand Down
8 changes: 6 additions & 2 deletions app/scripts/components/common/page-footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { variableGlsp } from '../../styles/variable-utils';
import { Tip } from '$components/common/tip';
import { ComponentOverride } from '$components/common/page-overrides';

import SmartLink from '$components/common/smart-link';

const PageFooterSelf = styled.footer`
padding: ${variableGlsp(0.75, 1)};
background: ${themeVal('color.base-50')};
Expand Down Expand Up @@ -140,6 +142,8 @@ function PageFooter(props) {
variation='base-text'
size='small'
fitting='skinny'
target='_blank'
rel='noopener noreferrer'
>
<CollecticonBrandGithub title='Explore the code' meaningful />
GitHub
Expand All @@ -148,12 +152,12 @@ function PageFooter(props) {
</InfoList>
<FooterCredits>
<p>
<a href='https://earthdata.nasa.gov/'>
<SmartLink to='https://earthdata.nasa.gov/'>
<span>By</span> NASA <strong>Earthdata</strong> <span>on</span>{' '}
<time dateTime={nowDate.getFullYear()}>
{nowDate.getFullYear()}
</time>
</a>
</SmartLink>
{' • '}
<Tip
content={`Released on ${format(
Expand Down
28 changes: 25 additions & 3 deletions app/scripts/components/common/smart-link.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from 'react';
import { Link } from 'react-router-dom';

import { getLinkProps } from '$utils/url';

interface SmartLinkProps {
to: string;
}
Expand All @@ -10,10 +12,30 @@ interface SmartLinkProps {
*/
export default function SmartLink(props: SmartLinkProps) {
const { to, ...rest } = props;
const isExternalLink = /^https?:\/\//.test(to);
const linkProps = getLinkProps(to);
return isExternalLink ? (
<a {...linkProps} {...rest} />
) : (
<Link {...linkProps} {...rest} />
);
}


return /^https?:\/\//.test(to) ? (
<a href={to} {...rest} />
interface CustomLinkProps {
href: string;
}

/**
* For links defined as markdown, this component will open the external link in a new tab.
*/
export function CustomLink(props: CustomLinkProps) {
const { href, ...rest } = props;
const isExternalLink = /^https?:\/\//.test(href);
const linkProps = getLinkProps(href);
return isExternalLink ? (
<a {...linkProps} {...rest} />
) : (
<Link to={to} {...rest} />
<Link {...linkProps} {...rest} />
);
}
27 changes: 27 additions & 0 deletions app/scripts/utils/url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { MouseEventHandler } from 'react';
import { getBoolean } from 'veda';
import { LinkProps } from 'react-router-dom';


export const getLinkProps = (
linkTo: string,
as?: React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLAnchorElement>>,
onClick?: (() => void) | MouseEventHandler
) => {
const externalLinksInNewTab = getBoolean('externalLinksInNewTab');
const isExternalLink = /^https?:\/\//.test(linkTo);
return isExternalLink
? {
href: linkTo,
to: linkTo,
...(externalLinksInNewTab
? {target: '_blank', rel: 'noopener noreferrer'}
: {}),
...(onClick ? {onClick: onClick} : {})
}
: {
...(as ? {as: as} : {}),
to: linkTo,
...(onClick ? {onClick: onClick} : {})
};
};
3 changes: 3 additions & 0 deletions parcel-resolver-veda/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ export interface LayerInfo {
one: string;
other: string;
};

export const getBoolean: (variable: string) => boolean;

/**
* List of custom user defined pages.
*/
Expand Down
4 changes: 3 additions & 1 deletion parcel-resolver-veda/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ module.exports = new Resolver({
root,
logger
)},
strings: ${JSON.stringify(withDefaultStrings(result.strings))}
strings: ${JSON.stringify(withDefaultStrings(result.strings))},
booleans: ${JSON.stringify(withDefaultStrings(result.booleans))}
};
export const theme = ${JSON.stringify(result.theme) || null};
Expand All @@ -212,6 +213,7 @@ module.exports = new Resolver({
.filter((k) => k.startsWith('/'));
export const getString = (variable) => config.strings[variable];
export const getBoolean = (variable) => config.booleans[variable];
export const datasets = ${generateMdxDataObject(datasetsImportData)};
export const stories = ${generateMdxDataObject(storiesImportData)};
Expand Down

0 comments on commit 9412b06

Please sign in to comment.