diff --git a/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/fileNameCell.styles.ts b/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/components/Citation/citation.styles.ts similarity index 100% rename from components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/fileNameCell.styles.ts rename to components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/components/Citation/citation.styles.ts diff --git a/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/components/Citation/citation.tsx b/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/components/Citation/citation.tsx new file mode 100644 index 00000000..fa2157f2 --- /dev/null +++ b/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/components/Citation/citation.tsx @@ -0,0 +1,52 @@ +import { + ANCHOR_TARGET, + REL_ATTRIBUTE, +} from "@databiosphere/findable-ui/lib/components/Links/common/entities"; +import { Link } from "@databiosphere/findable-ui/lib/components/Links/components/Link/link"; +import { SVG_ICON_PROPS } from "@databiosphere/findable-ui/lib/styles/common/mui/svgIcon"; +import { TYPOGRAPHY_PROPS } from "@databiosphere/findable-ui/lib/styles/common/mui/typography"; +import type { JSX } from "react"; +import { StyledNoWrap, StyledOpenInNewIcon } from "./citation.styles"; +import { DOI_BASE_URL, EXTERNAL_LINK_TITLE } from "./constants"; +import type { Props } from "./types"; +import { splitTrailingWord } from "./utils"; + +/** + * The source study citation. Links to the DOI when there is one, otherwise + * renders as plain text - an external-link affordance on a link to nowhere + * would be worse than none. Takes a required `publicationString`, so the + * caller owns the "is there a citation at all?" question and the split only + * runs on the branch that consumes it. + * @param props - Component props. + * @param props.doi - Source study DOI, if any. + * @param props.publicationString - Source study citation. + * @returns citation, linked to the DOI when one exists. + */ +export const Citation = ({ doi, publicationString }: Props): JSX.Element => { + if (!doi) return <>{publicationString}; + const { head, tail } = splitTrailingWord(publicationString); + return ( + + {head} + + {tail} + + + + } + rel={REL_ATTRIBUTE.NO_OPENER_NO_REFERRER} + target={ANCHOR_TARGET.BLANK} + // MUI `Link` defaults to `color="primary"` and findable-ui's theme does + // not override it, so the wrapper's `ink.light` is ignored unless the + // colour is set on the link itself. + TypographyProps={{ color: TYPOGRAPHY_PROPS.COLOR.INK_LIGHT }} + url={`${DOI_BASE_URL}${doi}`} + /> + ); +}; diff --git a/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/constants.ts b/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/components/Citation/constants.ts similarity index 100% rename from components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/constants.ts rename to components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/components/Citation/constants.ts diff --git a/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/components/Citation/types.ts b/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/components/Citation/types.ts new file mode 100644 index 00000000..d864b40b --- /dev/null +++ b/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/components/Citation/types.ts @@ -0,0 +1,4 @@ +export interface Props { + doi: string | null; + publicationString: string; +} diff --git a/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/utils.ts b/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/components/Citation/utils.ts similarity index 52% rename from components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/utils.ts rename to components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/components/Citation/utils.ts index 420c85d3..1e677484 100644 --- a/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/utils.ts +++ b/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/components/Citation/utils.ts @@ -10,7 +10,11 @@ export function splitTrailingWord(text: string): { head: string; tail: string; } { - const index = text.trimEnd().lastIndexOf(" "); - if (index === -1) return { head: "", tail: text }; - return { head: text.slice(0, index + 1), tail: text.slice(index + 1) }; + // Slice the trimmed value, not the original: computing the index from + // `trimEnd()` and then slicing `text` leaves any trailing whitespace on the + // tail, which renders as a gap between the final word and the icon after it. + const trimmed = text.trimEnd(); + const index = trimmed.lastIndexOf(" "); + if (index === -1) return { head: "", tail: trimmed }; + return { head: trimmed.slice(0, index + 1), tail: trimmed.slice(index + 1) }; } diff --git a/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/fileNameCell.tsx b/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/fileNameCell.tsx index a7e31105..4170973b 100644 --- a/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/fileNameCell.tsx +++ b/components/HCABioNetworks/Network/Atlas/components/SourceDatasets/components/MainColumn/components/table/components/FileNameCell/fileNameCell.tsx @@ -1,17 +1,9 @@ -import { - ANCHOR_TARGET, - REL_ATTRIBUTE, -} from "@databiosphere/findable-ui/lib/components/Links/common/entities"; -import { Link } from "@databiosphere/findable-ui/lib/components/Links/components/Link/link"; -import { SVG_ICON_PROPS } from "@databiosphere/findable-ui/lib/styles/common/mui/svgIcon"; import { TYPOGRAPHY_PROPS } from "@databiosphere/findable-ui/lib/styles/common/mui/typography"; import { Stack, Typography } from "@mui/material"; import type { JSX } from "react"; import { buildVersionedFileNameValue } from "../../accessor"; -import { DOI_BASE_URL, EXTERNAL_LINK_TITLE } from "./constants"; -import { StyledNoWrap, StyledOpenInNewIcon } from "./fileNameCell.styles"; +import { Citation } from "./components/Citation/citation"; import type { Props } from "./types"; -import { splitTrailingWord } from "./utils"; /** * Pinned cell stacking the published file name over the source study citation. @@ -26,50 +18,18 @@ export const FileNameCell = ({ row }: Props): JSX.Element => { // Shared with the column's `accessorFn`, so the pinned column always sorts on // the value it displays. const fileName = buildVersionedFileNameValue(row); - // Split once - the final word is held on one line with the icon that follows. - const citation = publicationString - ? splitTrailingWord(publicationString) - : null; return ( {fileName} - {citation && ( + {publicationString && ( - {doi ? ( - // Text and icon are one label, so they are a single link target. - - {citation.head} - - {citation.tail} - - - - } - rel={REL_ATTRIBUTE.NO_OPENER_NO_REFERRER} - target={ANCHOR_TARGET.BLANK} - // MUI `Link` defaults to `color="primary"` and findable-ui's - // theme does not override it, so the wrapper's `ink.light` is - // ignored unless the colour is set on the link itself. - TypographyProps={{ - color: TYPOGRAPHY_PROPS.COLOR.INK_LIGHT, - }} - url={`${DOI_BASE_URL}${doi}`} - /> - ) : ( - // No DOI, so no link and no external-link affordance. - publicationString - )} + )}