diff --git a/app/scripts/components/common/card.tsx b/app/scripts/components/common/card.tsx index 85e69af2e..0d64daab9 100644 --- a/app/scripts/components/common/card.tsx +++ b/app/scripts/components/common/card.tsx @@ -2,6 +2,7 @@ import React, { MouseEventHandler, ReactNode } from 'react'; import styled, { css } from 'styled-components'; import { Link } from 'react-router-dom'; import { format } from 'date-fns'; +import { CollecticonExpandTopRight } from '@devseed-ui/collecticons'; import { VerticalDivider } from '@devseed-ui/toolbar'; import { @@ -198,11 +199,11 @@ export const CardMeta = styled.div` } } - > ${/* sc-selector */VerticalDivider}:last-child { + > ${/* sc-selector */ VerticalDivider}:last-child { display: none; } - > ${/* sc-selector */VerticalDivider}:first-child { + > ${/* sc-selector */ VerticalDivider}:first-child { display: none; } `; @@ -284,6 +285,38 @@ const CardFigure = styled(Figure)` } `; +const ExternalLinkMark = styled.div` + display: flex; + align-items: center; + position: absolute; + top: ${variableGlsp(0.25)}; + right: ${variableGlsp(0.25)}; + padding: ${variableGlsp(0.125)} ${variableGlsp(0.25)}; + background-color: ${themeVal('color.primary')}; + color: ${themeVal('color.surface')}; + text-transform: none; + border-radius: calc( + ${multiply(themeVal('shape.rounded'), 2)} - ${variableGlsp(0.125)} + ); + z-index: 1; +`; + +const FlagText = styled.div` + display: inline; + font-weight: bold; + font-size: 0.825rem; + margin-right: ${variableGlsp(0.25)}; +`; + +export function ExternalLinkFlag() { + return ( + + External Link + + + ); +} + interface CardComponentProps { title: ReactNode; linkLabel: string; @@ -319,23 +352,26 @@ function CardComponent(props: CardComponentProps) { onCardClickCapture } = props; + const isExternalLink = linkTo.match(/^https?:\/\//); + const linkProps = isExternalLink + ? { href: linkTo } + : { as: Link, to: linkTo }; + return ( {title} - {parentName && parentTo && ( + {isExternalLink && } + {!isExternalLink && parentName && parentTo && ( {parentName} diff --git a/app/scripts/components/common/featured-slider-section.tsx b/app/scripts/components/common/featured-slider-section.tsx index 4d790ae2e..6674f7c00 100644 --- a/app/scripts/components/common/featured-slider-section.tsx +++ b/app/scripts/components/common/featured-slider-section.tsx @@ -97,7 +97,7 @@ function FeaturedSliderSection(props: FeaturedSliderSectionProps) { }} cardType='featured' linkLabel='View more' - linkTo={getItemPath(d)} + linkTo={d.asLink?.url ?? getItemPath(d)} title={d.name} overline={ diff --git a/app/scripts/components/common/related-content.tsx b/app/scripts/components/common/related-content.tsx index 4c63f3b71..9a256bf48 100644 --- a/app/scripts/components/common/related-content.tsx +++ b/app/scripts/components/common/related-content.tsx @@ -7,6 +7,7 @@ import { datasets, Media, RelatedContentData, + LinkContentData, StoryData } from 'veda'; import { utcString2userTzDate } from '$utils/date'; @@ -48,6 +49,7 @@ interface FormatBlock { description: string; date: string; link: string; + asLink?: LinkContentData; parentLink: string; media: Media; parent: RelatedContentData['type']; @@ -76,6 +78,7 @@ function formatBlock({ description, date, media, + asLink, type }): FormatBlock { return { @@ -84,6 +87,7 @@ function formatBlock({ description, date, media, + asLink, ...formatUrl(id, type), parent: type }; @@ -109,6 +113,7 @@ function formatContents(relatedData: RelatedContentData[]) { id, name, description, + asLink: (matchingContent as StoryData).asLink, date: (matchingContent as StoryData).pubDate, media, type @@ -141,7 +146,7 @@ export default function RelatedContent(props: RelatedContentProps) { diff --git a/app/scripts/components/home/featured-stories.tsx b/app/scripts/components/home/featured-stories.tsx index 268389109..94400ea95 100644 --- a/app/scripts/components/home/featured-stories.tsx +++ b/app/scripts/components/home/featured-stories.tsx @@ -78,7 +78,7 @@ function FeaturedStories() {

Science communication platform

- Share your {getString('stories').other.toLocaleLowerCase()} with others through the VEDA Dashboard. - Submit a{' '} + Share your {getString('stories').other.toLocaleLowerCase()} with + others through the VEDA Dashboard. Submit a{' '} { diff --git a/app/scripts/components/stories/hub/index.tsx b/app/scripts/components/stories/hub/index.tsx index 2fb91fbaf..c5cbd5376 100644 --- a/app/scripts/components/stories/hub/index.tsx +++ b/app/scripts/components/stories/hub/index.tsx @@ -161,11 +161,11 @@ function StoriesHub() { @@ -243,7 +243,7 @@ function StoriesHub() { } linkLabel='View more' - linkTo={getStoryPath(d)} + linkTo={d.asLink?.url ?? getStoryPath(d)} title={ import('$components/common/mdx-content')); function StoriesSingle() { const story = useStory(); - if (!story) throw resourceNotFound(); + if (!story || story.data.asLink) throw resourceNotFound(); const { media, related } = story.data; @@ -45,7 +45,10 @@ function StoriesSingle() { attributionAuthor={media?.author?.name} attributionUrl={media?.author?.url} renderDetailsBlock={() => ( - + )} /> diff --git a/mock/stories/external-link-example.stories.mdx b/mock/stories/external-link-example.stories.mdx new file mode 100644 index 000000000..184932fd7 --- /dev/null +++ b/mock/stories/external-link-example.stories.mdx @@ -0,0 +1,27 @@ +--- +featured: true +id: 'external-link-test' +name: External Link Test +description: Story to test external link +media: + src: ::file ./img-placeholder-6.jpg + alt: Generic placeholder by Unsplash + author: + name: Unsplash + url: https://unsplash.com/ +pubDate: 2023-02-09 +taxonomy: + - name: Topics + values: + - Agriculture + - name: Source + values: + - Development Seed +related: + - type: dataset + id: no2 + - type: story + id: air-quality-and-covid-19 +asLink: + url: 'https://developmentseed.org' +--- diff --git a/mock/stories/internal-link-example.stories.mdx b/mock/stories/internal-link-example.stories.mdx new file mode 100644 index 000000000..c84035afd --- /dev/null +++ b/mock/stories/internal-link-example.stories.mdx @@ -0,0 +1,27 @@ +--- +featured: true +id: 'internal-link-test' +name: Internal Link Test +description: Story to test internal link. Link to cata catalog. +media: + src: ::file ./img-placeholder-6.jpg + alt: Generic placeholder by Unsplash + author: + name: Unsplash + url: https://unsplash.com/ +pubDate: 2023-02-09 +taxonomy: + - name: Topics + values: + - Agriculture + - name: Source + values: + - Development Seed +related: + - type: dataset + id: no2 + - type: story + id: air-quality-and-covid-19 +asLink: + url: '/data-catalog' +--- diff --git a/mock/stories/life-of-water.stories.mdx b/mock/stories/life-of-water.stories.mdx index 4e657dfda..db7827c6c 100644 --- a/mock/stories/life-of-water.stories.mdx +++ b/mock/stories/life-of-water.stories.mdx @@ -21,7 +21,7 @@ related: - type: dataset id: no2 - type: story - id: air-quality-and-covid-19 + id: external-link-test --- diff --git a/parcel-resolver-veda/defaults.js b/parcel-resolver-veda/defaults.js index 9299a7a2e..ca4366aef 100644 --- a/parcel-resolver-veda/defaults.js +++ b/parcel-resolver-veda/defaults.js @@ -1,11 +1,15 @@ const { defaults, mapValues } = require('lodash'); -const defaultStrings = { +const defaultStrings = ensureOneOther({ stories: { one: 'Story', other: 'Stories' - } -}; + }, + storiesBanner: + 'Explore the guided narratives below to discover how NASA satellites and other Earth observing resources reveal a changing planet.', + dataCatalogBanner: + 'This dashboard explores key indicators to track and compare changes over time.' +}); /** * Combine the default strings with the user-provided strings, while converting @@ -13,8 +17,12 @@ const defaultStrings = { * @param {object} strings */ module.exports.withDefaultStrings = (strings) => { - const objectifiedStrings = mapValues(strings, (value) => - typeof value === 'string' ? { one: value, other: value } : value - ); + const objectifiedStrings = ensureOneOther(strings); return defaults({}, objectifiedStrings, defaultStrings); }; + +function ensureOneOther(objectWithStrings) { + return mapValues(objectWithStrings, (value) => + typeof value === 'string' ? { one: value, other: value } : value + ); +} diff --git a/parcel-resolver-veda/index.d.ts b/parcel-resolver-veda/index.d.ts index 43ea624f0..3c2682969 100644 --- a/parcel-resolver-veda/index.d.ts +++ b/parcel-resolver-veda/index.d.ts @@ -65,7 +65,7 @@ declare module 'veda' { analysis?: { metrics: string[]; exclude: boolean; - } + }; } // A normalized compare layer is the result after the compare definition is @@ -136,6 +136,14 @@ declare module 'veda' { id: string; thematic?: string; } + /** + * Link Content + * When the story is a link out to the external/internal content + */ + + export interface LinkContentData { + url: string; + } export interface DatasetUsage { url: string; @@ -174,6 +182,7 @@ declare module 'veda' { media?: Media; taxonomy: Taxonomy[]; related?: RelatedContentData[]; + asLink?: LinkContentData; } // /////////////////////////////////////////////////////////////////////////// @@ -258,7 +267,6 @@ declare module 'veda' { one: string; other: string; }; - /** * List of custom user defined pages. */