diff --git a/.gitignore b/.gitignore index 330de29b5..b59e06eae 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,9 @@ _templates # favicons /public/favicons/* +# og images +/public/og/* + /files/**/out/ #Python diff --git a/app/components/Layout/components/BackPage/components/BackPageHero/components/BackPageHeroActions/backPageHeroActions.tsx b/app/components/Layout/components/BackPage/components/BackPageHero/components/BackPageHeroActions/backPageHeroActions.tsx index 16afcbcf8..aca827689 100644 --- a/app/components/Layout/components/BackPage/components/BackPageHero/components/BackPageHeroActions/backPageHeroActions.tsx +++ b/app/components/Layout/components/BackPage/components/BackPageHero/components/BackPageHeroActions/backPageHeroActions.tsx @@ -9,7 +9,6 @@ import { import { useConfig } from "@databiosphere/findable-ui/lib/hooks/useConfig"; import { TYPOGRAPHY_PROPS } from "@databiosphere/findable-ui/lib/styles/common/mui/typography"; import { JSX } from "react"; -import { SiteConfig } from "../../../../../../../../../site-config/common/entities"; import { StyledBackPageHeroActions } from "./backPageHeroActions.styles"; export interface BackPageHeroActionsProps { @@ -21,7 +20,7 @@ export const BackPageHeroActions = ({ callToActionProps, linkProps, }: BackPageHeroActionsProps): JSX.Element => { - const { config } = useConfig() as { config: SiteConfig }; + const { config } = useConfig() as { config: { portalURL?: string } }; const { getURL, label, ...otherProps } = linkProps || {}; const linkUrl = getURL?.(config.portalURL); return ( diff --git a/app/components/common/OgMeta/ogMeta.tsx b/app/components/common/OgMeta/ogMeta.tsx new file mode 100644 index 000000000..0488e3222 --- /dev/null +++ b/app/components/common/OgMeta/ogMeta.tsx @@ -0,0 +1,70 @@ +import NextHead from "next/head"; +import { useRouter } from "next/router"; +import { JSX } from "react"; +import type { OgMetaProps } from "./types"; + +/** + * Builds the canonical path from the router's asPath, stripping query and hash. + * @param asPath - The router's asPath value. + * @returns clean path. + */ +function buildPath(asPath: string): string { + return asPath.split("?")[0].split("#")[0]; +} + +/** + * Builds the OG title from the page title and app title. + * @param appTitle - The application title. + * @param pageTitle - The page-specific title. + * @returns formatted title. + */ +function buildTitle(appTitle: string, pageTitle?: string | null): string { + if (pageTitle && pageTitle !== appTitle) { + return `${pageTitle} - ${appTitle}`; + } + return appTitle; +} + +/** + * Renders Open Graph and Twitter meta tags for rich link sharing. + * @param props - The component props. + * @param props.appTitle - The application title. + * @param props.browserURL - The site's base URL. + * @param props.defaultDescription - Fallback description when no page description is provided. + * @param props.pageDescription - Page-specific description. + * @param props.pageTitle - Page-specific title. + * @returns head element with meta tags. + */ +export const OgMeta = ({ + appTitle, + browserURL, + defaultDescription, + pageDescription, + pageTitle, +}: OgMetaProps): JSX.Element => { + const { asPath } = useRouter(); + const description = pageDescription || defaultDescription; + const image = `${browserURL}/og/og-image.png`; + const path = buildPath(asPath); + const title = buildTitle(appTitle, pageTitle); + const url = `${browserURL}${path}`; + return ( + + + + + + + + + + + + + + ); +}; diff --git a/app/components/common/OgMeta/types.ts b/app/components/common/OgMeta/types.ts new file mode 100644 index 000000000..5cba9d74b --- /dev/null +++ b/app/components/common/OgMeta/types.ts @@ -0,0 +1,7 @@ +export interface OgMetaProps { + appTitle: string; + browserURL: string; + defaultDescription: string; + pageDescription?: string | null; + pageTitle?: string | null; +} diff --git a/app/config/config.ts b/app/config/config.ts index b91ee4e15..47d50f2ef 100644 --- a/app/config/config.ts +++ b/app/config/config.ts @@ -1,11 +1,11 @@ import { setConfig } from "@databiosphere/findable-ui/lib/config/config"; -import { SiteConfig } from "@databiosphere/findable-ui/lib/config/entities"; import anvilCatalogDev from "../../site-config/anvil-catalog/dev/config"; import anvilCatalogProd from "../../site-config/anvil-catalog/prod/config"; import anvilCmgCCDev from "../../site-config/anvil-cmg/cc-dev/config"; import anvilCmgDev from "../../site-config/anvil-cmg/dev/config"; import anvilCmgProd from "../../site-config/anvil-cmg/prod/config"; import anvilCmgTempdev from "../../site-config/anvil-cmg/tempdev/config"; +import { SiteConfig } from "../../site-config/common/entities"; import hcaDcpCCMaDev from "../../site-config/hca-dcp/cc-ma-dev/config"; import hcaDcpDev from "../../site-config/hca-dcp/dev/config"; import hcaDcpMaDev from "../../site-config/hca-dcp/ma-dev/config"; diff --git a/app/content/anvil-cmg/beta-announcement.mdx b/app/content/anvil-cmg/beta-announcement.mdx index 9ff9a2500..7beed97a9 100644 --- a/app/content/anvil-cmg/beta-announcement.mdx +++ b/app/content/anvil-cmg/beta-announcement.mdx @@ -1,3 +1,8 @@ +--- +pageTitle: "Beta Announcement" +pageDescription: "AnVIL Data Explorer beta launch announcement and new features." +--- + > { const slug = getSlug(context); const contentPathname = getContentPathname(); @@ -27,7 +26,8 @@ export async function getContentStaticProps( } const markdownPathname = getMarkdownPathname(contentPathname, slug); const markdownWithMeta = fs.readFileSync(markdownPathname, "utf-8"); - const { content } = matter(markdownWithMeta); + const { content, data } = matter(markdownWithMeta); + const { pageDescription, pageTitle } = data as ContentFrontmatter; const mdxSource = await serialize(content, { mdxOptions: { development: process.env.NODE_ENV === "development", @@ -40,6 +40,7 @@ export async function getContentStaticProps( props: { layoutStyle: LAYOUT_STYLE_NO_CONTRAST_DEFAULT, mdxSource, + pageDescription: pageDescription ?? null, pageTitle, slug, }, diff --git a/app/content/common/entities.ts b/app/content/common/entities.ts index d0f1ee278..be1b0ddad 100644 --- a/app/content/common/entities.ts +++ b/app/content/common/entities.ts @@ -7,9 +7,15 @@ export interface AnchorProps { href: string; } +export interface ContentFrontmatter { + pageDescription?: string; + pageTitle: string; +} + export interface ContentProps { layoutStyle?: LayoutStyle; mdxSource: MDXRemoteSerializeResult | null; + pageDescription?: string | null; pageTitle: string; slug: string[] | null; } diff --git a/app/content/lungmap/apis.mdx b/app/content/lungmap/apis.mdx index 8357b9cf8..1830e6e25 100644 --- a/app/content/lungmap/apis.mdx +++ b/app/content/lungmap/apis.mdx @@ -1,3 +1,7 @@ +--- +pageTitle: "APIs" +--- + = async ({ if (!entityConfig || !entityId) return { notFound: true }; - const props: EntityDetailPageProps = { browserURL, entityListType }; + const { label } = entityConfig; + const props: EntityDetailPageProps = { + browserURL, + entityListType, + pageTitle: typeof label === "string" ? label : null, + }; // Process entity override props. processEntityOverrideProps(entityConfig, entityListType, entityId, props); @@ -290,6 +297,13 @@ export const getStaticProps: GetStaticProps = async ({ props ); + props.pageTitle = buildEntityPageTitle( + entityConfig, + props.data, + entityTab, + entityId + ); + return { props, }; @@ -297,6 +311,35 @@ export const getStaticProps: GetStaticProps = async ({ export default EntityDetailPage; +/** + * Builds the entity detail page title from the fetched entity data plus the + * active detail tab. Falls back to the entity id when no entity title is + * available. + * @param entityConfig - Entity config providing getTitle and tab definitions. + * @param data - Fetched entity data (may be undefined). + * @param entityTab - The active detail tab route. + * @param entityId - The entity id used as a fallback when no title is found. + * @returns Formatted page title. + */ +function buildEntityPageTitle( + entityConfig: EntityConfig, + data: AzulEntityStaticResponse["data"], + entityTab: string | undefined, + entityId: string +): string { + const { + detail: { tabs }, + getTitle, + } = entityConfig; + + const entityTitle = getTitle?.(data); + const { label } = tabs.find(({ route }) => route === entityTab) || {}; + + const detailTitle = entityTitle || entityId; + + return typeof label === "string" ? `${label} — ${detailTitle}` : detailTitle; +} + /** * Returns the catalog prefix for the given default catalog. * @param defaultCatalog - Default catalog. diff --git a/pages/[entityListType]/index.tsx b/pages/[entityListType]/index.tsx index c73734a5e..514781708 100644 --- a/pages/[entityListType]/index.tsx +++ b/pages/[entityListType]/index.tsx @@ -18,7 +18,8 @@ interface PageUrl extends ParsedUrlQuery { interface ListPageProps extends AzulEntitiesStaticResponse { entityListType: string; - pageTitle?: string; + pageDescription?: string | null; + pageTitle?: string | null; } /** @@ -98,12 +99,12 @@ export const getStaticProps: GetStaticProps< const { exploreMode, label } = entityConfig; const { fetchAllEntities } = getEntityService(entityConfig, undefined); // Determine the type of fetch, either from an API endpoint or a TSV. - let pageTitle; - if (typeof label === "string") { - pageTitle = label; - } + const pageTitle = typeof label === "string" ? label : null; + const pageDescription = pageTitle + ? `Browse and explore ${pageTitle.toLowerCase()}.` + : null; - const props: ListPageProps = { entityListType, pageTitle }; + const props: ListPageProps = { entityListType, pageDescription, pageTitle }; // Seed database. if (exploreMode === EXPLORE_MODE.CS_FETCH_CS_FILTERING) { diff --git a/pages/_app.tsx b/pages/_app.tsx index 665b42ce4..28dd22fc6 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -25,6 +25,7 @@ import { ThemeProvider as EmotionThemeProvider } from "@emotion/react"; import { createTheme, CssBaseline, Theme, ThemeProvider } from "@mui/material"; import { createBreakpoints } from "@mui/system"; import { deepmerge } from "@mui/utils"; +import { OgMeta } from "app/components/common/OgMeta/ogMeta"; import { config } from "app/config/config"; import { FEATURES } from "app/shared/entities"; import { NextPage } from "next"; @@ -37,7 +38,8 @@ const FEATURE_FLAGS = Object.values(FEATURES); const SESSION_TIMEOUT = 15 * 60 * 1000; // 15 minutes export interface PageProps extends AzulEntitiesStaticResponse { - pageTitle?: string; + pageDescription?: string | null; + pageTitle?: string | null; } export type NextPageWithComponent = NextPage & { @@ -53,11 +55,19 @@ setFeatureFlags(FEATURE_FLAGS); function MyApp({ Component, pageProps }: AppPropsWithComponent): JSX.Element { // Set up the site configuration, layout and theme. const appConfig = config(); - const { analytics, layout, redirectRootToPath, themeOptions } = appConfig; + const { + analytics, + appTitle, + browserURL, + description, + layout, + redirectRootToPath, + themeOptions, + } = appConfig; const { gtmAuth, gtmId, gtmPreview } = analytics || {}; const { floating, footer, header } = layout || {}; const theme = createAppTheme(themeOptions); - const { entityListType, pageTitle } = pageProps as PageProps; + const { entityListType, pageDescription, pageTitle } = pageProps as PageProps; const Main = Component.Main || DXMain; // Initialize Google Tag Manager. @@ -71,7 +81,14 @@ function MyApp({ Component, pageProps }: AppPropsWithComponent): JSX.Element { - + + diff --git a/pages/apis/index.tsx b/pages/apis/index.tsx index 541fb327d..98040246b 100644 --- a/pages/apis/index.tsx +++ b/pages/apis/index.tsx @@ -11,7 +11,7 @@ import NotFoundPage from "../404"; const slug = ["apis"]; export const getStaticProps: GetStaticProps = async () => { - return getContentStaticProps({ params: { slug } }, "APIs"); + return getContentStaticProps({ params: { slug } }); }; const Page = ({ diff --git a/pages/beta-announcement/index.tsx b/pages/beta-announcement/index.tsx index 18935b310..9ae1e2f0b 100644 --- a/pages/beta-announcement/index.tsx +++ b/pages/beta-announcement/index.tsx @@ -11,7 +11,7 @@ import NotFoundPage from "../404"; const slug = ["beta-announcement"]; export const getStaticProps: GetStaticProps = async () => { - return getContentStaticProps({ params: { slug } }, "Beta Announcement"); + return getContentStaticProps({ params: { slug } }); }; const Page = ({ diff --git a/pages/data-dictionary/[dictionary]/index.tsx b/pages/data-dictionary/[dictionary]/index.tsx index 43bd3ee33..4baf6a9ef 100644 --- a/pages/data-dictionary/[dictionary]/index.tsx +++ b/pages/data-dictionary/[dictionary]/index.tsx @@ -21,7 +21,13 @@ export const getStaticProps = async ( context: GetStaticPropsContext ): Promise> => { const { dictionary } = context.params as PageUrlParams; - return { props: { dictionary } }; + return { + props: { + dictionary, + pageDescription: "Browse the data dictionary and metadata schema.", + pageTitle: "Data Dictionary", + }, + }; }; export const getStaticPaths: GetStaticPaths = async () => { diff --git a/pages/export/biodata-catalyst.tsx b/pages/export/biodata-catalyst.tsx index 81537c606..6c30eb30c 100644 --- a/pages/export/biodata-catalyst.tsx +++ b/pages/export/biodata-catalyst.tsx @@ -5,6 +5,7 @@ import { JSX } from "react"; export const getStaticProps: GetStaticProps = async () => { return { props: { + pageDescription: "Export selected data to NHLBI BioData Catalyst.", pageTitle: "Export to NHLBI BioData Catalyst", }, }; diff --git a/pages/export/cancer-genomics-cloud.tsx b/pages/export/cancer-genomics-cloud.tsx index f78a2c8da..b0644aec6 100644 --- a/pages/export/cancer-genomics-cloud.tsx +++ b/pages/export/cancer-genomics-cloud.tsx @@ -5,6 +5,7 @@ import { JSX } from "react"; export const getStaticProps: GetStaticProps = async () => { return { props: { + pageDescription: "Export selected data to Cancer Genomics Cloud.", pageTitle: "Export to Cancer Genomics Cloud", }, }; diff --git a/pages/export/cavatica.tsx b/pages/export/cavatica.tsx index c2c9670f3..4b3e9a1dc 100644 --- a/pages/export/cavatica.tsx +++ b/pages/export/cavatica.tsx @@ -5,6 +5,7 @@ import { JSX } from "react"; export const getStaticProps: GetStaticProps = async () => { return { props: { + pageDescription: "Export selected data to CAVATICA for analysis.", pageTitle: "Export to CAVATICA", }, }; diff --git a/pages/export/download-manifest.tsx b/pages/export/download-manifest.tsx index 276486123..aba0b012f 100644 --- a/pages/export/download-manifest.tsx +++ b/pages/export/download-manifest.tsx @@ -5,6 +5,7 @@ import { JSX } from "react"; export const getStaticProps: GetStaticProps = async () => { return { props: { + pageDescription: "Request a file manifest for your selected data.", pageTitle: "Request File Manifest", }, }; diff --git a/pages/export/export-to-terra.tsx b/pages/export/export-to-terra.tsx index ef8f2eaab..2cdb80302 100644 --- a/pages/export/export-to-terra.tsx +++ b/pages/export/export-to-terra.tsx @@ -5,6 +5,7 @@ import { JSX } from "react"; export const getStaticProps: GetStaticProps = async () => { return { props: { + pageDescription: "Export selected data to Terra for analysis.", pageTitle: "Export to Terra", }, }; diff --git a/pages/export/get-curl-command.tsx b/pages/export/get-curl-command.tsx index f5b767119..99b9f7ccc 100644 --- a/pages/export/get-curl-command.tsx +++ b/pages/export/get-curl-command.tsx @@ -10,6 +10,7 @@ import { hasNRESConsentGroup } from "../../app/viewModelBuilders/azul/anvil-cmg/ export const getStaticProps: GetStaticProps = async () => { return { props: { + pageDescription: "Download selected data using the curl command.", pageTitle: 'Download Selected Data Using "curl"', }, }; diff --git a/pages/export/index.tsx b/pages/export/index.tsx index e95e24158..8ebab3d2c 100644 --- a/pages/export/index.tsx +++ b/pages/export/index.tsx @@ -5,6 +5,7 @@ import { JSX } from "react"; export const getStaticProps: GetStaticProps = async () => { return { props: { + pageDescription: "Choose an export method for your selected data.", pageTitle: "Choose Export Method", }, }; diff --git a/pages/ga-announcement/index.tsx b/pages/ga-announcement/index.tsx index cb0ad9283..0292d1aec 100644 --- a/pages/ga-announcement/index.tsx +++ b/pages/ga-announcement/index.tsx @@ -11,10 +11,7 @@ import NotFoundPage from "../404"; const slug = ["ga-announcement"]; export const getStaticProps: GetStaticProps = async () => { - return getContentStaticProps( - { params: { slug } }, - "General Availability Announcement" - ); + return getContentStaticProps({ params: { slug } }); }; const Page = ({ diff --git a/pages/guides/data-download-options.tsx b/pages/guides/data-download-options.tsx index 682926792..cbe2b5783 100644 --- a/pages/guides/data-download-options.tsx +++ b/pages/guides/data-download-options.tsx @@ -17,7 +17,7 @@ import { const slug = ["guides", "data-download-options"]; export const getStaticProps: GetStaticProps = async () => { - return getContentStaticProps({ params: { slug } }, "Data Download Options"); + return getContentStaticProps({ params: { slug } }); }; const Page = ({ diff --git a/pages/guides/data-download-via-curl.tsx b/pages/guides/data-download-via-curl.tsx index eab1734ae..034ac6611 100644 --- a/pages/guides/data-download-via-curl.tsx +++ b/pages/guides/data-download-via-curl.tsx @@ -17,7 +17,7 @@ import { const slug = ["guides", "data-download-via-curl"]; export const getStaticProps: GetStaticProps = async () => { - return getContentStaticProps({ params: { slug } }, "Data Download via curl"); + return getContentStaticProps({ params: { slug } }); }; const Page = ({ diff --git a/pages/guides/index.tsx b/pages/guides/index.tsx index 5aaf7730a..184ce0863 100644 --- a/pages/guides/index.tsx +++ b/pages/guides/index.tsx @@ -17,7 +17,7 @@ import { const slug = ["guides"]; export const getStaticProps: GetStaticProps = async () => { - return getContentStaticProps({ params: { slug } }, "Guides"); + return getContentStaticProps({ params: { slug } }); }; const Page = ({ diff --git a/pages/guides/individual-file-download.tsx b/pages/guides/individual-file-download.tsx index d3b805241..bf4fe4e8f 100644 --- a/pages/guides/individual-file-download.tsx +++ b/pages/guides/individual-file-download.tsx @@ -17,10 +17,7 @@ import { const slug = ["guides", "individual-file-download"]; export const getStaticProps: GetStaticProps = async () => { - return getContentStaticProps( - { params: { slug } }, - "Individual File Download" - ); + return getContentStaticProps({ params: { slug } }); }; const Page = ({ diff --git a/pages/guides/tsv-file-manifest-download.tsx b/pages/guides/tsv-file-manifest-download.tsx index 014203012..27e46c12f 100644 --- a/pages/guides/tsv-file-manifest-download.tsx +++ b/pages/guides/tsv-file-manifest-download.tsx @@ -17,10 +17,7 @@ import { const slug = ["guides", "tsv-file-manifest-download"]; export const getStaticProps: GetStaticProps = async () => { - return getContentStaticProps( - { params: { slug } }, - "TSV File Manifest Download" - ); + return getContentStaticProps({ params: { slug } }); }; const Page = ({ diff --git a/pages/login/index.tsx b/pages/login/index.tsx index 2d1146a75..3d5a23428 100644 --- a/pages/login/index.tsx +++ b/pages/login/index.tsx @@ -4,7 +4,10 @@ import { JSX } from "react"; export const getStaticProps: GetStaticProps = async () => { return { - props: { pageTitle: "Login" }, + props: { + pageDescription: "Sign in to access protected data and features.", + pageTitle: "Login", + }, }; }; diff --git a/pages/metadata/index.tsx b/pages/metadata/index.tsx index bd36b3cff..45a6d5b5b 100644 --- a/pages/metadata/index.tsx +++ b/pages/metadata/index.tsx @@ -11,7 +11,7 @@ import NotFoundPage from "../404"; const slug = ["metadata"]; export const getStaticProps: GetStaticProps = async () => { - return getContentStaticProps({ params: { slug } }, "Metadata Dictionary"); + return getContentStaticProps({ params: { slug } }); }; const Page = ({ diff --git a/pages/privacy/index.tsx b/pages/privacy/index.tsx index fc13b0ec7..6eb902d98 100644 --- a/pages/privacy/index.tsx +++ b/pages/privacy/index.tsx @@ -11,7 +11,7 @@ import NotFoundPage from "../404"; const slug = ["privacy"]; export const getStaticProps: GetStaticProps = async () => { - return getContentStaticProps({ params: { slug } }, "Privacy"); + return getContentStaticProps({ params: { slug } }); }; const Page = ({ diff --git a/pages/terms-of-service/index.tsx b/pages/terms-of-service/index.tsx index 8a6e6cba3..722cd1895 100644 --- a/pages/terms-of-service/index.tsx +++ b/pages/terms-of-service/index.tsx @@ -11,7 +11,7 @@ import NotFoundPage from "../404"; const slug = ["terms-of-service"]; export const getStaticProps: GetStaticProps = async () => { - return getContentStaticProps({ params: { slug } }, "Terms of Service"); + return getContentStaticProps({ params: { slug } }); }; const Page = ({ diff --git a/scripts/build.sh b/scripts/build.sh index 58ef84189..093e87618 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -21,4 +21,22 @@ then fi else echo "Directory $DIR not found." +fi + +# Reset OG image destination so builds for different site configs can't +# accidentally inherit a previous build's image, then copy if the source +# directory has any files. +OG_DIR="./site-config/$1/images/og" +OG_PUBLIC_DIR="./public/og" + +rm -rf "$OG_PUBLIC_DIR" +mkdir -p "$OG_PUBLIC_DIR" + +if [ -d "$OG_DIR" ]; then + shopt -s nullglob + og_files=("$OG_DIR"/*) + shopt -u nullglob + if [ ${#og_files[@]} -gt 0 ]; then + cp "${og_files[@]}" "$OG_PUBLIC_DIR/" + fi fi \ No newline at end of file diff --git a/scripts/common-build.sh b/scripts/common-build.sh index 9c90d4d67..f5c263b8c 100755 --- a/scripts/common-build.sh +++ b/scripts/common-build.sh @@ -21,4 +21,22 @@ then fi else echo "Directory $DIR not found." +fi + +# Reset OG image destination so builds for different site configs can't +# accidentally inherit a previous build's image, then copy if the source +# directory has any files. +OG_DIR="./site-config/$1/images/og" +OG_PUBLIC_DIR="./public/og" + +rm -rf "$OG_PUBLIC_DIR" +mkdir -p "$OG_PUBLIC_DIR" + +if [ -d "$OG_DIR" ]; then + shopt -s nullglob + og_files=("$OG_DIR"/*) + shopt -u nullglob + if [ ${#og_files[@]} -gt 0 ]; then + cp "${og_files[@]}" "$OG_PUBLIC_DIR/" + fi fi \ No newline at end of file diff --git a/site-config/anvil-catalog/dev/config.ts b/site-config/anvil-catalog/dev/config.ts index eca9c6942..accbfe480 100644 --- a/site-config/anvil-catalog/dev/config.ts +++ b/site-config/anvil-catalog/dev/config.ts @@ -17,6 +17,7 @@ import { socialMedia } from "./socials/socialMedia"; // Template constants const APP_TITLE = "AnVIL Dataset Catalog"; const BROWSER_URL = "https://anvilproject.dev.clevercanary.com"; +const DESCRIPTION = "Browse datasets across the AnVIL Dataset Catalog."; const EXPLORER_URL = "https://explore.anvilproject.dev.clevercanary.com"; const HOME_PAGE_PATH = ROUTES.CONSORTIA; const PORTAL_URL = "https://anvilproject.dev.clevercanary.com"; @@ -81,6 +82,7 @@ export function makeConfig( dataSource: { url: "", }, + description: DESCRIPTION, entities: [ consortiaEntityConfig, studiesEntityConfig, diff --git a/site-config/anvil-catalog/images/og/og-image.png b/site-config/anvil-catalog/images/og/og-image.png new file mode 100644 index 000000000..2d86a4e25 Binary files /dev/null and b/site-config/anvil-catalog/images/og/og-image.png differ diff --git a/site-config/anvil-cmg/dev/config.ts b/site-config/anvil-cmg/dev/config.ts index 3726d8931..36cad69e3 100644 --- a/site-config/anvil-cmg/dev/config.ts +++ b/site-config/anvil-cmg/dev/config.ts @@ -26,6 +26,8 @@ import { floating } from "./layout/floating"; // Template constants const APP_TITLE = "AnVIL Data Explorer"; +const DESCRIPTION = + "Explore datasets, donors, biosamples, and files in the AnVIL Data Explorer."; const DATA_URL = "https://service.anvil.gi.ucsc.edu"; const BROWSER_URL = "https://explore.anvil.gi.ucsc.edu"; const PORTAL_URL = "https://anvilproject.dev.clevercanary.com"; @@ -159,6 +161,7 @@ export function makeConfig( }, url: `${dataUrl}/`, }, + description: DESCRIPTION, enableEntitiesView: true, entities: [ datasetsEntityConfig, diff --git a/site-config/anvil-cmg/images/og/og-image.png b/site-config/anvil-cmg/images/og/og-image.png new file mode 100644 index 000000000..2d86a4e25 Binary files /dev/null and b/site-config/anvil-cmg/images/og/og-image.png differ diff --git a/site-config/common/entities.ts b/site-config/common/entities.ts index 5d337aa96..969f67f34 100644 --- a/site-config/common/entities.ts +++ b/site-config/common/entities.ts @@ -1,5 +1,6 @@ import { SiteConfig as DXSiteConfig } from "@databiosphere/findable-ui/lib/config/entities"; export interface SiteConfig extends DXSiteConfig { + description: string; portalURL?: string; } diff --git a/site-config/hca-dcp/dev/config.ts b/site-config/hca-dcp/dev/config.ts index df73534d5..207a68326 100644 --- a/site-config/hca-dcp/dev/config.ts +++ b/site-config/hca-dcp/dev/config.ts @@ -19,6 +19,8 @@ import { floating } from "./layout/floating"; // Template constants const APP_TITLE = "HCA Data Explorer"; const CATALOG = "dcp59"; +const DESCRIPTION = + "Explore projects, samples, and files in the HCA Data Explorer."; const BROWSER_URL = "https://explore.data.humancellatlas.dev.clevercanary.com"; const DATA_URL = "https://service.azul.data.humancellatlas.org"; const EXPORT_TO_TERRA_URL = "https://app.terra.bio"; @@ -57,6 +59,7 @@ export function makeConfig( }, url: `${dataUrl}/`, }, + description: DESCRIPTION, enableEntitiesView: true, entities: [projectsEntityConfig, samplesEntityConfig, filesEntityConfig], export: exportConfig, diff --git a/site-config/hca-dcp/images/og/og-image.png b/site-config/hca-dcp/images/og/og-image.png new file mode 100644 index 000000000..9612a7605 Binary files /dev/null and b/site-config/hca-dcp/images/og/og-image.png differ diff --git a/site-config/lungmap/dev/config.ts b/site-config/lungmap/dev/config.ts index f30224a24..2218a437b 100644 --- a/site-config/lungmap/dev/config.ts +++ b/site-config/lungmap/dev/config.ts @@ -18,6 +18,8 @@ import { socialMedia } from "./socialMedia"; const APP_TITLE = "LungMAP Data Explorer"; const BROWSER_URL = "https://dev.data-browser.lungmap.net"; const CATALOG = "lm2"; +const DESCRIPTION = + "Explore projects, samples, and files in the LungMAP Data Explorer."; const DATA_URL = HCA_DATA_URL; const EXPORT_TO_TERRA_URL = "https://bvdp-saturn-dev.appspot.com/"; const HOME_PAGE_PATH = "/projects"; @@ -54,6 +56,7 @@ export function makeConfig( }, url: `${dataUrl}/`, }, + description: DESCRIPTION, enableEntitiesView: true, entities: [projectsEntityConfig, samplesEntityConfig, filesEntityConfig], export: exportConfig, diff --git a/site-config/lungmap/images/og/og-image.png b/site-config/lungmap/images/og/og-image.png new file mode 100644 index 000000000..95b1ccd05 Binary files /dev/null and b/site-config/lungmap/images/og/og-image.png differ