Skip to content

Commit 29fef36

Browse files
authored
Merge pull request #93 from NeuroJSON/dev-fan
Add revision-aware dataset rendering, Suggested Databases panel (real-time cards), and search UI polish
2 parents e526764 + c176b90 commit 29fef36

File tree

8 files changed

+360
-239
lines changed

8 files changed

+360
-239
lines changed

public/img/search_page/search.png

37.4 KB
Loading

src/components/DatasetDetailPage/MetaDataPanel.tsx

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ type Props = {
1818
datasetDocument: any;
1919
dbName: string | undefined;
2020
docId: string | undefined;
21+
// NEW:
22+
currentRev?: string; // from URL (?rev=...)
23+
onChangeRev?: (rev?: string | null) => void; // to update URL
24+
revsList?: { rev: string }[];
2125
};
2226

2327
type RevInfo = { rev: string };
@@ -27,16 +31,37 @@ const MetaDataPanel: React.FC<Props> = ({
2731
datasetDocument,
2832
dbName,
2933
docId,
34+
currentRev,
35+
onChangeRev,
36+
revsList = [], // default empty
3037
}) => {
31-
const revs: RevInfo[] = useMemo(
32-
() =>
33-
Array.isArray(datasetDocument?.["_revs_info"])
34-
? (datasetDocument!["_revs_info"] as RevInfo[])
35-
: [],
36-
[datasetDocument]
37-
);
38-
const [revIdx, setRevIdx] = useState(0);
38+
// const revs: RevInfo[] = useMemo(
39+
// () =>
40+
// Array.isArray(datasetDocument?.["_revs_info"])
41+
// ? (datasetDocument!["_revs_info"] as RevInfo[])
42+
// : [],
43+
// [datasetDocument]
44+
// );
45+
const revs = revsList;
46+
47+
// derive index from currentRev; fallback to 0 (latest)
48+
const deriveIdx = React.useCallback((revList: RevInfo[], cur?: string) => {
49+
if (!revList.length) return 0;
50+
if (!cur) return 0;
51+
const idx = revList.findIndex((r) => r.rev === cur);
52+
return idx >= 0 ? idx : 0;
53+
}, []);
54+
55+
const [revIdx, setRevIdx] = useState<number>(deriveIdx(revs, currentRev));
56+
57+
// keep local idx synced when URL rev or list changes
58+
React.useEffect(() => {
59+
setRevIdx(deriveIdx(revs, currentRev));
60+
}, [revs, currentRev, deriveIdx]);
61+
3962
const selected = revs[revIdx];
63+
// const [revIdx, setRevIdx] = useState(0);
64+
// const selected = revs[revIdx];
4065

4166
return (
4267
<Box
@@ -191,7 +216,14 @@ const MetaDataPanel: React.FC<Props> = ({
191216
labelId="rev-select-label"
192217
label="Select revision"
193218
value={revIdx}
194-
onChange={(e) => setRevIdx(Number(e.target.value))}
219+
onChange={(e) => {
220+
const idx = Number(e.target.value);
221+
setRevIdx(idx);
222+
const chosen = revs[idx]?.rev;
223+
// update URL -> parent will refetch with ?rev=chosen
224+
onChangeRev?.(chosen || null);
225+
}}
226+
// onChange={(e) => setRevIdx(Number(e.target.value))}
195227
>
196228
{revs.map((r, idx) => {
197229
const [verNum, hash] = r.rev.split("-", 2);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Box, Tooltip, ClickAwayListener, TooltipProps } from "@mui/material";
2+
import { useState, PropsWithChildren } from "react";
3+
4+
type ClickTooltipProps = PropsWithChildren<{
5+
title: TooltipProps["title"];
6+
placement?: TooltipProps["placement"];
7+
componentsProps?: TooltipProps["componentsProps"];
8+
}>;
9+
10+
export default function ClickTooltip({
11+
title,
12+
placement = "right",
13+
componentsProps,
14+
children,
15+
}: ClickTooltipProps) {
16+
const [open, setOpen] = useState(false);
17+
const toggle = () => setOpen((o) => !o);
18+
const close = () => setOpen(false);
19+
20+
return (
21+
<ClickAwayListener onClickAway={close}>
22+
<Box sx={{ display: "inline-flex" }}>
23+
<Tooltip
24+
open={open}
25+
onClose={close}
26+
disableFocusListener
27+
disableHoverListener
28+
disableTouchListener
29+
placement={placement}
30+
componentsProps={componentsProps}
31+
title={title}
32+
arrow
33+
>
34+
{/* span to ensure Tooltip always has a single DOM child */}
35+
<span onClick={toggle}>{children}</span>
36+
</Tooltip>
37+
</Box>
38+
</ClickAwayListener>
39+
);
40+
}

src/components/SearchPage/DatabaseCard.tsx

Lines changed: 46 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,18 @@ const DatabaseCard: React.FC<Props> = ({
102102
};
103103

104104
return (
105-
<Card sx={{ mb: 3, position: "relative" }}>
105+
<Card
106+
sx={{
107+
mb: 3,
108+
position: "relative",
109+
transition: "all .2s ease",
110+
borderStyle: "dashed",
111+
borderColor: "divider",
112+
backgroundColor: "#FCFCFF",
113+
boxShadow: 0,
114+
width: { xs: "350px", md: "200px" },
115+
}}
116+
>
106117
<CardContent>
107118
<Box
108119
sx={{
@@ -113,45 +124,44 @@ const DatabaseCard: React.FC<Props> = ({
113124
gap: 2,
114125
}}
115126
>
116-
{/* Logo as Avatar */}
117-
<Box sx={{ display: "flex", alignItems: "center" }}>
118-
{logo && (
119-
<Avatar
120-
variant="square"
121-
src={logo}
122-
alt={fullName || "Database Logo"}
127+
<Box>
128+
<Box sx={{ display: "flex", gap: 1, alignItems: "flex-start" }}>
129+
<Box sx={{ display: "flex", alignItems: "center" }}>
130+
{logo && (
131+
<Avatar
132+
variant="square"
133+
src={logo}
134+
alt={fullName || "Database Logo"}
135+
sx={{
136+
width: 40,
137+
height: 40,
138+
mb: 1,
139+
"& img": {
140+
objectFit: "contain", // show full image inside
141+
},
142+
}}
143+
/>
144+
)}
145+
</Box>
146+
<Typography
123147
sx={{
124-
width: 60,
125-
height: 60,
126-
mb: 1,
127-
"& img": {
128-
objectFit: "contain", // show full image inside
129-
},
148+
fontWeight: 600,
149+
color: Colors.darkPurple,
150+
textDecoration: "none",
151+
":hover": { textDecoration: "underline" },
130152
}}
131-
/>
132-
)}
133-
</Box>
134-
{/* database card */}
135-
<Box>
136-
<Typography
137-
variant="h6"
138-
sx={{
139-
fontWeight: 600,
140-
color: Colors.darkPurple,
141-
textDecoration: "none",
142-
":hover": { textDecoration: "underline" },
143-
}}
144-
component={Link}
145-
to={databaseLink}
146-
target="_blank"
147-
>
148-
Database:{" "}
149-
{highlightKeyword(fullName || "Untitled Database", keyword)}
150-
</Typography>
151-
<Stack spacing={2} margin={1}>
153+
component={Link}
154+
to={databaseLink}
155+
target="_blank"
156+
>
157+
{highlightKeyword(fullName || "Untitled Database", keyword)}
158+
</Typography>
159+
</Box>
160+
161+
<Stack spacing={0.5}>
152162
<Stack
153163
direction="row"
154-
spacing={1}
164+
spacing={0.5}
155165
flexWrap="wrap"
156166
gap={1}
157167
alignItems="center"
@@ -163,32 +173,6 @@ const DatabaseCard: React.FC<Props> = ({
163173
{Array.isArray(modalities) && modalities.length > 0 ? (
164174
modalities.map(renderDatatype)
165175
) : (
166-
// (
167-
// modalities.map((mod, idx) => (
168-
// <Chip
169-
// key={idx}
170-
// label={mod}
171-
// variant="outlined"
172-
// onClick={() => onChipClick("modality", mod)}
173-
// sx={{
174-
// "& .MuiChip-label": {
175-
// paddingX: "6px",
176-
// fontSize: "0.8rem",
177-
// },
178-
// height: "24px",
179-
// color: Colors.darkPurple,
180-
// border: `1px solid ${Colors.darkPurple}`,
181-
// fontWeight: "bold",
182-
// transition: "all 0.2s ease",
183-
// "&:hover": {
184-
// backgroundColor: `${Colors.purple} !important`,
185-
// color: "white",
186-
// borderColor: Colors.purple,
187-
// },
188-
// }}
189-
// />
190-
// ))
191-
// )
192176
<Typography variant="body2" mt={1}>
193177
N/A
194178
</Typography>

0 commit comments

Comments
 (0)