Skip to content

Commit b53a802

Browse files
committed
feat: highlight subject folder when navigating from search results; refs #96
1 parent 0c9ebf2 commit b53a802

File tree

4 files changed

+60
-30
lines changed

4 files changed

+60
-30
lines changed

src/components/DatasetDetailPage/FileTree/FileTree.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type Props = {
1414
onPreview: (src: string | any, index: number, isInternal?: boolean) => void;
1515
getInternalByPath: (path: string) => { data: any; index: number } | undefined;
1616
getJsonByPath?: (path: string) => any;
17+
highlightText?: string;
1718
};
1819

1920
const formatSize = (n: number) => {
@@ -32,6 +33,7 @@ const FileTree: React.FC<Props> = ({
3233
onPreview,
3334
getInternalByPath,
3435
getJsonByPath,
36+
highlightText,
3537
}) => (
3638
<Box
3739
sx={{
@@ -71,6 +73,7 @@ const FileTree: React.FC<Props> = ({
7173
onPreview={onPreview}
7274
getInternalByPath={getInternalByPath}
7375
getJsonByPath={getJsonByPath}
76+
highlightText={highlightText}
7477
/> // pass the handlePreview(onPreview = handlePreview) function to FileTreeRow
7578
))}
7679
</Box>

src/components/DatasetDetailPage/FileTree/FileTreeRow.tsx

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { Box, Button, Collapse, Typography } from "@mui/material";
1414
import { Tooltip, IconButton } from "@mui/material";
1515
import { Colors } from "design/theme";
1616
import React, { useState } from "react";
17+
import { Color } from "three";
1718

1819
// show more / show less button for long string
1920
const LeafString: React.FC<{ value: string }> = ({ value }) => {
@@ -80,11 +81,11 @@ const LeafString: React.FC<{ value: string }> = ({ value }) => {
8081
type Props = {
8182
node: TreeNode;
8283
level: number;
83-
8484
// src is either an external URL(string) or the internal object
8585
onPreview: (src: string | any, index: number, isInternal?: boolean) => void;
8686
getInternalByPath: (path: string) => { data: any; index: number } | undefined;
8787
getJsonByPath?: (path: string) => any;
88+
highlightText?: string;
8889
};
8990

9091
// copy helper function
@@ -112,6 +113,7 @@ const FileTreeRow: React.FC<Props> = ({
112113
onPreview,
113114
getInternalByPath,
114115
getJsonByPath,
116+
highlightText,
115117
}) => {
116118
const [open, setOpen] = useState(false);
117119
const [copied, setCopied] = useState(false);
@@ -120,6 +122,34 @@ const FileTreeRow: React.FC<Props> = ({
120122
const internal = getInternalByPath(node.path);
121123
const externalUrl = node.link?.url;
122124

125+
const rowRef = React.useRef<HTMLDivElement | null>(null);
126+
// Highlight only if this row is exactly the subject folder (e.g., "sub-04")
127+
const isSubjectFolder =
128+
node.kind === "folder" && /^sub-[A-Za-z0-9]+$/i.test(node.name);
129+
const isExactHit =
130+
!!highlightText &&
131+
isSubjectFolder &&
132+
node.name.toLowerCase() === highlightText.toLowerCase();
133+
134+
React.useEffect(() => {
135+
if (isExactHit && rowRef.current) {
136+
rowRef.current.scrollIntoView({ behavior: "smooth", block: "center" });
137+
// subtle flash
138+
// rowRef.current.animate(
139+
// [
140+
// { backgroundColor: `${Colors.yellow}`, offset: 0 }, // turn yellow
141+
// { backgroundColor: `${Colors.yellow}`, offset: 0.85 }, // stay yellow 85% of time
142+
// { backgroundColor: "transparent", offset: 1 }, // then fade out
143+
// ],
144+
// { duration: 8000, easing: "ease", fill: "forwards" }
145+
// );
146+
}
147+
}, [isExactHit]);
148+
149+
const rowHighlightSx = isExactHit
150+
? { backgroundColor: `${Colors.yellow}`, borderRadius: 4 }
151+
: {};
152+
123153
const handleCopy = async (e: React.MouseEvent) => {
124154
e.stopPropagation(); // prevent expand/ collapse from firing when click the copy button
125155
const json = getJsonByPath?.(node.path); // call getJsonByPath(node.path)
@@ -136,13 +166,15 @@ const FileTreeRow: React.FC<Props> = ({
136166
return (
137167
<>
138168
<Box
169+
ref={rowRef}
139170
sx={{
140171
display: "flex",
141172
alignItems: "flex-start",
142173
gap: 1,
143174
py: 0.5,
144175
px: 1,
145176
cursor: "pointer",
177+
...rowHighlightSx,
146178
"&:hover": { backgroundColor: "rgba(0,0,0,0.04)" },
147179
}}
148180
onClick={() => setOpen((o) => !o)}
@@ -252,6 +284,7 @@ const FileTreeRow: React.FC<Props> = ({
252284
onPreview={onPreview}
253285
getInternalByPath={getInternalByPath}
254286
getJsonByPath={getJsonByPath}
287+
highlightText={highlightText} // for subject highlight
255288
/>
256289
))}
257290
</Collapse>
@@ -308,31 +341,6 @@ const FileTreeRow: React.FC<Props> = ({
308341
: formatLeafValue(node.value)}
309342
</Typography>
310343
))}
311-
312-
{/* {!node.link && node.value !== undefined && (
313-
<Typography
314-
title={
315-
node.name === "_ArrayZipData_"
316-
? "[compressed data]"
317-
: typeof node.value === "string"
318-
? node.value
319-
: JSON.stringify(node.value)
320-
}
321-
sx={{
322-
fontFamily: "monospace",
323-
fontSize: "0.85rem",
324-
color: "text.secondary",
325-
whiteSpace: "nowrap",
326-
overflow: "hidden",
327-
textOverflow: "ellipsis",
328-
mt: 0.25,
329-
}}
330-
>
331-
{node.name === "_ArrayZipData_"
332-
? "[compressed data]"
333-
: formatLeafValue(node.value)}
334-
</Typography>
335-
)} */}
336344
</Box>
337345
{/* ALWAYS show copy for files, even when no external/internal */}
338346
<Box sx={{ alignSelf: "flex-start" }}>

src/components/SearchPage/SubjectCard.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ const SubjectCard: React.FC<SubjectCardProps> = ({
3434
}) => {
3535
const { modalities, tasks, sessions, types } = parsedJson.value;
3636
const subjectLink = `${RoutesEnum.DATABASES}/${dbname}/${dsname}`;
37+
// const subjectLink = `${
38+
// RoutesEnum.DATABASES
39+
// }/${dbname}/${dsname}?focusSubj=${encodeURIComponent(subj)}`;
40+
const canonicalSubj = /^sub-/i.test(subj)
41+
? subj
42+
: `sub-${String(subj)
43+
.replace(/^sub-/i, "")
44+
.replace(/^0+/, "")
45+
.padStart(2, "0")}`;
3746

3847
// get the gender of subject
3948
const genderCode = parsedJson?.key?.[1];
@@ -84,8 +93,9 @@ const SubjectCard: React.FC<SubjectCardProps> = ({
8493
":hover": { textDecoration: "underline" },
8594
}}
8695
component={Link}
87-
to={subjectLink}
88-
target="_blank"
96+
// to={subjectLink}
97+
to={`${subjectLink}?focusSubj=${encodeURIComponent(canonicalSubj)}`}
98+
// target="_blank"
8999
>
90100
<PersonOutlineIcon />
91101
Subject: {subj} &nbsp;&nbsp;|&nbsp;&nbsp; Dataset: {dsname}

src/pages/UpdatedDatasetDetailPage.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,16 @@ interface InternalDataLink {
5454
const UpdatedDatasetDetailPage: React.FC = () => {
5555
const { dbName, docId } = useParams<{ dbName: string; docId: string }>();
5656
const navigate = useNavigate();
57-
// for revision
5857
const [searchParams, setSearchParams] = useSearchParams();
58+
// for subject highlight
59+
const focusSubjRaw = searchParams.get("focusSubj") || undefined;
60+
const focusSubj = !focusSubjRaw
61+
? undefined
62+
: /^sub-/i.test(focusSubjRaw)
63+
? focusSubjRaw
64+
: `sub-${focusSubjRaw.replace(/^0+/, "").padStart(2, "0")}`;
65+
console.log("focusSubj", focusSubj);
66+
// for revision
5967
const rev = searchParams.get("rev") || undefined;
6068

6169
const handleSelectRevision = (newRev?: string | null) => {
@@ -835,6 +843,7 @@ const UpdatedDatasetDetailPage: React.FC = () => {
835843
onPreview={handlePreview} // pass the function down to FileTree
836844
getInternalByPath={getInternalByPath}
837845
getJsonByPath={getJsonByPath}
846+
highlightText={focusSubj} // for subject highlight
838847
/>
839848
</Box>
840849
</Box>
@@ -1156,7 +1165,7 @@ const UpdatedDatasetDetailPage: React.FC = () => {
11561165
}}
11571166
></Box>
11581167

1159-
{/* <DatasetFlashcards */}
1168+
{/* <api tabs */}
11601169
<LoadDatasetTabs
11611170
pagename={docId ?? ""}
11621171
docname={datasetDocument?.Name || ""}

0 commit comments

Comments
 (0)