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
- )}
+
)}