diff --git a/src/components/SearchPage/DatasetCard.tsx b/src/components/SearchPage/DatasetCard.tsx
index 110b6fc..19fb758 100644
--- a/src/components/SearchPage/DatasetCard.tsx
+++ b/src/components/SearchPage/DatasetCard.tsx
@@ -1,6 +1,7 @@
import { Typography, Card, CardContent, Stack, Chip } from "@mui/material";
import { Colors } from "design/theme";
import React from "react";
+import { useMemo } from "react";
import { Link } from "react-router-dom";
import RoutesEnum from "types/routes.enum";
@@ -17,7 +18,9 @@ interface DatasetCardProps {
info?: {
Authors?: string[];
DatasetDOI?: string;
+ [k: string]: any;
};
+ [k: string]: any;
};
};
index: number;
@@ -25,6 +28,63 @@ interface DatasetCardProps {
keyword?: string; // for keyword highlight
}
+/** ---------- utility helpers ---------- **/
+const normalize = (s: string) =>
+ s
+ ?.replace(/[\u2018\u2019\u2032]/g, "'") // curly → straight
+ ?.replace(/[\u201C\u201D\u2033]/g, '"') ?? // curly → straight
+ "";
+
+const containsKeyword = (text?: string, kw?: string) => {
+ if (!text || !kw) return false;
+ const t = normalize(text).toLowerCase();
+ const k = normalize(kw).toLowerCase();
+ return t.includes(k);
+};
+
+/** Find a short snippet in secondary fields if not already visible */
+function findMatchSnippet(
+ v: any,
+ kw?: string
+): { label: string; html: string } | null {
+ if (!kw) return null;
+
+ // Which fields to scan (can add/remove fields here)
+ const CANDIDATE_FIELDS: Array<[string, (v: any) => string | undefined]> = [
+ ["Acknowledgements", (v) => v?.info?.Acknowledgements],
+ [
+ "Funding",
+ (v) =>
+ Array.isArray(v?.info?.Funding)
+ ? v.info.Funding.join(" ")
+ : v?.info?.Funding,
+ ],
+ ["ReferencesAndLinks", (v) => v?.info?.ReferencesAndLinks],
+ ];
+
+ const k = normalize(kw).toLowerCase();
+
+ for (const [label, getter] of CANDIDATE_FIELDS) {
+ const raw = getter(v); // v = parsedJson.value
+ if (!raw) continue;
+ const text = normalize(String(raw));
+ const i = text.toLowerCase().indexOf(k); // k is the lowercase version of keyword
+ if (i >= 0) {
+ const start = Math.max(0, i - 40);
+ const end = Math.min(text.length, i + k.length + 40);
+ const before = text.slice(start, i);
+ const hit = text.slice(i, i + k.length);
+ const after = text.slice(i + k.length, end);
+ const html = `${
+ start > 0 ? "…" : ""
+ }${before}${hit}${after}${end < text.length ? "…" : ""}`;
+ return { label, html };
+ }
+ }
+ return null;
+}
+/** ---------- end of helpers ---------- **/
+
const DatasetCard: React.FC = ({
dbname,
dsname,
@@ -40,7 +100,29 @@ const DatasetCard: React.FC = ({
const rawDOI = info?.DatasetDOI?.replace(/^doi:/, "");
const doiLink = rawDOI ? `https://doi.org/${rawDOI}` : null;
- // keyword hightlight functional component
+ // precompute what’s visible & whether it already contains the keyword
+ const authorsJoined = Array.isArray(info?.Authors)
+ ? info!.Authors.join(", ")
+ : typeof info?.Authors === "string"
+ ? info!.Authors
+ : "";
+
+ const visibleHasKeyword = useMemo(
+ () =>
+ containsKeyword(name, keyword) ||
+ containsKeyword(readme, keyword) ||
+ containsKeyword(authorsJoined, keyword),
+ [name, readme, authorsJoined, keyword]
+ );
+
+ // If not visible, produce a one-line snippet from other fields (for non-visible fields)
+ const snippet = useMemo(
+ () =>
+ !visibleHasKeyword ? findMatchSnippet(parsedJson.value, keyword) : null,
+ [parsedJson.value, keyword, visibleHasKeyword]
+ );
+
+ // keyword hightlight functional component (only for visible fields)
const highlightKeyword = (text: string, keyword?: string) => {
if (!keyword || !text?.toLowerCase().includes(keyword.toLowerCase())) {
return text;
@@ -99,7 +181,10 @@ const DatasetCard: React.FC = ({
{highlightKeyword(name || "Untitled Dataset", keyword)}
- Database: {dbname} | Dataset: {dsname}
+ {/* Database: {dbname} | Dataset: {dsname} */}
+ Database: {highlightKeyword(dbname, keyword)}
+ {" "} | {" "}
+ Dataset: {highlightKeyword(dsname, keyword)}
@@ -168,20 +253,35 @@ const DatasetCard: React.FC = ({
{info?.Authors && (
Authors:{" "}
- {highlightKeyword(
- Array.isArray(info.Authors)
- ? info.Authors.join(", ")
- : typeof info.Authors === "string"
- ? info.Authors
- : "N/A",
- keyword
- )}
+ {highlightKeyword(authorsJoined || "N/A", keyword)}
)}
)}
+ {/* show why it matched if not visible in main fields */}
+ {snippet && (
+
+
+ only
+ dangerouslySetInnerHTML={{ __html: snippet.html }}
+ />
+
+ )}
+
{doiLink && (
diff --git a/src/pages/DatasetDetailPage.tsx b/src/pages/DatasetDetailPage.tsx
index 0999906..c1b5c89 100644
--- a/src/pages/DatasetDetailPage.tsx
+++ b/src/pages/DatasetDetailPage.tsx
@@ -305,7 +305,7 @@ const DatasetDetailPage: React.FC = () => {
useEffect(() => {
if (datasetDocument) {
// ✅ Extract External Data & Assign `index`
- console.log("datasetDocument", datasetDocument);
+ // console.log("datasetDocument", datasetDocument);
const links = extractDataLinks(datasetDocument, "").map(
(link, index) => ({
...link,
diff --git a/src/pages/UpdatedDatasetDetailPage.tsx b/src/pages/UpdatedDatasetDetailPage.tsx
index a56e0d0..ee24bd0 100644
--- a/src/pages/UpdatedDatasetDetailPage.tsx
+++ b/src/pages/UpdatedDatasetDetailPage.tsx
@@ -93,6 +93,7 @@ const UpdatedDatasetDetailPage: React.FC = () => {
const [copiedKey, setCopiedKey] = useState(null);
const copyTimer = useRef(null);
const aiSummary = datasetDocument?.[".datainfo"]?.AISummary ?? "";
+ const readme = datasetDocument?.["README"] ?? "";
const handleSelectRevision = (newRev?: string | null) => {
setSearchParams((prev) => {
const p = new URLSearchParams(prev); // copy of the query url
@@ -808,7 +809,7 @@ const UpdatedDatasetDetailPage: React.FC = () => {
)}
{/* ai summary */}
- {aiSummary && (
+ {aiSummary ? (
<>
{
>
+ ) : readme ? (
+ <>
+
+
+ Summary
+
+
+
+
+ >
+ ) : (
+ ""
)}