Skip to content

Commit 5e19f9b

Browse files
committed
feat: convert flashcard layout to tab interface for cleaner navigation
1 parent 174269f commit 5e19f9b

File tree

2 files changed

+284
-2
lines changed

2 files changed

+284
-2
lines changed
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
import { Tabs, Tab, Box, Typography } from "@mui/material";
2+
import { Colors } from "design/theme";
3+
import React from "react";
4+
import { useState } from "react";
5+
6+
interface LoadDatasetTabsProps {
7+
pagename: string;
8+
docname: string;
9+
dbname: string;
10+
serverUrl: string;
11+
datasetDocument?: any;
12+
onekey: string;
13+
}
14+
15+
const flashcardStyles = {
16+
container: {
17+
display: "flex",
18+
flexWrap: "wrap",
19+
justifyContent: "space-between",
20+
marginTop: "20px",
21+
gap: "0px",
22+
},
23+
flashcard: {
24+
background: "white",
25+
padding: "15px",
26+
marginBottom: "0px",
27+
borderRadius: "8px",
28+
borderLeft: `5px solid ${Colors.green}`,
29+
// width: "calc(100% - 8px)", // Two per row, tight spacing
30+
width: "100%",
31+
boxSizing: "border-box" as const,
32+
},
33+
flashcardTitle: {
34+
marginTop: 0,
35+
marginBottom: 8,
36+
fontWeight: "bold",
37+
color: Colors.darkPurple,
38+
},
39+
codeBlock: {
40+
display: "block",
41+
background: "#e0e0e0",
42+
// background: Colors.black,
43+
color: Colors.black,
44+
padding: "10px",
45+
borderRadius: "5px",
46+
// fontFamily: "monospace",
47+
whiteSpace: "pre-wrap",
48+
},
49+
};
50+
51+
const LoadDatasetTabs: React.FC<LoadDatasetTabsProps> = ({
52+
pagename,
53+
docname,
54+
dbname,
55+
serverUrl,
56+
datasetDocument,
57+
onekey,
58+
}) => {
59+
const [tabIndex, setTabIndex] = useState(0);
60+
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
61+
setTabIndex(newValue);
62+
};
63+
const datasetDesc = datasetDocument?.["dataset_description.json"];
64+
const datasetName = datasetDesc?.Name?.includes(" - ")
65+
? datasetDesc.Name.split(" - ")[1]
66+
: datasetDesc?.Name || datasetDocument?._id || docname;
67+
const datasetUrl = datasetName
68+
? `${serverUrl}${dbname}/${encodeURIComponent(datasetName)}/`
69+
: `${serverUrl}${dbname}/`;
70+
71+
const TabPanel = ({
72+
children,
73+
value,
74+
index,
75+
}: {
76+
children?: React.ReactNode;
77+
value: number;
78+
index: number;
79+
}) => {
80+
return (
81+
<div role="tabpanel" hidden={value !== index}>
82+
{value === index && <Box sx={{ p: 2 }}>{children}</Box>}
83+
{/* {value === index && (
84+
<Box
85+
sx={{
86+
border: "1px solid #ccc",
87+
borderTop: "none",
88+
borderRadius: "5px 5px 5px 5px",
89+
p: 2,
90+
backgroundColor: "#fff",
91+
borderLeft: `5px solid ${Colors.purple}`,
92+
}}
93+
>
94+
{children}
95+
</Box>
96+
)} */}
97+
</div>
98+
);
99+
};
100+
101+
return (
102+
<>
103+
<Tabs
104+
value={tabIndex}
105+
onChange={handleTabChange}
106+
variant="scrollable"
107+
scrollButtons="auto"
108+
sx={{
109+
"& .MuiTab-root": {
110+
color: Colors.lightGray, // default color
111+
fontSize: "large",
112+
},
113+
"& .Mui-selected": {
114+
color: Colors.green, // active tab color
115+
fontWeight: "bold",
116+
// backgroundColor: Colors.white,
117+
// borderRadius: "5px 5px 0px 0px",
118+
// borderLeft: `5px solid ${Colors.purple}`,
119+
},
120+
"& .MuiTabs-indicator": {
121+
backgroundColor: Colors.green, // underline color
122+
// display: "none",
123+
},
124+
}}
125+
>
126+
<Tab label="Python (REST API)" />
127+
<Tab label="MATLAB (REST API)" />
128+
<Tab label="MATLAB/Octave (Local)" />
129+
<Tab label="Python (Local)" />
130+
<Tab label="C++" />
131+
<Tab label="Node.js" />
132+
</Tabs>
133+
134+
{/* FLASHCARD 1: Python REST API */}
135+
<TabPanel value={tabIndex} index={0}>
136+
<Box style={flashcardStyles.flashcard}>
137+
<Typography variant="h6" style={flashcardStyles.flashcardTitle}>
138+
Load by URL with REST-API in Python
139+
</Typography>
140+
<Typography>Install:</Typography>
141+
<code style={flashcardStyles.codeBlock}>
142+
pip install jdata bjdata numpy
143+
</code>
144+
<Typography>Load from URL:</Typography>
145+
<code style={flashcardStyles.codeBlock}>
146+
{`import jdata as jd
147+
data = jd.loadurl('${datasetUrl}')
148+
149+
# List all externally linked files
150+
links = jd.jsonpath(data, '$.._DataLink_')
151+
152+
# Download & cache anatomical nii.gz data for sub-01/sub-02
153+
jd.jdlink(links, {'regex': 'anat/sub-0[12]_.*\\.nii'})`}
154+
</code>
155+
</Box>
156+
</TabPanel>
157+
158+
{/* FLASHCARD 2: MATLAB REST API */}
159+
<TabPanel value={tabIndex} index={1}>
160+
<Box style={flashcardStyles.flashcard}>
161+
<Typography variant="h6" style={flashcardStyles.flashcardTitle}>
162+
Load by URL with REST-API in MATLAB
163+
</Typography>
164+
<Typography>Install:</Typography>
165+
<code style={flashcardStyles.codeBlock}>
166+
Download and addpath to JSONLab
167+
</code>
168+
<Typography>Load from URL:</Typography>
169+
<code style={flashcardStyles.codeBlock}>
170+
{`data = loadjson('${datasetUrl}');
171+
172+
% or without JSONLab (webread cannot decode JData annotations)
173+
data = webread('${datasetUrl}');
174+
175+
% List all externally linked files
176+
links = jsonpath(data, '$.._DataLink_');
177+
178+
% Download & cache anatomical nii.gz data for sub-01/sub-02
179+
niidata = jdlink(links, 'regex', 'anat/sub-0[12]_.*\\.nii');`}
180+
</code>
181+
</Box>
182+
</TabPanel>
183+
184+
{/* FLASHCARD 3: MATLAB/Octave */}
185+
<TabPanel value={tabIndex} index={2}>
186+
<Box style={flashcardStyles.flashcard}>
187+
<Typography variant="h6" style={flashcardStyles.flashcardTitle}>
188+
Use in MATLAB/Octave
189+
</Typography>
190+
<Typography>Load:</Typography>
191+
<code
192+
style={flashcardStyles.codeBlock}
193+
>{`data = loadjd('${docname}.json');`}</code>
194+
<Typography>Read value:</Typography>
195+
<code
196+
style={flashcardStyles.codeBlock}
197+
>{`data.(encodevarname('${onekey}'))`}</code>
198+
</Box>
199+
</TabPanel>
200+
201+
{/* FLASHCARD 4: Python Local */}
202+
<TabPanel value={tabIndex} index={3}>
203+
<Box style={flashcardStyles.flashcard}>
204+
<Typography variant="h6" style={flashcardStyles.flashcardTitle}>
205+
Use in Python
206+
</Typography>
207+
<Typography>Load:</Typography>
208+
<code style={flashcardStyles.codeBlock}>
209+
{`import jdata as jd
210+
data = jd.load('${docname}.json')`}
211+
</code>
212+
<Typography>Read value:</Typography>
213+
<code style={flashcardStyles.codeBlock}>{`data["${onekey}"]`}</code>
214+
</Box>
215+
</TabPanel>
216+
217+
{/* FLASHCARD 5: C++ */}
218+
<TabPanel value={tabIndex} index={4}>
219+
<Box style={flashcardStyles.flashcard}>
220+
<Typography variant="h6" style={flashcardStyles.flashcardTitle}>
221+
Use in C++
222+
</Typography>
223+
<Typography>Install:</Typography>
224+
<code style={flashcardStyles.codeBlock}>
225+
Download JSON for Modern C++ json.hpp
226+
</code>
227+
<Typography>Load:</Typography>
228+
<code style={flashcardStyles.codeBlock}>
229+
{`#include "json.hpp"
230+
using json=nlohmann::ordered_json;
231+
232+
std::ifstream datafile("${docname}.json");
233+
json data(datafile);`}
234+
</code>
235+
<Typography>Read value:</Typography>
236+
<code
237+
style={flashcardStyles.codeBlock}
238+
>{`std::cout << data["${onekey}"];`}</code>
239+
</Box>
240+
</TabPanel>
241+
242+
{/* FLASHCARD 6: Node.js */}
243+
<TabPanel value={tabIndex} index={5}>
244+
<Box style={flashcardStyles.flashcard}>
245+
<Typography variant="h6" style={flashcardStyles.flashcardTitle}>
246+
Use in JS/Node.js
247+
</Typography>
248+
<Typography>Install:</Typography>
249+
<code style={flashcardStyles.codeBlock}>
250+
npm install jda numjs pako atob
251+
</code>
252+
<Typography>Load:</Typography>
253+
<code style={flashcardStyles.codeBlock}>
254+
{`const fs = require("fs");
255+
const jd = require("jda");
256+
global.atob = require("atob");
257+
258+
const fn = "${docname}.json";
259+
var jstr = fs.readFileSync(fn).toString().replace(/\\n/g, "");
260+
var data = new jd(JSON.parse(jstr));
261+
data = data.decode();`}
262+
</code>
263+
<Typography>Read value:</Typography>
264+
<code
265+
style={flashcardStyles.codeBlock}
266+
>{`console.log(data.data["${onekey}"]);`}</code>
267+
</Box>
268+
</TabPanel>
269+
</>
270+
);
271+
};
272+
273+
export default LoadDatasetTabs;

src/pages/DatasetDetailPage.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
Collapse,
1717
} from "@mui/material";
1818
import { TextField } from "@mui/material";
19+
import LoadDatasetTabs from "components/DatasetDetailPage/LoadDatasetTabs";
1920
import theme, { Colors } from "design/theme";
2021
import { useAppDispatch } from "hooks/useAppDispatch";
2122
import { useAppSelector } from "hooks/useAppSelector";
@@ -949,9 +950,17 @@ const DatasetDetailPage: React.FC = () => {
949950
</Box>
950951
{/* ✅ ADD FLASHCARDS COMPONENT HERE ✅ */}
951952

952-
<div id="chartpanel"></div>
953+
{/* <div id="chartpanel"></div> */}
954+
<Box
955+
sx={{
956+
borderBottom: `1px solid ${Colors.lightGray}`,
957+
marginTop: 4,
958+
marginBottom: 3,
959+
}}
960+
></Box>
953961

954-
<DatasetFlashcards
962+
{/* <DatasetFlashcards */}
963+
<LoadDatasetTabs
955964
pagename={docId ?? ""}
956965
docname={datasetDocument?.Name || ""}
957966
dbname={dbName || ""}

0 commit comments

Comments
 (0)