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..3e04aac26 100644
--- a/app/content/lungmap/apis.mdx
+++ b/app/content/lungmap/apis.mdx
@@ -1,3 +1,8 @@
+---
+pageDescription: "REST API reference for querying LungMAP project, sample, and file metadata."
+pageTitle: "APIs"
+---
+
= async ({
if (!entityConfig || !entityId) return { notFound: true };
- const props: EntityDetailPageProps = { entityListType };
+ const { label } = entityConfig;
+ const props: EntityDetailPageProps = {
+ entityListType,
+ pageTitle: typeof label === "string" ? label : null,
+ };
// Process entity override props.
processEntityOverrideProps(entityConfig, entityListType, entityId, props);
@@ -280,6 +286,13 @@ export const getStaticProps: GetStaticProps = async ({
props
);
+ props.pageTitle = buildEntityPageTitle(
+ entityConfig,
+ props.data,
+ entityTab,
+ entityId
+ );
+
return {
props,
};
@@ -287,6 +300,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..83e9f415c
Binary files /dev/null and b/site-config/lungmap/images/og/og-image.png differ