diff --git a/app/scripts/components/common/card/index.tsx b/app/scripts/components/common/card/index.tsx index c9b34a2fe..3de3b603d 100644 --- a/app/scripts/components/common/card/index.tsx +++ b/app/scripts/components/common/card/index.tsx @@ -2,7 +2,6 @@ import React, { lazy, MouseEventHandler, ComponentType } from 'react'; import styled, { css } from 'styled-components'; import { format } from 'date-fns'; import { CollecticonExpandTopRight } from '@devseed-ui/collecticons'; -const SmartLink = lazy(() => import('../smart-link')); import { glsp, media, @@ -10,6 +9,7 @@ import { themeVal, listReset, } from '@devseed-ui/theme-provider'; +const SmartLink = lazy(() => import('../smart-link')); import { CardBody, CardBlank, CardHeader, CardHeadline, CardTitle, CardOverline } from './styles'; import HorizontalInfoCard, { HorizontalCardStyles } from './horizontal-info-card'; @@ -227,6 +227,7 @@ export interface LinkProperties { export interface LinkWithPathProperties extends LinkProperties { linkTo: string; + isLinkExternal?: boolean; } export interface CardComponentBaseProps { @@ -250,6 +251,7 @@ export interface CardComponentBaseProps { export interface CardComponentPropsDeprecated extends CardComponentBaseProps { linkTo: string; onLinkClick?: MouseEventHandler; + isLinkExternal?: boolean; } export interface CardComponentProps extends CardComponentBaseProps { linkProperties: LinkWithPathProperties; @@ -287,16 +289,17 @@ function CardComponent(props: CardComponentPropsType) { const { linkProperties: linkPropertiesProps } = props; linkProperties = linkPropertiesProps; } else { - const { linkTo, onLinkClick, } = props; + const { linkTo, onLinkClick, isLinkExternal } = props; linkProperties = { linkTo, onLinkClick, pathAttributeKeyName: 'to', - LinkElement: SmartLink + LinkElement: SmartLink, + isLinkExternal }; } - const isExternalLink = /^https?:\/\//.test(linkProperties.linkTo); + const isExternalLink = linkProperties.isLinkExternal ?? /^https?:\/\//.test(linkProperties.linkTo); return ( void; children?: ReactNode; } /** - * Switches between a `a` and a `Link` depending on the url. + * Switches between a `a` and a `Link` depending on the optional `isLinkExternal` prop or the url. */ export default function SmartLink(props: SmartLinkProps) { - const { to, onLinkClick, children, ...rest } = props; - const isExternalLink = /^https?:\/\//.test(to); - const linkProps = getLinkProps(to, undefined, onLinkClick); + const { to, isLinkExternal, onLinkClick, children, ...rest } = props; + const isExternalLink = isLinkExternal ?? /^https?:\/\//.test(to); + const linkProps = getLinkProps(to, isLinkExternal, undefined, onLinkClick); return isExternalLink ? ( {children} @@ -27,14 +28,15 @@ export default function SmartLink(props: SmartLinkProps) { interface CustomLinkProps { href: string; + isLinkExternal?: boolean; } /** - * For links defined as markdown, this component will open the external link in a new tab. + * For links defined as markdown, this component will open the external link in a new tab depending on the optional `isLinkExternal` prop or the url. */ export function CustomLink(props: CustomLinkProps) { - const { href, ...rest } = props; - const isExternalLink = /^https?:\/\//.test(href); + const { href, isLinkExternal, ...rest } = props; + const isExternalLink = isLinkExternal ?? /^https?:\/\//.test(href); const linkProps = getLinkProps(href); return isExternalLink ? ( diff --git a/app/scripts/components/home/featured-stories.tsx b/app/scripts/components/home/featured-stories.tsx index a8bb557a7..23d1c1f23 100644 --- a/app/scripts/components/home/featured-stories.tsx +++ b/app/scripts/components/home/featured-stories.tsx @@ -82,7 +82,8 @@ function FeaturedStories() { linkProperties={{ linkTo: `${d.asLink?.url ?? getStoryPath(d)}`, LinkElement: SmartLink, - pathAttributeKeyName: 'to' + pathAttributeKeyName: 'to', + isLinkExternal: d.isLinkExternal }} title={d.name} tagLabels={[getString('stories').one]} diff --git a/app/scripts/components/sandbox/cards/index.js b/app/scripts/components/sandbox/cards/index.js index 834473e9f..dbd59add9 100644 --- a/app/scripts/components/sandbox/cards/index.js +++ b/app/scripts/components/sandbox/cards/index.js @@ -13,6 +13,7 @@ function SandboxCards() { >, - onClick?: (() => void) | MouseEventHandler - ) => { - // Open the link in a new tab when link is external - const isExternalLink = /^https?:\/\//.test(linkTo); - return isExternalLink + linkTo: string, + isLinkExternal?: boolean, + as?: React.ForwardRefExoticComponent< + LinkProps & React.RefAttributes + >, + onClick?: (() => void) | MouseEventHandler +) => { + // Open the link in a new tab when link is external + const isExternalLink = isLinkExternal ?? /^https?:\/\//.test(linkTo); + return isExternalLink ? { href: linkTo, to: linkTo, - ...{target: '_blank', rel: 'noopener noreferrer'}, - ...(onClick ? {onClick: onClick} : {}) + ...{ target: '_blank', rel: 'noopener noreferrer' }, + ...(onClick ? { onClick: onClick } : {}) } : { - ...(as ? {as: as} : {}), + ...(as ? { as: as } : {}), to: linkTo, - ...(onClick ? {onClick: onClick} : {}) + ...(onClick ? { onClick: onClick } : {}) }; - }; +}; diff --git a/mock/stories/external-link-example.stories.mdx b/mock/stories/external-link-example.stories.mdx index 184932fd7..51a5b85d9 100644 --- a/mock/stories/external-link-example.stories.mdx +++ b/mock/stories/external-link-example.stories.mdx @@ -1,7 +1,7 @@ --- featured: true id: 'external-link-test' -name: External Link Test +name: External Link Test description: Story to test external link media: src: ::file ./img-placeholder-6.jpg @@ -24,4 +24,5 @@ related: id: air-quality-and-covid-19 asLink: url: 'https://developmentseed.org' +isLinkExternal: true --- diff --git a/parcel-resolver-veda/index.d.ts b/parcel-resolver-veda/index.d.ts index 072384819..52083c4dd 100644 --- a/parcel-resolver-veda/index.d.ts +++ b/parcel-resolver-veda/index.d.ts @@ -207,6 +207,7 @@ declare module 'veda' { taxonomy: Taxonomy[]; related?: RelatedContentData[]; asLink?: LinkContentData; + isLinkExternal?: boolean; isHidden?: boolean; } @@ -339,7 +340,9 @@ declare module 'veda' { export const getBoolean: (variable: string) => boolean; export const getBannerFromVedaConfig: () => BannerData | undefined; - export const getCookieConsentFromVedaConfig: () => CookieConsentData| undefined; + export const getCookieConsentFromVedaConfig: () => + | CookieConsentData + | undefined; export const getNavItemsFromVedaConfig: () => | {