From 288b1b4a74fe896acb770a48ce8e3a14d48f20d6 Mon Sep 17 00:00:00 2001 From: MarSHub Date: Thu, 27 Feb 2025 13:04:40 -0600 Subject: [PATCH 01/20] Update branch Fan --- src/pages/DatasetDetailPage.tsx | 257 +++++++++++++----------- src/redux/neurojson/neurojson.action.ts | 6 - src/services/neurojson.service.ts | 2 - 3 files changed, 143 insertions(+), 122 deletions(-) diff --git a/src/pages/DatasetDetailPage.tsx b/src/pages/DatasetDetailPage.tsx index 604f5f0..5c9bebf 100644 --- a/src/pages/DatasetDetailPage.tsx +++ b/src/pages/DatasetDetailPage.tsx @@ -1,3 +1,5 @@ +import ExpandLess from "@mui/icons-material/ExpandLess"; +import ExpandMore from "@mui/icons-material/ExpandMore"; import { Box, Typography, @@ -6,6 +8,7 @@ import { Button, Card, CardContent, + Collapse, } from "@mui/material"; import theme, { Colors } from "design/theme"; import { useAppDispatch } from "hooks/useAppDispatch"; @@ -33,6 +36,7 @@ const DatasetDetailPage: React.FC = () => { error, } = useAppSelector(NeurojsonSelector); const [externalLinks, setExternalLinks] = useState([]); + const [isExpanded, setIsExpanded] = useState(false); // Recursive function to find `_DataLink_` const extractDataLinks = (obj: any, path: string): ExternalDataLink[] => { @@ -150,145 +154,170 @@ const DatasetDetailPage: React.FC = () => { )} - {externalLinks.length > 0 && ( - - External Data ({externalLinks.length} links) - setIsExpanded(!isExpanded)} sx={{ - backgroundColor: Colors.white, - border: `1px solid ${Colors.lightGray}`, - borderRadius: "8px", - padding: 2, - boxShadow: "0px 2px 4px rgba(0,0,0,0.05)", + display: "flex", + alignItems: "center", + cursor: "pointer", + marginBottom: 2, }} > + + External Data ({externalLinks.length} links) + + {isExpanded ? : } + + + - - - Total Size:{" "} - {externalLinks - .reduce((acc, link) => { - const sizeMatch = link.size.match(/(\d+(\.\d+)?)/); - const sizeInMB = sizeMatch ? parseFloat(sizeMatch[1]) : 0; - return acc + sizeInMB; - }, 0) - .toFixed(2)}{" "} - MB - - - - - {externalLinks.map((link, index) => ( - + externalLinks.forEach((link) => + window.open(link.url, "_blank") + ) + } > - - - {link.name} - - - Size: {link.size} - - - - - - + + + {link.name} + + + Size: {link.size} + + + + + + + + ))} - ))} + - + )} diff --git a/src/redux/neurojson/neurojson.action.ts b/src/redux/neurojson/neurojson.action.ts index 8ea837c..c4f86dd 100644 --- a/src/redux/neurojson/neurojson.action.ts +++ b/src/redux/neurojson/neurojson.action.ts @@ -29,11 +29,8 @@ export const loadPaginatedData = createAsyncThunk( { rejectWithValue, dispatch, getState } ) => { try { - // Get current state const state = getState() as any; const currentData = state.neurojson.data; - - // If there is data and dbName changed, reset data first if (currentData.length > 0 && currentData[0]?.dbName !== dbName) { dispatch({ type: "neurojson/resetData" }); } @@ -48,7 +45,6 @@ export const loadPaginatedData = createAsyncThunk( return rejectWithValue("No more data to load."); } - // Add dbName to each row for tracking response.rows = response.rows.map((row) => ({ ...row, dbName, @@ -81,10 +77,8 @@ export const fetchDocumentDetails = createAsyncThunk( ) => { try { const data = await NeurojsonService.getDocumentById(dbName, docId); - console.log(data); return data; } catch (error: any) { - console.error("Failed to fetch document details:", error); return rejectWithValue("Failed to fetch document details."); } } diff --git a/src/services/neurojson.service.ts b/src/services/neurojson.service.ts index 28aa562..a3a95cb 100644 --- a/src/services/neurojson.service.ts +++ b/src/services/neurojson.service.ts @@ -29,9 +29,7 @@ export const NeurojsonService = { }, getDocumentById: async (dbName: string, documentId: string): Promise => { try { - console.log(`${baseURL}/${dbName}/${documentId}`); const response = await api.get(`${baseURL}/${dbName}/${documentId}`); - console.log(response.data); return response.data; } catch (error) { console.error( From c82a6245c08b77468f1663552688c1f0ea123dc8 Mon Sep 17 00:00:00 2001 From: MarSHub Date: Thu, 27 Feb 2025 13:09:38 -0600 Subject: [PATCH 02/20] Manual deployment --- .github/workflows/build-deploy-zodiac.yml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build-deploy-zodiac.yml b/.github/workflows/build-deploy-zodiac.yml index 8a157fe..4c7f7bd 100644 --- a/.github/workflows/build-deploy-zodiac.yml +++ b/.github/workflows/build-deploy-zodiac.yml @@ -24,13 +24,16 @@ jobs: - name: Determine Branch Name id: get_branch - run: echo "branch_name=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV - - - name: Copy files to the server via SFTP - uses: wlixcc/SFTP-Deploy-Action@v1.2.4 - with: - server: ${{ secrets.NEUROJ_SERVER }} - username: ${{ secrets.NEUROJ_SERVER_USER }} - ssh_private_key: ${{ secrets.NEUROJ_SERVER_SSH_KEY }} - local_path: "./build/*" - remote_path: "/var/www/html/dev/${{ env.branch_name }}/" + run: echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV + + - name: Copy files to the server via SCP + run: | + echo "Deploying to /var/www/html/dev/${{ env.BRANCH_NAME }}/" + scp -r -o StrictHostKeyChecking=no ./build/* ${{ secrets.NEUROJ_SERVER_USER }}@${{ secrets.NEUROJ_SERVER }}:/var/www/html/dev/${{ env.BRANCH_NAME }}/ + + - name: Restart Server (Only in the deployed folder) + run: | + echo "Restarting services in /var/www/html/dev/${{ env.BRANCH_NAME }}/" + ssh -o StrictHostKeyChecking=no ${{ secrets.NEUROJ_SERVER_USER }}@${{ secrets.NEUROJ_SERVER }} << EOF + cd /var/www/html/dev/${{ env.BRANCH_NAME }}/ && pm2 restart all || echo "No PM2 processes found in this directory" + EOF From ff3dd40c5a4db376d2bc92c6d794176f1c1c4f29 Mon Sep 17 00:00:00 2001 From: MarSHub Date: Thu, 27 Feb 2025 13:12:02 -0600 Subject: [PATCH 03/20] Manual deployment --- .github/workflows/netlify-deploy.yml | 32 ---------------------------- 1 file changed, 32 deletions(-) delete mode 100644 .github/workflows/netlify-deploy.yml diff --git a/.github/workflows/netlify-deploy.yml b/.github/workflows/netlify-deploy.yml deleted file mode 100644 index 85124b9..0000000 --- a/.github/workflows/netlify-deploy.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Deploy to Netlify (dev branch) - -on: - push: - branches: - - dev # Trigger only on pushes to the 'dev' branch - -jobs: - deploy: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Install Node.js - uses: actions/setup-node@v3 - with: - node-version: "22" - - - name: Install dependencies - run: npm install - - - name: Build project - run: npm run build # Update this command if your build script is different - - - name: Deploy to Netlify - uses: netlify/actions-cli@v3 - with: - auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} - site-id: ${{ secrets.NETLIFY_SITE_ID }} - deploy-dir: build # Adjust this if your build output folder is different From eee772a00627b3649eec60145fb200afe613734b Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Mon, 3 Mar 2025 13:50:23 -0500 Subject: [PATCH 04/20] change the background of landing page --- src/design/Layouts/FullScreen.tsx | 10 +++++++--- src/design/theme.ts | 5 +++++ src/pages/Home.tsx | 8 ++++---- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/design/Layouts/FullScreen.tsx b/src/design/Layouts/FullScreen.tsx index d8d15ae..601f790 100644 --- a/src/design/Layouts/FullScreen.tsx +++ b/src/design/Layouts/FullScreen.tsx @@ -17,7 +17,7 @@ const FullScreen = () => { maxWidth: "100vw", width: "100%", overflowX: "hidden", - backgroundColor: Colors.primary.main, + backgroundColor: `${Colors.darkpurple}`, transition: "background 0.3s ease-in-out", backdropFilter: "blur(2.5px)", borderBottom: `2px solid ${Colors.primary.dark}`, @@ -42,7 +42,7 @@ const FullScreen = () => { }} onClick={() => navigate("/")} > - + NeuroJSON.io Free Data Worth Sharing @@ -99,6 +99,7 @@ const FullScreen = () => { lineHeight={"1.5rem"} letterSpacing={"0.05rem"} sx={{ + color: Colors.white, transition: "color 0.3s ease, transform 0.3s ease", "&:hover": { color: Colors.white, @@ -121,7 +122,10 @@ const FullScreen = () => { height: "calc(100vh - 6rem)", boxSizing: "border-box", marginTop: "6rem", - backgroundColor: Colors.lightGray, + // backgroundColor: Colors.lightGray, + backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 1500'%3E%3Cdefs%3E%3CradialGradient id='a' gradientUnits='objectBoundingBox'%3E%3Cstop offset='0' stop-color='%23000000'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/radialGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='0' y1='750' x2='1550' y2='750'%3E%3Cstop offset='0' stop-color='%232c3379'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/linearGradient%3E%3Cpath id='s' fill='url(%23b)' d='M1549.2 51.6c-5.4 99.1-20.2 197.6-44.2 293.6c-24.1 96-57.4 189.4-99.3 278.6c-41.9 89.2-92.4 174.1-150.3 253.3c-58 79.2-123.4 152.6-195.1 219c-71.7 66.4-149.6 125.8-232.2 177.2c-82.7 51.4-170.1 94.7-260.7 129.1c-90.6 34.4-184.4 60-279.5 76.3C192.6 1495 96.1 1502 0 1500c96.1-2.1 191.8-13.3 285.4-33.6c93.6-20.2 185-49.5 272.5-87.2c87.6-37.7 171.3-83.8 249.6-137.3c78.4-53.5 151.5-114.5 217.9-181.7c66.5-67.2 126.4-140.7 178.6-218.9c52.3-78.3 96.9-161.4 133-247.9c36.1-86.5 63.8-176.2 82.6-267.6c18.8-91.4 28.6-184.4 29.6-277.4c0.3-27.6 23.2-48.7 50.8-48.4s49.5 21.8 49.2 49.5c0 0.7 0 1.3-0.1 2L1549.2 51.6z'/%3E%3Cg id='g'%3E%3Cuse href='%23s' transform='scale(0.12) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.2) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.25) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(0.3) rotate(-20)'/%3E%3Cuse href='%23s' transform='scale(0.4) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(0.5) rotate(20)'/%3E%3Cuse href='%23s' transform='scale(0.6) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.7) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.835) rotate(-40)'/%3E%3Cuse href='%23s' transform='scale(0.9) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(1.05) rotate(25)'/%3E%3Cuse href='%23s' transform='scale(1.2) rotate(8)'/%3E%3Cuse href='%23s' transform='scale(1.333) rotate(-60)'/%3E%3Cuse href='%23s' transform='scale(1.45) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(1.6) rotate(10)'/%3E%3C/g%3E%3C/defs%3E%3Cg transform='translate(400 0)'%3E%3Cg transform='translate(0 375)'%3E%3Ccircle fill='url(%23a)' r='3000'/%3E%3Cg opacity='0.5'%3E%3Ccircle fill='url(%23a)' r='2000'/%3E%3Ccircle fill='url(%23a)' r='1800'/%3E%3Ccircle fill='url(%23a)' r='1700'/%3E%3Ccircle fill='url(%23a)' r='1651'/%3E%3Ccircle fill='url(%23a)' r='1450'/%3E%3Ccircle fill='url(%23a)' r='1250'/%3E%3Ccircle fill='url(%23a)' r='1175'/%3E%3Ccircle fill='url(%23a)' r='900'/%3E%3Ccircle fill='url(%23a)' r='750'/%3E%3Ccircle fill='url(%23a)' r='500'/%3E%3Ccircle fill='url(%23a)' r='380'/%3E%3Ccircle fill='url(%23a)' r='250'/%3E%3C/g%3E%3Cg transform='rotate(-273.6 0 0)'%3E%3Cuse href='%23g' transform='rotate(10)'/%3E%3Cuse href='%23g' transform='rotate(120)'/%3E%3Cuse href='%23g' transform='rotate(240)'/%3E%3C/g%3E%3Ccircle fill-opacity='0.99' fill='url(%23a)' r='3000'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`, + backgroundAttachment: "fixed", + backgroundSize: "cover", overflow: "auto", }} > diff --git a/src/design/theme.ts b/src/design/theme.ts index 5d507ce..3824dc6 100644 --- a/src/design/theme.ts +++ b/src/design/theme.ts @@ -1,3 +1,4 @@ +import { purple } from "@mui/material/colors"; import { createTheme } from "@mui/material/styles"; const primary = { @@ -22,6 +23,10 @@ export const Colors = { error: "#D9534F", textPrimary: "#212121", textSecondary: "#494747", + green: "#02DEC4", + yellow: "#FFDD31", + purple: "#5865F2", + darkpurple: "#282C56", primary, secondary, }; diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 1103dc5..fc21435 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -77,7 +77,7 @@ const Home: React.FC = () => { position: "absolute", top: "6%", left: "5%", - backgroundColor: "rgba(255, 255, 255, 0.8)", + backgroundColor: "none", padding: "1.5rem", borderRadius: "8px", boxShadow: "0 4px 8px rgba(0, 0, 0, 0.1)", @@ -87,11 +87,11 @@ const Home: React.FC = () => { Discover NeuroJSON IO - + Efficiently manage and explore your CouchDB databases and datasets with ease. @@ -101,7 +101,7 @@ const Home: React.FC = () => { - - {[ - { text: "Mission", url: "https://neurojson.org/Doc/Start" }, - { - text: "Get Started", - url: "https://neurojson.org/Doc/Start/User", - }, - { - text: "Contribute", - url: "https://neurojson.org/Doc/Start/Contributor", - }, - { text: "Tools", url: "https://neurojson.org/#software" }, - { text: "Search", url: null }, - { - text: "Forum", - url: "https://github.com/orgs/NeuroJSON/discussions", - }, - { text: "About", url: "https://neurojson.org/#people" }, + {/* Navigation links*/} + + + {[ + { text: "ABOUT", url: "https://neurojson.org/Doc/Start" }, + { text: "WIKI", url: "https://neurojson.org/Wiki" }, + { text: "SEARCH", url: null }, + ].map(({ text, url }) => ( + + {url ? ( + + + {text} + + + ) : ( + + {text} + + )} + + ))} + + + {/* {[ + // { text: "Mission", url: "https://neurojson.org/Doc/Start" }, + // { + // text: "Get Started", + // url: "https://neurojson.org/Doc/Start/User", + // }, + // { + // text: "Contribute", + // url: "https://neurojson.org/Doc/Start/Contributor", + // }, + // { text: "Tools", url: "https://neurojson.org/#software" }, + { text: "ABOUT", url: "https://neurojson.org/Doc/Start" }, + { text: "WIKI", url: "https://neurojson.org/Wiki"}, + { text: "SEARCH", url: null } + // { + // text: "Forum", + // url: "https://github.com/orgs/NeuroJSON/discussions", + // } ].map(({ text, url }) => ( {url ? ( @@ -81,11 +151,14 @@ const FullScreen = () => { lineHeight={"1.5rem"} letterSpacing={"0.05rem"} sx={{ + color: Colors.white, transition: "color 0.3s ease, transform 0.3s ease", "&:hover": { - color: Colors.white, + color: Colors.green, transform: "scale(1.05)", cursor: "pointer", + boxShadow: `0px 0px 15px ${Colors.green}`, + borderRadius: "5px", }, }} > @@ -102,9 +175,11 @@ const FullScreen = () => { color: Colors.white, transition: "color 0.3s ease, transform 0.3s ease", "&:hover": { - color: Colors.white, + color: Colors.green, transform: "scale(1.05)", cursor: "pointer", + boxShadow: `0px 0px 15px ${Colors.green}`, + borderRadius: "5px", }, }} > @@ -112,7 +187,7 @@ const FullScreen = () => { )} - ))} + ))} */} @@ -122,7 +197,6 @@ const FullScreen = () => { height: "calc(100vh - 6rem)", boxSizing: "border-box", marginTop: "6rem", - // backgroundColor: Colors.lightGray, backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 1500'%3E%3Cdefs%3E%3CradialGradient id='a' gradientUnits='objectBoundingBox'%3E%3Cstop offset='0' stop-color='%23000000'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/radialGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='0' y1='750' x2='1550' y2='750'%3E%3Cstop offset='0' stop-color='%232c3379'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/linearGradient%3E%3Cpath id='s' fill='url(%23b)' d='M1549.2 51.6c-5.4 99.1-20.2 197.6-44.2 293.6c-24.1 96-57.4 189.4-99.3 278.6c-41.9 89.2-92.4 174.1-150.3 253.3c-58 79.2-123.4 152.6-195.1 219c-71.7 66.4-149.6 125.8-232.2 177.2c-82.7 51.4-170.1 94.7-260.7 129.1c-90.6 34.4-184.4 60-279.5 76.3C192.6 1495 96.1 1502 0 1500c96.1-2.1 191.8-13.3 285.4-33.6c93.6-20.2 185-49.5 272.5-87.2c87.6-37.7 171.3-83.8 249.6-137.3c78.4-53.5 151.5-114.5 217.9-181.7c66.5-67.2 126.4-140.7 178.6-218.9c52.3-78.3 96.9-161.4 133-247.9c36.1-86.5 63.8-176.2 82.6-267.6c18.8-91.4 28.6-184.4 29.6-277.4c0.3-27.6 23.2-48.7 50.8-48.4s49.5 21.8 49.2 49.5c0 0.7 0 1.3-0.1 2L1549.2 51.6z'/%3E%3Cg id='g'%3E%3Cuse href='%23s' transform='scale(0.12) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.2) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.25) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(0.3) rotate(-20)'/%3E%3Cuse href='%23s' transform='scale(0.4) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(0.5) rotate(20)'/%3E%3Cuse href='%23s' transform='scale(0.6) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.7) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.835) rotate(-40)'/%3E%3Cuse href='%23s' transform='scale(0.9) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(1.05) rotate(25)'/%3E%3Cuse href='%23s' transform='scale(1.2) rotate(8)'/%3E%3Cuse href='%23s' transform='scale(1.333) rotate(-60)'/%3E%3Cuse href='%23s' transform='scale(1.45) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(1.6) rotate(10)'/%3E%3C/g%3E%3C/defs%3E%3Cg transform='translate(400 0)'%3E%3Cg transform='translate(0 375)'%3E%3Ccircle fill='url(%23a)' r='3000'/%3E%3Cg opacity='0.5'%3E%3Ccircle fill='url(%23a)' r='2000'/%3E%3Ccircle fill='url(%23a)' r='1800'/%3E%3Ccircle fill='url(%23a)' r='1700'/%3E%3Ccircle fill='url(%23a)' r='1651'/%3E%3Ccircle fill='url(%23a)' r='1450'/%3E%3Ccircle fill='url(%23a)' r='1250'/%3E%3Ccircle fill='url(%23a)' r='1175'/%3E%3Ccircle fill='url(%23a)' r='900'/%3E%3Ccircle fill='url(%23a)' r='750'/%3E%3Ccircle fill='url(%23a)' r='500'/%3E%3Ccircle fill='url(%23a)' r='380'/%3E%3Ccircle fill='url(%23a)' r='250'/%3E%3C/g%3E%3Cg transform='rotate(-273.6 0 0)'%3E%3Cuse href='%23g' transform='rotate(10)'/%3E%3Cuse href='%23g' transform='rotate(120)'/%3E%3Cuse href='%23g' transform='rotate(240)'/%3E%3C/g%3E%3Ccircle fill-opacity='0.99' fill='url(%23a)' r='3000'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`, backgroundAttachment: "fixed", backgroundSize: "cover", diff --git a/src/design/theme.ts b/src/design/theme.ts index 3824dc6..8f160cf 100644 --- a/src/design/theme.ts +++ b/src/design/theme.ts @@ -1,4 +1,4 @@ -import { purple } from "@mui/material/colors"; +import { orange, purple } from "@mui/material/colors"; import { createTheme } from "@mui/material/styles"; const primary = { @@ -24,9 +24,12 @@ export const Colors = { textPrimary: "#212121", textSecondary: "#494747", green: "#02DEC4", + darkgreen: "#49c6ae", yellow: "#FFDD31", purple: "#5865F2", darkpurple: "#282C56", + orange: "#FF9F2F", + darkorange: "#E88C25", primary, secondary, }; diff --git a/src/hooks/useIsLargeScreen.ts b/src/hooks/useIsLargeScreen.ts index 1e2b034..96c093e 100644 --- a/src/hooks/useIsLargeScreen.ts +++ b/src/hooks/useIsLargeScreen.ts @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react'; + const useIsLargeScreen = () => { const [isLargeScreen, setIsLargeScreen] = useState(false); diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index fc21435..cc0c0ae 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -103,8 +103,10 @@ const Home: React.FC = () => { sx={{ backgroundColor: Colors.green, color: Colors.white, + fontWeight: "Bold", "&:hover": { - backgroundColor: Colors.primary.dark, + backgroundColor: Colors.darkgreen, + boxShadow: `0px 0px 15px ${Colors.green}` }, }} onClick={() => navigate("/databases")} From 4bd315b709237fa1e6a15c6da15b2233f686cd66 Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Tue, 4 Mar 2025 17:55:09 -0500 Subject: [PATCH 06/20] Add Raleway and Ubuntu fonts, and update typography settings --- public/index.html | 18 +- src/components/NodeInfoPanel.tsx | 500 ++++++++++++++++++------------ src/design/Layouts/FullScreen.tsx | 337 +++++++++----------- src/design/theme.ts | 112 +++---- src/pages/Home.tsx | 2 +- 5 files changed, 505 insertions(+), 464 deletions(-) diff --git a/public/index.html b/public/index.html index 40bc154..113fd2f 100644 --- a/public/index.html +++ b/public/index.html @@ -2,17 +2,14 @@ - + - + + + - + + NeuroJSON.io - Free Data Worth Sharing diff --git a/src/components/NodeInfoPanel.tsx b/src/components/NodeInfoPanel.tsx index 737e811..a7e52c3 100644 --- a/src/components/NodeInfoPanel.tsx +++ b/src/components/NodeInfoPanel.tsx @@ -1,35 +1,44 @@ -import React, { useEffect, useRef } from "react"; // add useRef -import { Box, Typography, IconButton, Drawer, Grid, Card, CardContent, CardActions, Button } from "@mui/material"; import CloseIcon from "@mui/icons-material/Close"; -import { NodeObject } from "modules/universe/NeuroJsonGraph"; -import { Colors} from "design/theme"; -import { useNavigate } from "react-router-dom"; +import { + Box, + Typography, + IconButton, + Drawer, + Grid, + Card, + CardContent, + CardActions, + Button, +} from "@mui/material"; +import { Colors } from "design/theme"; import { useAppDispatch } from "hooks/useAppDispatch"; import { useAppSelector } from "hooks/useAppSelector"; -import { RootState } from "redux/store"; +import { NodeObject } from "modules/universe/NeuroJsonGraph"; +import React, { useEffect, useRef } from "react"; +import { useNavigate } from "react-router-dom"; import { fetchDbInfo } from "redux/neurojson/neurojson.action"; - +import { RootState } from "redux/store"; interface NodeInfoPanelProps { - open: boolean; - onClose: () => void; - nodeData: NodeObject | null; + open: boolean; + onClose: () => void; + nodeData: NodeObject | null; } // helper functions // covert the database size format -const formatSize = (bytes?: number): string =>{ - if (bytes === undefined) return "N/A"; - if (bytes >= 1_073_741_824) { - return `${Math.floor(bytes / 1_073_741_824)} Gb`; - } else if (bytes >= 1_048_576) { - return `${Math.floor(bytes / 1_048_576)} Mb`; - } else if (bytes >= 1024) { - return `${Math.floor(bytes / 1024)} Kb`; - } else { - return `${bytes} Bytes`; - } +const formatSize = (bytes?: number): string => { + if (bytes === undefined) return "N/A"; + if (bytes >= 1_073_741_824) { + return `${Math.floor(bytes / 1_073_741_824)} Gb`; + } else if (bytes >= 1_048_576) { + return `${Math.floor(bytes / 1_048_576)} Mb`; + } else if (bytes >= 1024) { + return `${Math.floor(bytes / 1024)} Kb`; + } else { + return `${bytes} Bytes`; + } }; // 1 Kilobyte (KB) = 1,024 Bytes // 1 Megabyte (MB) = 1,024 KB = 1,048,576 Bytes (1024*1024) @@ -37,205 +46,288 @@ const formatSize = (bytes?: number): string =>{ // convert the date format const dateCoverter = (date?: string): string => { - if (date === undefined) return "N/A"; - const newDate = new Date(Number(date) * 1000); - const result = new Intl.DateTimeFormat("en-US", { - year: "numeric", - month: "numeric", - day: "numeric", - hour: "numeric", - minute: "numeric", - second: "numeric" - }).format(newDate); - return result; -} + if (date === undefined) return "N/A"; + const newDate = new Date(Number(date) * 1000); + const result = new Intl.DateTimeFormat("en-US", { + year: "numeric", + month: "numeric", + day: "numeric", + hour: "numeric", + minute: "numeric", + second: "numeric", + }).format(newDate); + return result; +}; + +const NodeInfoPanel: React.FC = ({ + open, + onClose, + nodeData, +}) => { + const navigate = useNavigate(); + const dispatch = useAppDispatch(); + const dbInfo = useAppSelector((state: RootState) => state.neurojson.dbInfo); + // const drawerRef = useRef(null); // Reference to the Drawer content + // const loading = useAppSelector((state: RootState) => state.neurojson.loading); -const NodeInfoPanel: React.FC = ({ open, onClose, nodeData }) => { - const navigate = useNavigate(); - const dispatch = useAppDispatch(); - const dbInfo = useAppSelector((state: RootState) => state.neurojson.dbInfo); - // const drawerRef = useRef(null); // Reference to the Drawer content - // const loading = useAppSelector((state: RootState) => state.neurojson.loading); - + useEffect(() => { + if (nodeData?.id) { + dispatch(fetchDbInfo(nodeData.id.toLowerCase())); + } + }, [nodeData, dispatch]); + + return ( + + + {nodeData ? ( + <> + {/* Close Button */} + + + {nodeData.name} + + + + + + {/* Node Metadata */} + + + + Website + + + + {nodeData.url} + + + - useEffect(() => { - if (nodeData?.id) { - dispatch(fetchDbInfo(nodeData.id.toLowerCase())); - } - }, [nodeData, dispatch]); + + + Number of Datasets + + + {nodeData.datasets} + + - + + + Data Types + + + {nodeData.datatype.join(", ")} + + - return ( - - - {nodeData? ( - <> - {/* Close Button */} - - {nodeData.name} - - - - - {/* Node Metadata */} - + + + Data Standards + + + {nodeData.standard.join(", ")} + + + + + + Upstream Contact + + + + {nodeData.support} + + + + + + + NeuroJSON-Cuated Datasets + + {dbInfo ? ( + + {dbInfo.doc_count - 1} + + ) : ( + "Coming soon " + )} + + + {/*database info card*/} + {dbInfo ? ( + + + - Website - - {nodeData.url} - + + NeuroJSON.io Database Name + + {dbInfo.db_name} - - Number of Datasets - {nodeData.datasets} + + REST-API URL + + + {`https://neurojson.io:7777/${dbInfo.db_name}`} + - - Data Types - {nodeData.datatype.join(", ")} + + Database Creation Time + + + {dateCoverter(dbInfo.instance_start_time)} + - - Data Standards - {nodeData.standard.join(", ")} + + Searchable Database Size + + + {formatSize(dbInfo.sizes?.external)} + - - Upstream Contact - - {nodeData.support} - + + DatabaseDisk Size (compressed) + + {formatSize(dbInfo.sizes?.file)} - + + + + - NeuroJSON-Cuated Datasets - {dbInfo?({dbInfo.doc_count - 1}) : "Coming soon "} + - - {/*database info card*/} - {dbInfo? ( - - - - - NeuroJSON.io Database Name - {dbInfo.db_name} - - - REST-API URL - - {`https://neurojson.io:7777/${dbInfo.db_name}`} - - - - Database Creation Time - {dateCoverter(dbInfo.instance_start_time)} - - - Searchable Database Size - {formatSize(dbInfo.sizes?.external)} - - - DatabaseDisk Size (compressed) - {formatSize(dbInfo.sizes?.file)} - - - - - - - - - - - - - - - - - - - - - - ) : ( - Select a node to see database info. - )} - - - ) : ( - Select a node to see database info. - )} - - - ) + + + + + + + + + + + + + ) : ( + Select a node to see database info. + )} + + ) : ( + Select a node to see database info. + )} + + + ); }; export default NodeInfoPanel; diff --git a/src/design/Layouts/FullScreen.tsx b/src/design/Layouts/FullScreen.tsx index 7299aad..1ad3372 100644 --- a/src/design/Layouts/FullScreen.tsx +++ b/src/design/Layouts/FullScreen.tsx @@ -4,209 +4,148 @@ import useIsLargeScreen from "hooks/useIsLargeScreen"; import { Outlet, useNavigate } from "react-router-dom"; const FullScreen = () => { - const isLargeScreen = useIsLargeScreen(); - const navigate = useNavigate(); + const isLargeScreen = useIsLargeScreen(); + const navigate = useNavigate(); - // const justifyContentValue = isLargeScreen ? "flex-start" : "space-between"; - const justifyContentValue = isLargeScreen ? "space-between" : "center"; + const justifyContentValue = isLargeScreen ? "flex-start" : "space-between"; - return ( - <> - - - - - - - {/* Navigation links*/} - - - {[ - { text: "ABOUT", url: "https://neurojson.org/Doc/Start" }, - { text: "WIKI", url: "https://neurojson.org/Wiki" }, - { text: "SEARCH", url: null }, + return ( + <> + + + + + + + {/* Navigation links*/} + + + {[ + { text: "ABOUT", url: "https://neurojson.org/Doc/Start" }, + { text: "WIKI", url: "https://neurojson.org/Wiki" }, + { text: "SEARCH", url: null }, ].map(({ text, url }) => ( - - {url ? ( - - - {text} - - - ) : ( - - {text} - - )} - + + {url ? ( + + + {text} + + + ) : ( + + {text} + + )} + ))} - - - {/* {[ - // { text: "Mission", url: "https://neurojson.org/Doc/Start" }, - // { - // text: "Get Started", - // url: "https://neurojson.org/Doc/Start/User", - // }, - // { - // text: "Contribute", - // url: "https://neurojson.org/Doc/Start/Contributor", - // }, - // { text: "Tools", url: "https://neurojson.org/#software" }, - { text: "ABOUT", url: "https://neurojson.org/Doc/Start" }, - { text: "WIKI", url: "https://neurojson.org/Wiki"}, - { text: "SEARCH", url: null } - // { - // text: "Forum", - // url: "https://github.com/orgs/NeuroJSON/discussions", - // } - ].map(({ text, url }) => ( - - {url ? ( - - - {text} - - - ) : ( - - {text} - - )} - - ))} */} - - - - - - - - ); + + + + + + + + + + ); }; export default FullScreen; diff --git a/src/design/theme.ts b/src/design/theme.ts index 8f160cf..3e98133 100644 --- a/src/design/theme.ts +++ b/src/design/theme.ts @@ -2,69 +2,73 @@ import { orange, purple } from "@mui/material/colors"; import { createTheme } from "@mui/material/styles"; const primary = { - dark: "#5c6386", - main: "#7b81a5", - light: "#a0a5c2", + dark: "#5c6386", + main: "#7b81a5", + light: "#a0a5c2", }; const secondary = { - dark: "#374056", - main: "#48556B", - light: "#7487a0", + dark: "#374056", + main: "#48556B", + light: "#7487a0", }; export const Colors = { - white: "#FFFFFF", - black: "#000000", - lightGray: "#f2f2f2", - darkGray: "#4A4A4A", - accent: "#D5A021", - success: "#03BB50", - error: "#D9534F", - textPrimary: "#212121", - textSecondary: "#494747", - green: "#02DEC4", - darkgreen: "#49c6ae", - yellow: "#FFDD31", - purple: "#5865F2", - darkpurple: "#282C56", - orange: "#FF9F2F", - darkorange: "#E88C25", - primary, - secondary, + white: "#FFFFFF", + black: "#000000", + lightGray: "#f2f2f2", + darkGray: "#4A4A4A", + accent: "#D5A021", + success: "#03BB50", + error: "#D9534F", + textPrimary: "#212121", + textSecondary: "#494747", + green: "#02DEC4", + darkgreen: "#49c6ae", + yellow: "#FFDD31", + purple: "#5865F2", + darkpurple: "#282C56", + orange: "#FF9F2F", + darkorange: "#E88C25", + primary, + secondary, }; const theme = createTheme({ - typography: { - fontFamily: [ - '"IBM Plex Sans"', - "-apple-system", - "BlinkMacSystemFont", - '"Segoe UI"', - "Roboto", - '"Helvetica Neue"', - "Arial", - "sans-serif", - ].join(","), - h1: { - fontWeight: 700, - fontSize: "2rem", - color: Colors.primary.dark, - }, - h2: { - fontWeight: 600, - fontSize: "1.75rem", - color: Colors.secondary.main, - }, - body1: { - fontSize: "1rem", - color: Colors.textPrimary, - }, - body2: { - fontSize: "0.875rem", - color: Colors.textSecondary, - }, - }, + typography: { + fontFamily: [ + "Raleway", + "Ubuntu", + '"IBM Plex Sans"', + "-apple-system", + "BlinkMacSystemFont", + '"Segoe UI"', + "Roboto", + '"Helvetica Neue"', + "Arial", + "sans-serif", + ].join(","), + h1: { + fontFamily: "Raleway", + fontWeight: 700, + fontSize: "2rem", + color: Colors.yellow, + textTransform: "none", + }, + h2: { + fontWeight: 600, + fontSize: "1.75rem", + color: Colors.secondary.main, + }, + body1: { + fontSize: "1rem", + color: Colors.textPrimary, + }, + body2: { + fontSize: "0.875rem", + color: Colors.textSecondary, + }, + }, }); export default theme; diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index cc0c0ae..5699972 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -89,7 +89,7 @@ const Home: React.FC = () => { gutterBottom sx={{ color: Colors.white }} > - Discover NeuroJSON IO + Discover NeuroJSON.io Efficiently manage and explore your CouchDB databases and datasets From cbc3f01d2715671b67c4580fc16fd8dec1e15a0f Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Wed, 5 Mar 2025 16:37:18 -0500 Subject: [PATCH 07/20] Assign distinct colors to different datatypes and update node color rendering --- src/components/NodeInfoPanel.tsx | 18 +- src/design/Layouts/FullScreen.tsx | 8 +- src/design/theme.ts | 9 +- src/modules/universe/NeuroJsonGraph.tsx | 424 +++++++++-------- src/pages/DatabasePage.tsx | 172 +++---- src/pages/DatasetPage.tsx | 582 ++++++++++++------------ src/pages/Home.tsx | 204 ++++----- 7 files changed, 740 insertions(+), 677 deletions(-) diff --git a/src/components/NodeInfoPanel.tsx b/src/components/NodeInfoPanel.tsx index a7e52c3..7c1ee7d 100644 --- a/src/components/NodeInfoPanel.tsx +++ b/src/components/NodeInfoPanel.tsx @@ -191,7 +191,7 @@ const NodeInfoPanel: React.FC = ({ NeuroJSON.io Database Name @@ -199,7 +199,7 @@ const NodeInfoPanel: React.FC = ({ REST-API URL @@ -217,7 +217,7 @@ const NodeInfoPanel: React.FC = ({ Database Creation Time @@ -227,7 +227,7 @@ const NodeInfoPanel: React.FC = ({ Searchable Database Size @@ -237,7 +237,7 @@ const NodeInfoPanel: React.FC = ({ DatabaseDisk Size (compressed) @@ -255,7 +255,7 @@ const NodeInfoPanel: React.FC = ({ backgroundColor: Colors.orange, color: Colors.white, "&:hover": { - backgroundColor: Colors.darkorange, + backgroundColor: Colors.darkOrange, }, }} onClick={() => navigate(`/databases/${nodeData.id}`)} @@ -271,7 +271,7 @@ const NodeInfoPanel: React.FC = ({ backgroundColor: Colors.orange, color: Colors.white, "&:hover": { - backgroundColor: Colors.darkorange, + backgroundColor: Colors.darkOrange, }, }} > @@ -286,7 +286,7 @@ const NodeInfoPanel: React.FC = ({ backgroundColor: Colors.orange, color: Colors.white, "&:hover": { - backgroundColor: Colors.darkorange, + backgroundColor: Colors.darkOrange, }, }} > @@ -301,7 +301,7 @@ const NodeInfoPanel: React.FC = ({ backgroundColor: Colors.orange, color: Colors.white, "&:hover": { - backgroundColor: Colors.darkorange, + backgroundColor: Colors.darkOrange, }, }} onClick={() => diff --git a/src/design/Layouts/FullScreen.tsx b/src/design/Layouts/FullScreen.tsx index 1ad3372..df4c020 100644 --- a/src/design/Layouts/FullScreen.tsx +++ b/src/design/Layouts/FullScreen.tsx @@ -46,10 +46,9 @@ const FullScreen = () => { > NeuroJSON.io @@ -57,7 +56,6 @@ const FullScreen = () => { variant="h2" sx={{ color: Colors.lightGray, - textTransform: "none", }} > Free Data Worth Sharing diff --git a/src/design/theme.ts b/src/design/theme.ts index 3e98133..b4b649a 100644 --- a/src/design/theme.ts +++ b/src/design/theme.ts @@ -24,12 +24,13 @@ export const Colors = { textPrimary: "#212121", textSecondary: "#494747", green: "#02DEC4", - darkgreen: "#49c6ae", + darkGreen: "#49c6ae", yellow: "#FFDD31", + lightYellow: "#FAEBD7", purple: "#5865F2", - darkpurple: "#282C56", + darkPurple: "#282C56", orange: "#FF9F2F", - darkorange: "#E88C25", + darkOrange: "#E88C25", primary, secondary, }; @@ -52,12 +53,12 @@ const theme = createTheme({ fontFamily: "Raleway", fontWeight: 700, fontSize: "2rem", - color: Colors.yellow, textTransform: "none", }, h2: { fontWeight: 600, fontSize: "1.75rem", + textTransform: "none", color: Colors.secondary.main, }, body1: { diff --git a/src/modules/universe/NeuroJsonGraph.tsx b/src/modules/universe/NeuroJsonGraph.tsx index aed1e58..b12ec19 100644 --- a/src/modules/universe/NeuroJsonGraph.tsx +++ b/src/modules/universe/NeuroJsonGraph.tsx @@ -4,192 +4,256 @@ import React, { useEffect, useRef } from "react"; import { useNavigate } from "react-router-dom"; import * as THREE from "three"; import { - CSS2DObject, - CSS2DRenderer, + CSS2DObject, + CSS2DRenderer, } from "three/examples/jsm/renderers/CSS2DRenderer"; import { Database } from "types/responses/registry.interface"; export interface NodeObject { - id: string; - name: string; - dbname: string; - color: string; - datatype: string[]; - support: string; - url: string; - datasets: number; - standard: string[]; // define type of standard property + id: string; + name: string; + dbname: string; + color: string; + datatype: string[]; + support: string; + url: string; + datasets: number; + standard: string[]; // define type of standard property } -const NeuroJsonGraph: React.FC<{ registry: Database[], onNodeClick?: (node: NodeObject) => void }> = ({ registry, onNodeClick }) => { - const navigate = useNavigate(); - const graphRef = useRef(null); - - // Function to determine color and size based on node size - const size2colorAndSize = (size: number) => { - if (size > 32) return { color: Colors.primary.dark, size: 10 }; - if (size > 3) return { color: Colors.primary.main, size: 7 }; - return { color: Colors.primary.light, size: 5 }; - }; - - useEffect(() => { - // Ensure registry and graphRef are properly initialized - if (!registry || registry.length === 0) { - console.error("Registry is empty or undefined:", registry); - return; - } - - if (!graphRef.current) { - console.error("Graph ref is null"); - return; - } - - // Prepare graph data - const graphData = { - nodes: registry.map((db) => { - const { color, size } = size2colorAndSize(db.datasets); - return { - id: db.id, - name: db.fullname || db.name, - dbname: db.name, - color: color, - datatype: db.datatype, - support: db.support, - url: db.url, - datasets: db.datasets, - size: size, - standard: db.standard || [],// add standard property - }; - }), - links: registry.flatMap((db, index) => { - const connections = []; - const nextIndex = (index + 1) % registry.length; - const { color } = size2colorAndSize(db.datasets); - connections.push({ - source: db.id, - target: registry[nextIndex].id, - color: color, - visible: true, - }); - return connections; - }), - }; - - // Initialize 3D Force Graph - const Graph = new ForceGraph3D(graphRef.current) - .graphData(graphData) - .nodeRelSize(2) - .nodeColor((node) => (node as NodeObject).color) - .linkWidth(2) - .backgroundColor("rgba(0,0,0,0)") - .nodeLabel("name") - .onNodeHover((node) => { - // Change cursor on hover - graphRef.current!.style.cursor = node ? "pointer" : "default"; - }) - .onNodeClick((node) => { - const castNode = node as NodeObject; - if (onNodeClick) { - onNodeClick(castNode); - } - // navigate(`/databases/${castNode.id}`); - }) - .nodeThreeObject((node) => { - const castNode = node as NodeObject; - - // Create a group to hold sphere and glow - const group = new THREE.Group(); - - // Create a 3D sphere for the node - const sphereGeometry = new THREE.SphereGeometry( - (castNode as any).size, - 16, - 16 - ); - const sphereMaterial = new THREE.MeshBasicMaterial({ - color: (castNode as any).color, - }); - const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); - group.add(sphere); - - // Create glow effect - const glowGeometry = new THREE.SphereGeometry( - (castNode as any).size * 1.2, - 16, - 16 - ); - const glowMaterial = new THREE.MeshBasicMaterial({ - color: (castNode as any).color, - transparent: true, - opacity: 0.2, - }); - const glow = new THREE.Mesh(glowGeometry, glowMaterial); - - // Animate glow - const animate = () => { - glow.scale.setScalar(1 + Math.sin(Date.now() * 0.003) * 0.1); - requestAnimationFrame(animate); - }; - animate(); - - group.add(glow); - - // Add label as CSS2DObject - const label = new CSS2DObject(document.createElement("div")); - label.element.textContent = castNode.dbname || "Unnamed"; - label.element.style.color = Colors.primary.main; - label.element.style.fontSize = "12px"; - label.element.style.pointerEvents = "none"; - label.position.set(0, 10, 0); - group.add(label); - - return group; - }); - - // Initialize CSS2DRenderer for 2D labels - const labelRenderer = new CSS2DRenderer(); - labelRenderer.setSize(window.innerWidth, window.innerHeight); - labelRenderer.domElement.style.position = "absolute"; - labelRenderer.domElement.style.top = "0px"; - labelRenderer.domElement.style.pointerEvents = "none"; - graphRef.current?.appendChild(labelRenderer.domElement); - - // Animate label rendering - const animate = () => { - requestAnimationFrame(animate); - labelRenderer.render(Graph.scene(), Graph.camera()); - }; - animate(); - - // Handle window resize - const resizeGraph = () => { - Graph.width(window.innerWidth).height(window.innerHeight); - labelRenderer.setSize(window.innerWidth, window.innerHeight); - }; - resizeGraph(); - window.addEventListener("resize", resizeGraph); - - // Cleanup on component unmount - return () => { - window.removeEventListener("resize", resizeGraph); - if (graphRef.current) { - graphRef.current.removeChild(labelRenderer.domElement); - } - }; - }, [registry]); - - return ( -
- ); +const NeuroJsonGraph: React.FC<{ + registry: Database[]; + onNodeClick?: (node: NodeObject) => void; +}> = ({ registry, onNodeClick }) => { + const navigate = useNavigate(); + const graphRef = useRef(null); + + // Define the datatype to color mapping + const DATA_TYPE_COLORS: Record = { + mri: [79, 51, 130], + fmri: [10, 81, 20], + pet: [0, 105, 192], + meg: [156, 57, 0], + eeg: [134, 31, 55], + ieeg: [18, 109, 62], + beh: [12, 93, 210], + fmap: [255, 255, 59], + dwi: [200, 9, 12], + fnirs: [255, 193, 7], + phenotype: [255, 87, 34], + }; + + // Function to blend colors based on datatypes + const blendColors = (datatypes: string[]): string => { + if (datatypes.length === 0) return "rgb(255,255,255)"; // Default white + + let totalR = 0, + totalG = 0, + totalB = 0; + let count = 0; + + datatypes.forEach((type) => { + const color = DATA_TYPE_COLORS[type]; + if (color) { + totalR += color[0]; + totalG += color[1]; + totalB += color[2]; + count++; + } + }); + + if (count === 0) count = 1; // Prevent division by zero + + const avgR = Math.floor(totalR / count); + const avgG = Math.floor(totalG / count); + const avgB = Math.floor(totalB / count); + + return `rgb(${avgR}, ${avgG}, ${avgB})`; + }; + + // Function to determine color and size based on node size + // const size2colorAndSize = (size: number) => { + // if (size > 32) return { color: Colors.primary.dark, size: 10 }; + // if (size > 3) return { color: Colors.primary.main, size: 7 }; + // return { color: Colors.primary.light, size: 5 }; + // }; + + useEffect(() => { + // Ensure registry and graphRef are properly initialized + if (!registry || registry.length === 0) { + console.error("Registry is empty or undefined:", registry); + return; + } + + if (!graphRef.current) { + console.error("Graph ref is null"); + return; + } + + // Prepare graph data + const graphData = { + nodes: registry.map((db) => { + // const { color, size } = size2colorAndSize(db.datasets); + const color = blendColors(db.datatype); + const size = db.datasets > 32 ? 10 : db.datasets > 3 ? 7 : 5; + + return { + id: db.id, + name: db.fullname || db.name, + dbname: db.name, + color: color, + datatype: db.datatype, + support: db.support, + url: db.url, + datasets: db.datasets, + size: size, + standard: db.standard || [], // add standard property + }; + }), + links: registry.flatMap((db, index) => { + const connections = []; + const nextIndex = (index + 1) % registry.length; + // const { color } = size2colorAndSize(db.datasets); + const color = blendColors(db.datatype); + connections.push({ + source: db.id, + target: registry[nextIndex].id, + color: color, + visible: true, + }); + return connections; + + // non-circle rendering + // const similarNodes = registry.filter( + // (otherDb) => + // db.datatype.some((type) => otherDb.datatype.includes(type)) && + // db.id !== otherDb.id + // ); + + // return similarNodes.map((otherDb) => ({ + // source: db.id, + // target: otherDb.id, + // color: blendColors(db.datatype), // Link color based on datatype + // visible: true, + // })); + }), + }; + + // Initialize 3D Force Graph + const Graph = new ForceGraph3D(graphRef.current) + .graphData(graphData) + .nodeRelSize(2) + .nodeColor((node) => (node as NodeObject).color) + .linkWidth(2) + .backgroundColor("rgba(0,0,0,0)") + .nodeLabel("name") + .onNodeHover((node) => { + // Change cursor on hover + graphRef.current!.style.cursor = node ? "pointer" : "default"; + }) + .onNodeClick((node) => { + const castNode = node as NodeObject; + if (onNodeClick) { + onNodeClick(castNode); + } + // navigate(`/databases/${castNode.id}`); + }) + .nodeThreeObject((node) => { + const castNode = node as NodeObject; + + // Create a group to hold sphere and glow + const group = new THREE.Group(); + + // Create a 3D sphere for the node + const sphereGeometry = new THREE.SphereGeometry( + (castNode as any).size, + 16, + 16 + ); + const sphereMaterial = new THREE.MeshBasicMaterial({ + color: (castNode as any).color, + }); + const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); + group.add(sphere); + + // Create glow effect + const glowGeometry = new THREE.SphereGeometry( + (castNode as any).size * 1.2, + 16, + 16 + ); + const glowMaterial = new THREE.MeshBasicMaterial({ + color: (castNode as any).color, + transparent: true, + opacity: 0.2, + }); + const glow = new THREE.Mesh(glowGeometry, glowMaterial); + + // Animate glow + const animate = () => { + glow.scale.setScalar(1 + Math.sin(Date.now() * 0.003) * 0.1); + requestAnimationFrame(animate); + }; + animate(); + + group.add(glow); + + // Add label as CSS2DObject + const label = new CSS2DObject(document.createElement("div")); + label.element.textContent = castNode.dbname || "Unnamed"; + label.element.style.color = Colors.primary.main; + label.element.style.fontSize = "12px"; + label.element.style.pointerEvents = "none"; + label.position.set(0, 10, 0); + group.add(label); + + return group; + }); + + // Initialize CSS2DRenderer for 2D labels + const labelRenderer = new CSS2DRenderer(); + labelRenderer.setSize(window.innerWidth, window.innerHeight); + labelRenderer.domElement.style.position = "absolute"; + labelRenderer.domElement.style.top = "0px"; + labelRenderer.domElement.style.pointerEvents = "none"; + graphRef.current?.appendChild(labelRenderer.domElement); + + // Animate label rendering + const animate = () => { + requestAnimationFrame(animate); + labelRenderer.render(Graph.scene(), Graph.camera()); + }; + animate(); + + // Handle window resize + const resizeGraph = () => { + Graph.width(window.innerWidth).height(window.innerHeight); + labelRenderer.setSize(window.innerWidth, window.innerHeight); + }; + resizeGraph(); + window.addEventListener("resize", resizeGraph); + + // Cleanup on component unmount + return () => { + window.removeEventListener("resize", resizeGraph); + if (graphRef.current) { + graphRef.current.removeChild(labelRenderer.domElement); + } + }; + }, [registry]); + + return ( +
+ ); }; export default NeuroJsonGraph; diff --git a/src/pages/DatabasePage.tsx b/src/pages/DatabasePage.tsx index e85808a..a989c34 100644 --- a/src/pages/DatabasePage.tsx +++ b/src/pages/DatabasePage.tsx @@ -8,96 +8,96 @@ import { fetchRegistry } from "redux/neurojson/neurojson.action"; import { NeurojsonSelector } from "redux/neurojson/neurojson.selector"; const DatabasePage: React.FC = () => { - const navigate = useNavigate(); - const dispatch = useAppDispatch(); - const { registry } = useAppSelector(NeurojsonSelector); + const navigate = useNavigate(); + const dispatch = useAppDispatch(); + const { registry } = useAppSelector(NeurojsonSelector); - useEffect(() => { - dispatch(fetchRegistry()); - }, [dispatch]); + useEffect(() => { + dispatch(fetchRegistry()); + }, [dispatch]); - if (!registry || !Array.isArray(registry) || registry.length === 0) { - return ( - - - - No Databases Found - - - Please check back later or contact support if this persists. - - - - ); - } + if (!registry || !Array.isArray(registry) || registry.length === 0) { + return ( + + + + No Databases Found + + + Please check back later or contact support if this persists. + + + + ); + } - return ( - - - - Databases - - - {registry.map((db) => { - if (!db?.id) { - console.warn("Database entry missing ID:", db); - return null; - } + return ( + + + + Databases + + + {registry.map((db) => { + if (!db?.id) { + console.warn("Database entry missing ID:", db); + return null; + } - return ( - - ); - })} - - - - ); + return ( + + ); + })} + + + + ); }; export default DatabasePage; diff --git a/src/pages/DatasetPage.tsx b/src/pages/DatasetPage.tsx index 35ab1a8..6c57e68 100644 --- a/src/pages/DatasetPage.tsx +++ b/src/pages/DatasetPage.tsx @@ -1,23 +1,23 @@ import { - fetchDbInfo, - loadPaginatedData, + fetchDbInfo, + loadPaginatedData, } from "../redux/neurojson/neurojson.action"; import { - Box, - Typography, - CircularProgress, - Alert, - Card, - CardContent, - Grid, - Link, - Chip, - Stack, - Button, - Select, - MenuItem, - FormControl, - InputLabel, + Box, + Typography, + CircularProgress, + Alert, + Card, + CardContent, + Grid, + Link, + Chip, + Stack, + Button, + Select, + MenuItem, + FormControl, + InputLabel, } from "@mui/material"; import { Colors } from "design/theme"; import { useAppDispatch } from "hooks/useAppDispatch"; @@ -27,296 +27,296 @@ import { useNavigate, useParams } from "react-router-dom"; import RoutesEnum from "types/routes.enum"; const DatasetPage: React.FC = () => { - const navigate = useNavigate(); - const { dbName } = useParams<{ dbName: string }>(); - const dispatch = useAppDispatch(); - const { loading, error, data, limit, hasMore } = useAppSelector( - (state: { neurojson: any }) => state.neurojson - ); - const [currentOffset, setCurrentOffset] = useState(0); - const [pageSize, setPageSize] = useState(10); + const navigate = useNavigate(); + const { dbName } = useParams<{ dbName: string }>(); + const dispatch = useAppDispatch(); + const { loading, error, data, limit, hasMore } = useAppSelector( + (state: { neurojson: any }) => state.neurojson + ); + const [currentOffset, setCurrentOffset] = useState(0); + const [pageSize, setPageSize] = useState(10); - useEffect(() => { - if (dbName) { - dispatch(fetchDbInfo(dbName.toLowerCase())); - dispatch( - loadPaginatedData({ - dbName: dbName.toLowerCase(), - offset: 0, - limit: pageSize, - }) - ); - } - }, [dbName, dispatch, pageSize]); + useEffect(() => { + if (dbName) { + dispatch(fetchDbInfo(dbName.toLowerCase())); + dispatch( + loadPaginatedData({ + dbName: dbName.toLowerCase(), + offset: 0, + limit: pageSize, + }) + ); + } + }, [dbName, dispatch, pageSize]); - const loadMoreData = () => { - if (dbName && !loading) { - const nextOffset = currentOffset + pageSize; - setCurrentOffset(nextOffset); - dispatch( - loadPaginatedData({ - dbName: dbName.toLowerCase(), - offset: nextOffset, - limit: pageSize, - }) - ); - } - }; + const loadMoreData = () => { + if (dbName && !loading) { + const nextOffset = currentOffset + pageSize; + setCurrentOffset(nextOffset); + dispatch( + loadPaginatedData({ + dbName: dbName.toLowerCase(), + offset: nextOffset, + limit: pageSize, + }) + ); + } + }; - const handlePageSizeChange = (event: any) => { - setPageSize(event.target.value); - setCurrentOffset(0); // Reset offset when changing page size - }; + const handlePageSizeChange = (event: any) => { + setPageSize(event.target.value); + setCurrentOffset(0); // Reset offset when changing page size + }; - return ( - - - - Database: {dbName || "N/A"} - + return ( + + + + Database: {dbName || "N/A"} + - - - Items per page - - - - + + + Items per page + + + + - {error && ( - - {error} - - )} + {error && ( + + {error} + + )} - {loading && ( - - )} + {loading && ( + + )} - {!loading && !error && data.length > 0 && ( - - {data.map((doc: any) => ( - - - - + {!loading && !error && data.length > 0 && ( + + {data.map((doc: any) => ( + + + + - - ID: {doc.id} - + + ID: {doc.id} + - - - {doc.value.subj && ( - - )} - {doc.value.modality && - doc.value.modality.map((mod: string) => ( - - ))} - + + + {doc.value.subj && ( + + )} + {doc.value.modality && + doc.value.modality.map((mod: string) => ( + + ))} + - - Summary:{" "} - {doc.value.readme || "No description available"} - + + Summary:{" "} + {doc.value.readme || "No description available"} + - - Authors:{" "} - {Array.isArray(doc.value.info?.Authors) - ? doc.value.info.Authors.join(", ") - : doc.value.info?.Authors || "Unknown"} - + + Authors:{" "} + {Array.isArray(doc.value.info?.Authors) + ? doc.value.info.Authors.join(", ") + : doc.value.info?.Authors || "Unknown"} + - - - Size:{" "} - {doc.value.length - ? `${(doc.value.length / 1024 / 1024).toFixed(2)} MB` - : "Unknown"} - + + + Size:{" "} + {doc.value.length + ? `${(doc.value.length / 1024 / 1024).toFixed(2)} MB` + : "Unknown"} + - {doc.value.info?.DatasetDOI && ( - - - - )} - - - - - - ))} - - )} + {doc.value.info?.DatasetDOI && ( + + + + )} + + + + + + ))} + + )} - {!loading && !error && data.length === 0 && ( - - No database information available. - - )} + {!loading && !error && data.length === 0 && ( + + No database information available. + + )} - {!loading && ( - - - - )} - - ); + {!loading && ( + + + + )} + + ); }; export default DatasetPage; diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 5699972..b6bd941 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -1,124 +1,124 @@ import { - Box, - Typography, - Button, - Container, - Grid, - CircularProgress, + Box, + Typography, + Button, + Container, + Grid, + CircularProgress, } from "@mui/material"; +import NodeInfoPanel from "components/NodeInfoPanel"; import { Colors } from "design/theme"; import { useAppDispatch } from "hooks/useAppDispatch"; import { useAppSelector } from "hooks/useAppSelector"; import NeuroJsonGraph from "modules/universe/NeuroJsonGraph"; +import { NodeObject } from "modules/universe/NeuroJsonGraph"; import React, { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { fetchRegistry } from "redux/neurojson/neurojson.action"; import { NeurojsonSelector } from "redux/neurojson/neurojson.selector"; -import NodeInfoPanel from "components/NodeInfoPanel"; -import { NodeObject } from "modules/universe/NeuroJsonGraph"; const Home: React.FC = () => { - const navigate = useNavigate(); - const dispatch = useAppDispatch(); - const { registry, loading } = useAppSelector(NeurojsonSelector); + const navigate = useNavigate(); + const dispatch = useAppDispatch(); + const { registry, loading } = useAppSelector(NeurojsonSelector); - // State for selected node and panel visibility - const [selectedNode, setSelectedNode] = useState(null); - const [panelOpen, setPanelOpen] = useState(false); + // State for selected node and panel visibility + const [selectedNode, setSelectedNode] = useState(null); + const [panelOpen, setPanelOpen] = useState(false); - useEffect(() => { - dispatch(fetchRegistry()); - }, [dispatch]); + useEffect(() => { + dispatch(fetchRegistry()); + }, [dispatch]); - // Handle node click: Set selected node and open panel - const handleNodeClick = (node: NodeObject) => { - setSelectedNode(node); - setPanelOpen(true); - }; + // Handle node click: Set selected node and open panel + const handleNodeClick = (node: NodeObject) => { + setSelectedNode(node); + setPanelOpen(true); + }; - return ( - - - {!registry ? ( - - - - ) : registry && registry.length > 0 ? ( - - ) : ( - - - No data available to display - - - )} - + return ( + + + {!registry ? ( + + + + ) : registry && registry.length > 0 ? ( + + ) : ( + + + No data available to display + + + )} + - - {/* Header Section */} - - Discover NeuroJSON.io - - - Efficiently manage and explore your CouchDB databases and datasets - with ease. - + + {/* Header Section */} + + Discover NeuroJSON.io + + + Efficiently manage and explore your CouchDB databases and datasets + with ease. + - {/* Navigation to Database Page */} - - - - + {/* Navigation to Database Page */} + + + + - setPanelOpen(false)} nodeData={selectedNode} /> - - ); + setPanelOpen(false)} + nodeData={selectedNode} + /> + + ); }; export default Home; From 548b6455226a7e1ca6267cad220d6c841ac528d2 Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Tue, 11 Mar 2025 14:48:12 -0400 Subject: [PATCH 08/20] Revise the circle nodes layout to a constellation-style graph --- src/modules/universe/NeuroJsonGraph.tsx | 144 ++++++++++++++++++++---- 1 file changed, 119 insertions(+), 25 deletions(-) diff --git a/src/modules/universe/NeuroJsonGraph.tsx b/src/modules/universe/NeuroJsonGraph.tsx index b12ec19..8139a21 100644 --- a/src/modules/universe/NeuroJsonGraph.tsx +++ b/src/modules/universe/NeuroJsonGraph.tsx @@ -77,6 +77,27 @@ const NeuroJsonGraph: React.FC<{ // if (size > 3) return { color: Colors.primary.main, size: 7 }; // return { color: Colors.primary.light, size: 5 }; // }; + // Custom random number generator (same as `mulberry32`) + const mulberry32 = (a: number) => { + return function () { + let t = (a += 0x6d2b79f5); + t = Math.imul(t ^ (t >>> 15), t | 1); + t ^= t + Math.imul(t ^ (t >>> 7), t | 61); + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + }; + }; + + const rngfun = mulberry32(0x123456789); // Seeded random function + + // // Shuffle nodes + // const nodenum = registry.length; + // const randnode = [...Array(nodenum).keys()]; + + // Fisher-Yates Shuffle + // for (let i = 0; i < nodenum; i++) { + // const j = Math.floor(rngfun() * (i + 1)); + // [randnode[i], randnode[j]] = [randnode[j], randnode[i]]; + // } useEffect(() => { // Ensure registry and graphRef are properly initialized @@ -90,6 +111,33 @@ const NeuroJsonGraph: React.FC<{ return; } + let colorlist: { brightness: number; index: number }[] = registry.map( + (db, index) => { + const colorStr = blendColors(db.datatype); // Get color in "rgb(R,G,B)" format + + // **Extract RGB values from the string** + const match = colorStr.match(/\d+/g); // Get numbers from "rgb(R,G,B)" + if (!match) return { brightness: 255, index }; // Default to white if extraction fails + + const [r, g, b] = match.map(Number); // Convert to numbers + const brightness = 0.2126 * r + 0.7152 * g + 0.0722 * b; // Compute brightness + + return { brightness, index }; + } + ); + + // **2️⃣ Sort nodes by brightness (dark → bright)** + colorlist.sort((a, b) => a.brightness - b.brightness); + + // // **3️⃣ Create shuffled node list using Fisher-Yates algorithm** + // const nodenum = registry.length; + // const randnode = colorlist.map((item) => item.index); // Get sorted indices + + // for (let i = 0; i < nodenum; i++) { + // const j = Math.floor(rngfun() * (i + 1)); + // [randnode[i], randnode[j]] = [randnode[j], randnode[i]]; + // } + // Prepare graph data const graphData = { nodes: registry.map((db) => { @@ -107,35 +155,81 @@ const NeuroJsonGraph: React.FC<{ url: db.url, datasets: db.datasets, size: size, - standard: db.standard || [], // add standard property + standard: db.standard || [], }; }), - links: registry.flatMap((db, index) => { - const connections = []; - const nextIndex = (index + 1) % registry.length; - // const { color } = size2colorAndSize(db.datasets); - const color = blendColors(db.datatype); - connections.push({ - source: db.id, - target: registry[nextIndex].id, - color: color, - visible: true, - }); - return connections; - // non-circle rendering - // const similarNodes = registry.filter( - // (otherDb) => - // db.datatype.some((type) => otherDb.datatype.includes(type)) && - // db.id !== otherDb.id - // ); + links: registry.flatMap((db, index) => { + // const color = blendColors(db.datatype); + // return registry + // .filter( + // (otherDb) => + // db.id !== otherDb.id && + // db.datatype.some((type) => otherDb.datatype.includes(type)) + // ) + // .map((otherDB) => ({ + // source: db.id, + // target: otherDB.id, + // color: Colors.lightGray, + // visible: true, + // })); - // return similarNodes.map((otherDb) => ({ + // const connections = []; + // const nextIndex = (index + 1) % registry.length; + // // const { color } = size2colorAndSize(db.datasets); + // const color = blendColors(db.datatype); + // connections.push({ // source: db.id, - // target: otherDb.id, - // color: blendColors(db.datatype), // Link color based on datatype + // target: registry[nextIndex].id, + // color: color, // visible: true, - // })); + // }); + // return connections; + + // use original website logic + const coloridx = index; + const i = colorlist[coloridx].index; // Get shuffled node index + const node = registry[i]; // Get actual node + + // Determine number of connections (proportional to dataset size) + const conn = 1 + Math.round(rngfun() * Math.max(1, node.datasets / 20)); + // const numConnections = 4; + const connections: { + source: string; + target: string; + color: string; + visible: boolean; + }[] = []; + + // for (let j = -conn; j <= conn; j++) { + // if (j === 0) continue; // Skip linking to itself + // if (coloridx + j >= nodenum) break; // Prevent out-of-bounds errors + + // const targetNode = registry[randnode[Math.max(0, coloridx + j)]]; // Pick a nearby node from shuffled list + + // connections.push({ + // source: node.id, + // target: targetNode.id, + // color: blendColors(node.datatype), // Match node's color + // visible: true, // Make links visible + // }); + // } + + for (let j = 1; j <= conn; j++) { + if (index + j >= registry.length) break; // Prevent out-of-bounds errors + + const targetIdx = colorlist[index + j].index; // Get next closest in brightness + const targetNode = registry[targetIdx]; + + connections.push({ + source: node.id, + target: targetNode.id, + color: blendColors(node.datatype), // Keep consistent coloring + visible: true, // Make links visible + }); + } + + return connections; }), }; @@ -144,7 +238,7 @@ const NeuroJsonGraph: React.FC<{ .graphData(graphData) .nodeRelSize(2) .nodeColor((node) => (node as NodeObject).color) - .linkWidth(2) + .linkWidth(0.5) .backgroundColor("rgba(0,0,0,0)") .nodeLabel("name") .onNodeHover((node) => { @@ -201,7 +295,7 @@ const NeuroJsonGraph: React.FC<{ // Add label as CSS2DObject const label = new CSS2DObject(document.createElement("div")); label.element.textContent = castNode.dbname || "Unnamed"; - label.element.style.color = Colors.primary.main; + label.element.style.color = Colors.white; label.element.style.fontSize = "12px"; label.element.style.pointerEvents = "none"; label.position.set(0, 10, 0); From 9e0ca6d2c1cb0d6e9b01908803e3c78047c0334e Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Tue, 11 Mar 2025 15:28:06 -0400 Subject: [PATCH 09/20] Update node sizing: replace fixed sizes with dataset-based dynamic scaling --- src/modules/universe/NeuroJsonGraph.tsx | 78 ++++--------------------- 1 file changed, 11 insertions(+), 67 deletions(-) diff --git a/src/modules/universe/NeuroJsonGraph.tsx b/src/modules/universe/NeuroJsonGraph.tsx index 8139a21..d96ce52 100644 --- a/src/modules/universe/NeuroJsonGraph.tsx +++ b/src/modules/universe/NeuroJsonGraph.tsx @@ -77,7 +77,8 @@ const NeuroJsonGraph: React.FC<{ // if (size > 3) return { color: Colors.primary.main, size: 7 }; // return { color: Colors.primary.light, size: 5 }; // }; - // Custom random number generator (same as `mulberry32`) + + // Custom random number generator const mulberry32 = (a: number) => { return function () { let t = (a += 0x6d2b79f5); @@ -87,17 +88,7 @@ const NeuroJsonGraph: React.FC<{ }; }; - const rngfun = mulberry32(0x123456789); // Seeded random function - - // // Shuffle nodes - // const nodenum = registry.length; - // const randnode = [...Array(nodenum).keys()]; - - // Fisher-Yates Shuffle - // for (let i = 0; i < nodenum; i++) { - // const j = Math.floor(rngfun() * (i + 1)); - // [randnode[i], randnode[j]] = [randnode[j], randnode[i]]; - // } + const rngfun = mulberry32(0x123456789); useEffect(() => { // Ensure registry and graphRef are properly initialized @@ -115,7 +106,7 @@ const NeuroJsonGraph: React.FC<{ (db, index) => { const colorStr = blendColors(db.datatype); // Get color in "rgb(R,G,B)" format - // **Extract RGB values from the string** + // Extract RGB values from the string const match = colorStr.match(/\d+/g); // Get numbers from "rgb(R,G,B)" if (!match) return { brightness: 255, index }; // Default to white if extraction fails @@ -126,24 +117,18 @@ const NeuroJsonGraph: React.FC<{ } ); - // **2️⃣ Sort nodes by brightness (dark → bright)** + // Sort nodes by brightness colorlist.sort((a, b) => a.brightness - b.brightness); - // // **3️⃣ Create shuffled node list using Fisher-Yates algorithm** - // const nodenum = registry.length; - // const randnode = colorlist.map((item) => item.index); // Get sorted indices - - // for (let i = 0; i < nodenum; i++) { - // const j = Math.floor(rngfun() * (i + 1)); - // [randnode[i], randnode[j]] = [randnode[j], randnode[i]]; - // } - // Prepare graph data const graphData = { nodes: registry.map((db) => { // const { color, size } = size2colorAndSize(db.datasets); const color = blendColors(db.datatype); - const size = db.datasets > 32 ? 10 : db.datasets > 3 ? 7 : 5; + // const size = db.datasets > 32 ? 10 : db.datasets > 3 ? 7 : 5; + + let size = db.datasets > 100 ? Math.log(db.datasets) : db.datasets / 5; + size = Math.max(size, 2); return { id: db.id, @@ -160,40 +145,13 @@ const NeuroJsonGraph: React.FC<{ }), links: registry.flatMap((db, index) => { - // const color = blendColors(db.datatype); - // return registry - // .filter( - // (otherDb) => - // db.id !== otherDb.id && - // db.datatype.some((type) => otherDb.datatype.includes(type)) - // ) - // .map((otherDB) => ({ - // source: db.id, - // target: otherDB.id, - // color: Colors.lightGray, - // visible: true, - // })); - - // const connections = []; - // const nextIndex = (index + 1) % registry.length; - // // const { color } = size2colorAndSize(db.datasets); - // const color = blendColors(db.datatype); - // connections.push({ - // source: db.id, - // target: registry[nextIndex].id, - // color: color, - // visible: true, - // }); - // return connections; - - // use original website logic const coloridx = index; const i = colorlist[coloridx].index; // Get shuffled node index const node = registry[i]; // Get actual node // Determine number of connections (proportional to dataset size) const conn = 1 + Math.round(rngfun() * Math.max(1, node.datasets / 20)); - // const numConnections = 4; + const connections: { source: string; target: string; @@ -201,20 +159,6 @@ const NeuroJsonGraph: React.FC<{ visible: boolean; }[] = []; - // for (let j = -conn; j <= conn; j++) { - // if (j === 0) continue; // Skip linking to itself - // if (coloridx + j >= nodenum) break; // Prevent out-of-bounds errors - - // const targetNode = registry[randnode[Math.max(0, coloridx + j)]]; // Pick a nearby node from shuffled list - - // connections.push({ - // source: node.id, - // target: targetNode.id, - // color: blendColors(node.datatype), // Match node's color - // visible: true, // Make links visible - // }); - // } - for (let j = 1; j <= conn; j++) { if (index + j >= registry.length) break; // Prevent out-of-bounds errors @@ -238,7 +182,7 @@ const NeuroJsonGraph: React.FC<{ .graphData(graphData) .nodeRelSize(2) .nodeColor((node) => (node as NodeObject).color) - .linkWidth(0.5) + .linkWidth(1) .backgroundColor("rgba(0,0,0,0)") .nodeLabel("name") .onNodeHover((node) => { From 57b6640331a395cabb0319687bedb9f6e27e6d9d Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Wed, 12 Mar 2025 12:26:03 -0400 Subject: [PATCH 10/20] Update node links: refactored link logic to prioritize connections between similar-colored nodes, ensuring links reflect shared datatypes and form tighter clusters. --- src/design/Layouts/FullScreen.tsx | 2 +- src/modules/universe/NeuroJsonGraph.tsx | 70 +++++++++++-------------- src/pages/Home.tsx | 5 +- 3 files changed, 34 insertions(+), 43 deletions(-) diff --git a/src/design/Layouts/FullScreen.tsx b/src/design/Layouts/FullScreen.tsx index df4c020..b83a71c 100644 --- a/src/design/Layouts/FullScreen.tsx +++ b/src/design/Layouts/FullScreen.tsx @@ -134,7 +134,7 @@ const FullScreen = () => { height: "calc(100vh - 6rem)", boxSizing: "border-box", marginTop: "6rem", - backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 1500'%3E%3Cdefs%3E%3CradialGradient id='a' gradientUnits='objectBoundingBox'%3E%3Cstop offset='0' stop-color='%23000000'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/radialGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='0' y1='750' x2='1550' y2='750'%3E%3Cstop offset='0' stop-color='%232c3379'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/linearGradient%3E%3Cpath id='s' fill='url(%23b)' d='M1549.2 51.6c-5.4 99.1-20.2 197.6-44.2 293.6c-24.1 96-57.4 189.4-99.3 278.6c-41.9 89.2-92.4 174.1-150.3 253.3c-58 79.2-123.4 152.6-195.1 219c-71.7 66.4-149.6 125.8-232.2 177.2c-82.7 51.4-170.1 94.7-260.7 129.1c-90.6 34.4-184.4 60-279.5 76.3C192.6 1495 96.1 1502 0 1500c96.1-2.1 191.8-13.3 285.4-33.6c93.6-20.2 185-49.5 272.5-87.2c87.6-37.7 171.3-83.8 249.6-137.3c78.4-53.5 151.5-114.5 217.9-181.7c66.5-67.2 126.4-140.7 178.6-218.9c52.3-78.3 96.9-161.4 133-247.9c36.1-86.5 63.8-176.2 82.6-267.6c18.8-91.4 28.6-184.4 29.6-277.4c0.3-27.6 23.2-48.7 50.8-48.4s49.5 21.8 49.2 49.5c0 0.7 0 1.3-0.1 2L1549.2 51.6z'/%3E%3Cg id='g'%3E%3Cuse href='%23s' transform='scale(0.12) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.2) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.25) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(0.3) rotate(-20)'/%3E%3Cuse href='%23s' transform='scale(0.4) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(0.5) rotate(20)'/%3E%3Cuse href='%23s' transform='scale(0.6) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.7) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.835) rotate(-40)'/%3E%3Cuse href='%23s' transform='scale(0.9) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(1.05) rotate(25)'/%3E%3Cuse href='%23s' transform='scale(1.2) rotate(8)'/%3E%3Cuse href='%23s' transform='scale(1.333) rotate(-60)'/%3E%3Cuse href='%23s' transform='scale(1.45) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(1.6) rotate(10)'/%3E%3C/g%3E%3C/defs%3E%3Cg transform='translate(400 0)'%3E%3Cg transform='translate(0 375)'%3E%3Ccircle fill='url(%23a)' r='3000'/%3E%3Cg opacity='0.5'%3E%3Ccircle fill='url(%23a)' r='2000'/%3E%3Ccircle fill='url(%23a)' r='1800'/%3E%3Ccircle fill='url(%23a)' r='1700'/%3E%3Ccircle fill='url(%23a)' r='1651'/%3E%3Ccircle fill='url(%23a)' r='1450'/%3E%3Ccircle fill='url(%23a)' r='1250'/%3E%3Ccircle fill='url(%23a)' r='1175'/%3E%3Ccircle fill='url(%23a)' r='900'/%3E%3Ccircle fill='url(%23a)' r='750'/%3E%3Ccircle fill='url(%23a)' r='500'/%3E%3Ccircle fill='url(%23a)' r='380'/%3E%3Ccircle fill='url(%23a)' r='250'/%3E%3C/g%3E%3Cg transform='rotate(-273.6 0 0)'%3E%3Cuse href='%23g' transform='rotate(10)'/%3E%3Cuse href='%23g' transform='rotate(120)'/%3E%3Cuse href='%23g' transform='rotate(240)'/%3E%3C/g%3E%3Ccircle fill-opacity='0.99' fill='url(%23a)' r='3000'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`, + backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 1500'%3E%3Cdefs%3E%3CradialGradient id='a' gradientUnits='objectBoundingBox'%3E%3Cstop offset='0' stop-color='%23000000'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/radialGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='0' y1='750' x2='1550' y2='750'%3E%3Cstop offset='0' stop-color='%232c3379'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/linearGradient%3E%3Cpath id='s' fill='url(%23b)' d='M1549.2 51.6c-5.4 99.1-20.2 197.6-44.2 293.6c-24.1 96-57.4 189.4-99.3 278.6c-41.9 89.2-92.4 174.1-150.3 253.3c-58 79.2-123.4 152.6-195.1 219c-71.7 66.4-149.6 125.8-232.2 177.2c-82.7 51.4-170.1 94.7-260.7 129.1c-90.6 34.4-184.4 60-279.5 76.3C192.6 1495 96.1 1502 0 1500c96.1-2.1 191.8-13.3 285.4-33.6c93.6-20.2 185-49.5 272.5-87.2c87.6-37.7 171.3-83.8 249.6-137.3c78.4-53.5 151.5-114.5 217.9-181.7c66.5-67.2 126.4-140.7 178.6-218.9c52.3-78.3 96.9-161.4 133-247.9c36.1-86.5 63.8-176.2 82.6-267.6c18.8-91.4 28.6-184.4 29.6-277.4c0.3-27.6 23.2-48.7 50.8-48.4s49.5 21.8 49.2 49.5c0 0.7 0 1.3-0.1 2L1549.2 51.6z'/%3E%3Cg id='g'%3E%3Cuse href='%23s' transform='scale(0.12) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.2) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.25) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(0.3) rotate(-20)'/%3E%3Cuse href='%23s' transform='scale(0.4) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(0.5) rotate(20)'/%3E%3Cuse href='%23s' transform='scale(0.6) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.7) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.835) rotate(-40)'/%3E%3Cuse href='%23s' transform='scale(0.9) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(1.05) rotate(25)'/%3E%3Cuse href='%23s' transform='scale(1.2) rotate(8)'/%3E%3Cuse href='%23s' transform='scale(1.333) rotate(-60)'/%3E%3Cuse href='%23s' transform='scale(1.45) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(1.6) rotate(10)'/%3E%3C/g%3E%3C/defs%3E%3Cg transform='rotate(0 0 0)'%3E%3Cg transform='rotate(0 0 0)'%3E%3Ccircle fill='url(%23a)' r='3000'/%3E%3Cg opacity='0.5'%3E%3Ccircle fill='url(%23a)' r='2000'/%3E%3Ccircle fill='url(%23a)' r='1800'/%3E%3Ccircle fill='url(%23a)' r='1700'/%3E%3Ccircle fill='url(%23a)' r='1651'/%3E%3Ccircle fill='url(%23a)' r='1450'/%3E%3Ccircle fill='url(%23a)' r='1250'/%3E%3Ccircle fill='url(%23a)' r='1175'/%3E%3Ccircle fill='url(%23a)' r='900'/%3E%3Ccircle fill='url(%23a)' r='750'/%3E%3Ccircle fill='url(%23a)' r='500'/%3E%3Ccircle fill='url(%23a)' r='380'/%3E%3Ccircle fill='url(%23a)' r='250'/%3E%3C/g%3E%3Cg transform='rotate(0 0 0)'%3E%3Cuse href='%23g' transform='rotate(10)'/%3E%3Cuse href='%23g' transform='rotate(120)'/%3E%3Cuse href='%23g' transform='rotate(240)'/%3E%3C/g%3E%3Ccircle fill-opacity='0.83' fill='url(%23a)' r='3000'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`, backgroundAttachment: "fixed", backgroundSize: "cover", overflow: "auto", diff --git a/src/modules/universe/NeuroJsonGraph.tsx b/src/modules/universe/NeuroJsonGraph.tsx index d96ce52..83934e3 100644 --- a/src/modules/universe/NeuroJsonGraph.tsx +++ b/src/modules/universe/NeuroJsonGraph.tsx @@ -18,7 +18,7 @@ export interface NodeObject { support: string; url: string; datasets: number; - standard: string[]; // define type of standard property + standard: string[]; } const NeuroJsonGraph: React.FC<{ @@ -71,14 +71,7 @@ const NeuroJsonGraph: React.FC<{ return `rgb(${avgR}, ${avgG}, ${avgB})`; }; - // Function to determine color and size based on node size - // const size2colorAndSize = (size: number) => { - // if (size > 32) return { color: Colors.primary.dark, size: 10 }; - // if (size > 3) return { color: Colors.primary.main, size: 7 }; - // return { color: Colors.primary.light, size: 5 }; - // }; - - // Custom random number generator + // Custom random number generator for link connection usage const mulberry32 = (a: number) => { return function () { let t = (a += 0x6d2b79f5); @@ -102,20 +95,19 @@ const NeuroJsonGraph: React.FC<{ return; } - let colorlist: { brightness: number; index: number }[] = registry.map( - (db, index) => { + // create a colorlist after blend colors for nodes + let colorlist: { brightness: number; index: number; color: string }[] = + registry.map((db, index) => { const colorStr = blendColors(db.datatype); // Get color in "rgb(R,G,B)" format - - // Extract RGB values from the string const match = colorStr.match(/\d+/g); // Get numbers from "rgb(R,G,B)" - if (!match) return { brightness: 255, index }; // Default to white if extraction fails + if (!match) + return { brightness: 255, index, color: "rgb(255, 255, 255)" }; // Default to white if extraction fails const [r, g, b] = match.map(Number); // Convert to numbers const brightness = 0.2126 * r + 0.7152 * g + 0.0722 * b; // Compute brightness - return { brightness, index }; - } - ); + return { brightness, index, color: colorStr }; + }); // Sort nodes by brightness colorlist.sort((a, b) => a.brightness - b.brightness); @@ -123,12 +115,10 @@ const NeuroJsonGraph: React.FC<{ // Prepare graph data const graphData = { nodes: registry.map((db) => { - // const { color, size } = size2colorAndSize(db.datasets); const color = blendColors(db.datatype); - // const size = db.datasets > 32 ? 10 : db.datasets > 3 ? 7 : 5; - - let size = db.datasets > 100 ? Math.log(db.datasets) : db.datasets / 5; - size = Math.max(size, 2); + let size = + db.datasets > 100 ? Math.log(db.datasets) * 2.5 : db.datasets / 6; + size = Math.max(size, 4); return { id: db.id, @@ -144,13 +134,13 @@ const NeuroJsonGraph: React.FC<{ }; }), - links: registry.flatMap((db, index) => { - const coloridx = index; - const i = colorlist[coloridx].index; // Get shuffled node index - const node = registry[i]; // Get actual node - - // Determine number of connections (proportional to dataset size) - const conn = 1 + Math.round(rngfun() * Math.max(1, node.datasets / 20)); + links: colorlist.flatMap(({ index, color }, colorIdx) => { + const node = registry[index]; + // Determine number of connections + const scaledDatasets = + node.datasets > 100 ? Math.log(node.datasets) : node.datasets; + const conn = + 1 + Math.round(rngfun() * Math.max(1, scaledDatasets / 20)); const connections: { source: string; @@ -159,17 +149,19 @@ const NeuroJsonGraph: React.FC<{ visible: boolean; }[] = []; - for (let j = 1; j <= conn; j++) { - if (index + j >= registry.length) break; // Prevent out-of-bounds errors - - const targetIdx = colorlist[index + j].index; // Get next closest in brightness - const targetNode = registry[targetIdx]; + for (let j = -conn; j <= conn; j++) { + if (j === 0) continue; + const targetColorIdx = colorIdx + j; + if (targetColorIdx < 0 || targetColorIdx >= colorlist.length) + continue; // Prevent out-of-bounds errors + const targetIdx = colorlist[targetColorIdx].index; // Get registry node index in colorlist order + const targetNode = registry[targetIdx]; // Get target node info in registry connections.push({ source: node.id, target: targetNode.id, - color: blendColors(node.datatype), // Keep consistent coloring - visible: true, // Make links visible + color: blendColors(node.datatype), + visible: true, }); } @@ -180,7 +172,7 @@ const NeuroJsonGraph: React.FC<{ // Initialize 3D Force Graph const Graph = new ForceGraph3D(graphRef.current) .graphData(graphData) - .nodeRelSize(2) + .nodeRelSize(1) .nodeColor((node) => (node as NodeObject).color) .linkWidth(1) .backgroundColor("rgba(0,0,0,0)") @@ -239,8 +231,8 @@ const NeuroJsonGraph: React.FC<{ // Add label as CSS2DObject const label = new CSS2DObject(document.createElement("div")); label.element.textContent = castNode.dbname || "Unnamed"; - label.element.style.color = Colors.white; - label.element.style.fontSize = "12px"; + label.element.style.color = Colors.lightYellow; + label.element.style.fontSize = "16px"; label.element.style.pointerEvents = "none"; label.position.set(0, 10, 0); group.add(label); diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index b6bd941..29fc2fc 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -72,15 +72,14 @@ const Home: React.FC = () => { {/* Header Section */} From acfa6724b36748a8f91379aac11850dfeee3a579 Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Wed, 12 Mar 2025 15:52:25 -0400 Subject: [PATCH 11/20] Update home page background --- src/design/Layouts/FullScreen.tsx | 7 +++++-- src/modules/universe/NeuroJsonGraph.tsx | 4 ++-- src/pages/Home.tsx | 7 ++++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/design/Layouts/FullScreen.tsx b/src/design/Layouts/FullScreen.tsx index b83a71c..bceb01c 100644 --- a/src/design/Layouts/FullScreen.tsx +++ b/src/design/Layouts/FullScreen.tsx @@ -17,12 +17,14 @@ const FullScreen = () => { maxWidth: "100vw", width: "100%", overflowX: "hidden", - backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 1500'%3E%3Cdefs%3E%3CradialGradient id='a' gradientUnits='objectBoundingBox'%3E%3Cstop offset='0' stop-color='%23000000'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/radialGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='0' y1='750' x2='1550' y2='750'%3E%3Cstop offset='0' stop-color='%232c3379'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/linearGradient%3E%3Cpath id='s' fill='url(%23b)' d='M1549.2 51.6c-5.4 99.1-20.2 197.6-44.2 293.6c-24.1 96-57.4 189.4-99.3 278.6c-41.9 89.2-92.4 174.1-150.3 253.3c-58 79.2-123.4 152.6-195.1 219c-71.7 66.4-149.6 125.8-232.2 177.2c-82.7 51.4-170.1 94.7-260.7 129.1c-90.6 34.4-184.4 60-279.5 76.3C192.6 1495 96.1 1502 0 1500c96.1-2.1 191.8-13.3 285.4-33.6c93.6-20.2 185-49.5 272.5-87.2c87.6-37.7 171.3-83.8 249.6-137.3c78.4-53.5 151.5-114.5 217.9-181.7c66.5-67.2 126.4-140.7 178.6-218.9c52.3-78.3 96.9-161.4 133-247.9c36.1-86.5 63.8-176.2 82.6-267.6c18.8-91.4 28.6-184.4 29.6-277.4c0.3-27.6 23.2-48.7 50.8-48.4s49.5 21.8 49.2 49.5c0 0.7 0 1.3-0.1 2L1549.2 51.6z'/%3E%3Cg id='g'%3E%3Cuse href='%23s' transform='scale(0.12) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.2) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.25) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(0.3) rotate(-20)'/%3E%3Cuse href='%23s' transform='scale(0.4) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(0.5) rotate(20)'/%3E%3Cuse href='%23s' transform='scale(0.6) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.7) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.835) rotate(-40)'/%3E%3Cuse href='%23s' transform='scale(0.9) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(1.05) rotate(25)'/%3E%3Cuse href='%23s' transform='scale(1.2) rotate(8)'/%3E%3Cuse href='%23s' transform='scale(1.333) rotate(-60)'/%3E%3Cuse href='%23s' transform='scale(1.45) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(1.6) rotate(10)'/%3E%3C/g%3E%3C/defs%3E%3Cg transform='translate(400 0)'%3E%3Cg transform='translate(0 375)'%3E%3Ccircle fill='url(%23a)' r='3000'/%3E%3Cg opacity='0.5'%3E%3Ccircle fill='url(%23a)' r='2000'/%3E%3Ccircle fill='url(%23a)' r='1800'/%3E%3Ccircle fill='url(%23a)' r='1700'/%3E%3Ccircle fill='url(%23a)' r='1651'/%3E%3Ccircle fill='url(%23a)' r='1450'/%3E%3Ccircle fill='url(%23a)' r='1250'/%3E%3Ccircle fill='url(%23a)' r='1175'/%3E%3Ccircle fill='url(%23a)' r='900'/%3E%3Ccircle fill='url(%23a)' r='750'/%3E%3Ccircle fill='url(%23a)' r='500'/%3E%3Ccircle fill='url(%23a)' r='380'/%3E%3Ccircle fill='url(%23a)' r='250'/%3E%3C/g%3E%3Cg transform='rotate(-273.6 0 0)'%3E%3Cuse href='%23g' transform='rotate(10)'/%3E%3Cuse href='%23g' transform='rotate(120)'/%3E%3Cuse href='%23g' transform='rotate(240)'/%3E%3C/g%3E%3Ccircle fill-opacity='0.99' fill='url(%23a)' r='3000'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`, + // backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 1500'%3E%3Cdefs%3E%3CradialGradient id='a' gradientUnits='objectBoundingBox'%3E%3Cstop offset='0' stop-color='%23000000'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/radialGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='0' y1='750' x2='1550' y2='750'%3E%3Cstop offset='0' stop-color='%232c3379'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/linearGradient%3E%3Cpath id='s' fill='url(%23b)' d='M1549.2 51.6c-5.4 99.1-20.2 197.6-44.2 293.6c-24.1 96-57.4 189.4-99.3 278.6c-41.9 89.2-92.4 174.1-150.3 253.3c-58 79.2-123.4 152.6-195.1 219c-71.7 66.4-149.6 125.8-232.2 177.2c-82.7 51.4-170.1 94.7-260.7 129.1c-90.6 34.4-184.4 60-279.5 76.3C192.6 1495 96.1 1502 0 1500c96.1-2.1 191.8-13.3 285.4-33.6c93.6-20.2 185-49.5 272.5-87.2c87.6-37.7 171.3-83.8 249.6-137.3c78.4-53.5 151.5-114.5 217.9-181.7c66.5-67.2 126.4-140.7 178.6-218.9c52.3-78.3 96.9-161.4 133-247.9c36.1-86.5 63.8-176.2 82.6-267.6c18.8-91.4 28.6-184.4 29.6-277.4c0.3-27.6 23.2-48.7 50.8-48.4s49.5 21.8 49.2 49.5c0 0.7 0 1.3-0.1 2L1549.2 51.6z'/%3E%3Cg id='g'%3E%3Cuse href='%23s' transform='scale(0.12) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.2) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.25) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(0.3) rotate(-20)'/%3E%3Cuse href='%23s' transform='scale(0.4) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(0.5) rotate(20)'/%3E%3Cuse href='%23s' transform='scale(0.6) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.7) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.835) rotate(-40)'/%3E%3Cuse href='%23s' transform='scale(0.9) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(1.05) rotate(25)'/%3E%3Cuse href='%23s' transform='scale(1.2) rotate(8)'/%3E%3Cuse href='%23s' transform='scale(1.333) rotate(-60)'/%3E%3Cuse href='%23s' transform='scale(1.45) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(1.6) rotate(10)'/%3E%3C/g%3E%3C/defs%3E%3Cg transform='translate(400 0)'%3E%3Cg transform='translate(0 375)'%3E%3Ccircle fill='url(%23a)' r='3000'/%3E%3Cg opacity='0.5'%3E%3Ccircle fill='url(%23a)' r='2000'/%3E%3Ccircle fill='url(%23a)' r='1800'/%3E%3Ccircle fill='url(%23a)' r='1700'/%3E%3Ccircle fill='url(%23a)' r='1651'/%3E%3Ccircle fill='url(%23a)' r='1450'/%3E%3Ccircle fill='url(%23a)' r='1250'/%3E%3Ccircle fill='url(%23a)' r='1175'/%3E%3Ccircle fill='url(%23a)' r='900'/%3E%3Ccircle fill='url(%23a)' r='750'/%3E%3Ccircle fill='url(%23a)' r='500'/%3E%3Ccircle fill='url(%23a)' r='380'/%3E%3Ccircle fill='url(%23a)' r='250'/%3E%3C/g%3E%3Cg transform='rotate(-273.6 0 0)'%3E%3Cuse href='%23g' transform='rotate(10)'/%3E%3Cuse href='%23g' transform='rotate(120)'/%3E%3Cuse href='%23g' transform='rotate(240)'/%3E%3C/g%3E%3Ccircle fill-opacity='0.99' fill='url(%23a)' r='3000'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`, + backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 1500'%3E%3Cdefs%3E%3CradialGradient id='a' gradientUnits='objectBoundingBox'%3E%3Cstop offset='0' stop-color='%23000000'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/radialGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='0' y1='750' x2='1550' y2='750'%3E%3Cstop offset='0' stop-color='%232c3379'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/linearGradient%3E%3Cpath id='s' fill='url(%23b)' d='M1549.2 51.6c-5.4 99.1-20.2 197.6-44.2 293.6c-24.1 96-57.4 189.4-99.3 278.6c-41.9 89.2-92.4 174.1-150.3 253.3c-58 79.2-123.4 152.6-195.1 219c-71.7 66.4-149.6 125.8-232.2 177.2c-82.7 51.4-170.1 94.7-260.7 129.1c-90.6 34.4-184.4 60-279.5 76.3C192.6 1495 96.1 1502 0 1500c96.1-2.1 191.8-13.3 285.4-33.6c93.6-20.2 185-49.5 272.5-87.2c87.6-37.7 171.3-83.8 249.6-137.3c78.4-53.5 151.5-114.5 217.9-181.7c66.5-67.2 126.4-140.7 178.6-218.9c52.3-78.3 96.9-161.4 133-247.9c36.1-86.5 63.8-176.2 82.6-267.6c18.8-91.4 28.6-184.4 29.6-277.4c0.3-27.6 23.2-48.7 50.8-48.4s49.5 21.8 49.2 49.5c0 0.7 0 1.3-0.1 2L1549.2 51.6z'/%3E%3Cg id='g'%3E%3Cuse href='%23s' transform='scale(0.12) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.2) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.25) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(0.3) rotate(-20)'/%3E%3Cuse href='%23s' transform='scale(0.4) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(0.5) rotate(20)'/%3E%3Cuse href='%23s' transform='scale(0.6) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.7) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.835) rotate(-40)'/%3E%3Cuse href='%23s' transform='scale(0.9) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(1.05) rotate(25)'/%3E%3Cuse href='%23s' transform='scale(1.2) rotate(8)'/%3E%3Cuse href='%23s' transform='scale(1.333) rotate(-60)'/%3E%3Cuse href='%23s' transform='scale(1.45) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(1.6) rotate(10)'/%3E%3C/g%3E%3C/defs%3E%3Cg transform='translate(400 0)'%3E%3Cg %3E%3Ccircle fill='url(%23a)' r='3000'/%3E%3Cg opacity='0.5'%3E%3Ccircle fill='url(%23a)' r='2000'/%3E%3Ccircle fill='url(%23a)' r='1800'/%3E%3Ccircle fill='url(%23a)' r='1700'/%3E%3Ccircle fill='url(%23a)' r='1651'/%3E%3Ccircle fill='url(%23a)' r='1450'/%3E%3Ccircle fill='url(%23a)' r='1250'/%3E%3Ccircle fill='url(%23a)' r='1175'/%3E%3Ccircle fill='url(%23a)' r='900'/%3E%3Ccircle fill='url(%23a)' r='750'/%3E%3Ccircle fill='url(%23a)' r='500'/%3E%3Ccircle fill='url(%23a)' r='380'/%3E%3Ccircle fill='url(%23a)' r='250'/%3E%3C/g%3E%3Cg transform='rotate(-273.6 0 0)'%3E%3Cuse href='%23g' transform='rotate(10)'/%3E%3Cuse href='%23g' transform='rotate(120)'/%3E%3Cuse href='%23g' transform='rotate(240)'/%3E%3C/g%3E%3Ccircle fill-opacity='0.79' fill='url(%23a)' r='3000'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`, backgroundAttachment: "fixed", backgroundSize: "cover", transition: "background 0.3s ease-in-out", backdropFilter: "blur(2.5px)", borderBottom: `2px solid ${Colors.primary.dark}`, + boxShadow: `0px 0px 10px ${Colors.lightGray}`, left: "0", height: "6rem", }} @@ -134,7 +136,8 @@ const FullScreen = () => { height: "calc(100vh - 6rem)", boxSizing: "border-box", marginTop: "6rem", - backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 1500'%3E%3Cdefs%3E%3CradialGradient id='a' gradientUnits='objectBoundingBox'%3E%3Cstop offset='0' stop-color='%23000000'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/radialGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='0' y1='750' x2='1550' y2='750'%3E%3Cstop offset='0' stop-color='%232c3379'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/linearGradient%3E%3Cpath id='s' fill='url(%23b)' d='M1549.2 51.6c-5.4 99.1-20.2 197.6-44.2 293.6c-24.1 96-57.4 189.4-99.3 278.6c-41.9 89.2-92.4 174.1-150.3 253.3c-58 79.2-123.4 152.6-195.1 219c-71.7 66.4-149.6 125.8-232.2 177.2c-82.7 51.4-170.1 94.7-260.7 129.1c-90.6 34.4-184.4 60-279.5 76.3C192.6 1495 96.1 1502 0 1500c96.1-2.1 191.8-13.3 285.4-33.6c93.6-20.2 185-49.5 272.5-87.2c87.6-37.7 171.3-83.8 249.6-137.3c78.4-53.5 151.5-114.5 217.9-181.7c66.5-67.2 126.4-140.7 178.6-218.9c52.3-78.3 96.9-161.4 133-247.9c36.1-86.5 63.8-176.2 82.6-267.6c18.8-91.4 28.6-184.4 29.6-277.4c0.3-27.6 23.2-48.7 50.8-48.4s49.5 21.8 49.2 49.5c0 0.7 0 1.3-0.1 2L1549.2 51.6z'/%3E%3Cg id='g'%3E%3Cuse href='%23s' transform='scale(0.12) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.2) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.25) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(0.3) rotate(-20)'/%3E%3Cuse href='%23s' transform='scale(0.4) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(0.5) rotate(20)'/%3E%3Cuse href='%23s' transform='scale(0.6) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.7) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.835) rotate(-40)'/%3E%3Cuse href='%23s' transform='scale(0.9) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(1.05) rotate(25)'/%3E%3Cuse href='%23s' transform='scale(1.2) rotate(8)'/%3E%3Cuse href='%23s' transform='scale(1.333) rotate(-60)'/%3E%3Cuse href='%23s' transform='scale(1.45) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(1.6) rotate(10)'/%3E%3C/g%3E%3C/defs%3E%3Cg transform='rotate(0 0 0)'%3E%3Cg transform='rotate(0 0 0)'%3E%3Ccircle fill='url(%23a)' r='3000'/%3E%3Cg opacity='0.5'%3E%3Ccircle fill='url(%23a)' r='2000'/%3E%3Ccircle fill='url(%23a)' r='1800'/%3E%3Ccircle fill='url(%23a)' r='1700'/%3E%3Ccircle fill='url(%23a)' r='1651'/%3E%3Ccircle fill='url(%23a)' r='1450'/%3E%3Ccircle fill='url(%23a)' r='1250'/%3E%3Ccircle fill='url(%23a)' r='1175'/%3E%3Ccircle fill='url(%23a)' r='900'/%3E%3Ccircle fill='url(%23a)' r='750'/%3E%3Ccircle fill='url(%23a)' r='500'/%3E%3Ccircle fill='url(%23a)' r='380'/%3E%3Ccircle fill='url(%23a)' r='250'/%3E%3C/g%3E%3Cg transform='rotate(0 0 0)'%3E%3Cuse href='%23g' transform='rotate(10)'/%3E%3Cuse href='%23g' transform='rotate(120)'/%3E%3Cuse href='%23g' transform='rotate(240)'/%3E%3C/g%3E%3Ccircle fill-opacity='0.83' fill='url(%23a)' r='3000'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`, + // backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 1500'%3E%3Cdefs%3E%3CradialGradient id='a' gradientUnits='objectBoundingBox'%3E%3Cstop offset='0' stop-color='%23282C56'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/radialGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='0' y1='750' x2='1550' y2='750'%3E%3Cstop offset='0' stop-color='%234049a4'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/linearGradient%3E%3Cpath id='s' fill='url(%23b)' d='M1549.2 51.6c-5.4 99.1-20.2 197.6-44.2 293.6c-24.1 96-57.4 189.4-99.3 278.6c-41.9 89.2-92.4 174.1-150.3 253.3c-58 79.2-123.4 152.6-195.1 219c-71.7 66.4-149.6 125.8-232.2 177.2c-82.7 51.4-170.1 94.7-260.7 129.1c-90.6 34.4-184.4 60-279.5 76.3C192.6 1495 96.1 1502 0 1500c96.1-2.1 191.8-13.3 285.4-33.6c93.6-20.2 185-49.5 272.5-87.2c87.6-37.7 171.3-83.8 249.6-137.3c78.4-53.5 151.5-114.5 217.9-181.7c66.5-67.2 126.4-140.7 178.6-218.9c52.3-78.3 96.9-161.4 133-247.9c36.1-86.5 63.8-176.2 82.6-267.6c18.8-91.4 28.6-184.4 29.6-277.4c0.3-27.6 23.2-48.7 50.8-48.4s49.5 21.8 49.2 49.5c0 0.7 0 1.3-0.1 2L1549.2 51.6z'/%3E%3Cg id='g'%3E%3Cuse href='%23s' transform='scale(0.12) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.2) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.25) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(0.3) rotate(-20)'/%3E%3Cuse href='%23s' transform='scale(0.4) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(0.5) rotate(20)'/%3E%3Cuse href='%23s' transform='scale(0.6) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.7) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.835) rotate(-40)'/%3E%3Cuse href='%23s' transform='scale(0.9) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(1.05) rotate(25)'/%3E%3Cuse href='%23s' transform='scale(1.2) rotate(8)'/%3E%3Cuse href='%23s' transform='scale(1.333) rotate(-60)'/%3E%3Cuse href='%23s' transform='scale(1.45) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(1.6) rotate(10)'/%3E%3C/g%3E%3C/defs%3E%3Cg transform='translate(400 0)'%3E%3Cg %3E%3Ccircle fill='url(%23a)' r='3000'/%3E%3Cg opacity='0.5'%3E%3Ccircle fill='url(%23a)' r='2000'/%3E%3Ccircle fill='url(%23a)' r='1800'/%3E%3Ccircle fill='url(%23a)' r='1700'/%3E%3Ccircle fill='url(%23a)' r='1651'/%3E%3Ccircle fill='url(%23a)' r='1450'/%3E%3Ccircle fill='url(%23a)' r='1250'/%3E%3Ccircle fill='url(%23a)' r='1175'/%3E%3Ccircle fill='url(%23a)' r='900'/%3E%3Ccircle fill='url(%23a)' r='750'/%3E%3Ccircle fill='url(%23a)' r='500'/%3E%3Ccircle fill='url(%23a)' r='380'/%3E%3Ccircle fill='url(%23a)' r='250'/%3E%3C/g%3E%3Cg transform='rotate(-273.6 0 0)'%3E%3Cuse href='%23g' transform='rotate(10)'/%3E%3Cuse href='%23g' transform='rotate(120)'/%3E%3Cuse href='%23g' transform='rotate(240)'/%3E%3C/g%3E%3Ccircle fill-opacity='0.61' fill='url(%23a)' r='3000'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`, + backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 1500'%3E%3Cdefs%3E%3CradialGradient id='a' gradientUnits='objectBoundingBox'%3E%3Cstop offset='0' stop-color='%23000000'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/radialGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='0' y1='750' x2='1550' y2='750'%3E%3Cstop offset='0' stop-color='%232c3379'/%3E%3Cstop offset='1' stop-color='%235865F2'/%3E%3C/linearGradient%3E%3Cpath id='s' fill='url(%23b)' d='M1549.2 51.6c-5.4 99.1-20.2 197.6-44.2 293.6c-24.1 96-57.4 189.4-99.3 278.6c-41.9 89.2-92.4 174.1-150.3 253.3c-58 79.2-123.4 152.6-195.1 219c-71.7 66.4-149.6 125.8-232.2 177.2c-82.7 51.4-170.1 94.7-260.7 129.1c-90.6 34.4-184.4 60-279.5 76.3C192.6 1495 96.1 1502 0 1500c96.1-2.1 191.8-13.3 285.4-33.6c93.6-20.2 185-49.5 272.5-87.2c87.6-37.7 171.3-83.8 249.6-137.3c78.4-53.5 151.5-114.5 217.9-181.7c66.5-67.2 126.4-140.7 178.6-218.9c52.3-78.3 96.9-161.4 133-247.9c36.1-86.5 63.8-176.2 82.6-267.6c18.8-91.4 28.6-184.4 29.6-277.4c0.3-27.6 23.2-48.7 50.8-48.4s49.5 21.8 49.2 49.5c0 0.7 0 1.3-0.1 2L1549.2 51.6z'/%3E%3Cg id='g'%3E%3Cuse href='%23s' transform='scale(0.12) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.2) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.25) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(0.3) rotate(-20)'/%3E%3Cuse href='%23s' transform='scale(0.4) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(0.5) rotate(20)'/%3E%3Cuse href='%23s' transform='scale(0.6) rotate(60)'/%3E%3Cuse href='%23s' transform='scale(0.7) rotate(10)'/%3E%3Cuse href='%23s' transform='scale(0.835) rotate(-40)'/%3E%3Cuse href='%23s' transform='scale(0.9) rotate(40)'/%3E%3Cuse href='%23s' transform='scale(1.05) rotate(25)'/%3E%3Cuse href='%23s' transform='scale(1.2) rotate(8)'/%3E%3Cuse href='%23s' transform='scale(1.333) rotate(-60)'/%3E%3Cuse href='%23s' transform='scale(1.45) rotate(-30)'/%3E%3Cuse href='%23s' transform='scale(1.6) rotate(10)'/%3E%3C/g%3E%3C/defs%3E%3Cg transform='translate(400 0)'%3E%3Cg %3E%3Ccircle fill='url(%23a)' r='3000'/%3E%3Cg opacity='0.5'%3E%3Ccircle fill='url(%23a)' r='2000'/%3E%3Ccircle fill='url(%23a)' r='1800'/%3E%3Ccircle fill='url(%23a)' r='1700'/%3E%3Ccircle fill='url(%23a)' r='1651'/%3E%3Ccircle fill='url(%23a)' r='1450'/%3E%3Ccircle fill='url(%23a)' r='1250'/%3E%3Ccircle fill='url(%23a)' r='1175'/%3E%3Ccircle fill='url(%23a)' r='900'/%3E%3Ccircle fill='url(%23a)' r='750'/%3E%3Ccircle fill='url(%23a)' r='500'/%3E%3Ccircle fill='url(%23a)' r='380'/%3E%3Ccircle fill='url(%23a)' r='250'/%3E%3C/g%3E%3Cg transform='rotate(-273.6 0 0)'%3E%3Cuse href='%23g' transform='rotate(10)'/%3E%3Cuse href='%23g' transform='rotate(120)'/%3E%3Cuse href='%23g' transform='rotate(240)'/%3E%3C/g%3E%3Ccircle fill-opacity='0.79' fill='url(%23a)' r='3000'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`, backgroundAttachment: "fixed", backgroundSize: "cover", overflow: "auto", diff --git a/src/modules/universe/NeuroJsonGraph.tsx b/src/modules/universe/NeuroJsonGraph.tsx index 83934e3..df0e59d 100644 --- a/src/modules/universe/NeuroJsonGraph.tsx +++ b/src/modules/universe/NeuroJsonGraph.tsx @@ -172,7 +172,7 @@ const NeuroJsonGraph: React.FC<{ // Initialize 3D Force Graph const Graph = new ForceGraph3D(graphRef.current) .graphData(graphData) - .nodeRelSize(1) + .nodeRelSize(2) .nodeColor((node) => (node as NodeObject).color) .linkWidth(1) .backgroundColor("rgba(0,0,0,0)") @@ -215,7 +215,7 @@ const NeuroJsonGraph: React.FC<{ const glowMaterial = new THREE.MeshBasicMaterial({ color: (castNode as any).color, transparent: true, - opacity: 0.2, + opacity: 0.5, }); const glow = new THREE.Mesh(glowGeometry, glowMaterial); diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 29fc2fc..2f4679e 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -97,11 +97,12 @@ const Home: React.FC = () => { variant="contained" sx={{ backgroundColor: Colors.green, - color: Colors.white, + color: Colors.darkPurple, fontWeight: "Bold", "&:hover": { - backgroundColor: Colors.darkGreen, - boxShadow: `0px 0px 15px ${Colors.green}`, + backgroundColor: Colors.darkPurple, + color: Colors.green, + boxShadow: `0px 0px 15px ${Colors.darkGreen}`, }, }} onClick={() => navigate("/databases")} From 29ff1f9022451cfa940ebee22ffc9418df167922 Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Thu, 13 Mar 2025 00:24:46 -0400 Subject: [PATCH 12/20] modify build-deploy-zodiac.yml for deploy on zodiac --- .github/workflows/build-deploy-zodiac.yml | 21 ++++++------ src/modules/universe/NeuroJsonGraph.tsx | 39 +++++++++++++---------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/.github/workflows/build-deploy-zodiac.yml b/.github/workflows/build-deploy-zodiac.yml index 4c7f7bd..31bd848 100644 --- a/.github/workflows/build-deploy-zodiac.yml +++ b/.github/workflows/build-deploy-zodiac.yml @@ -10,7 +10,7 @@ on: jobs: deploy: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Check out the repository @@ -26,14 +26,11 @@ jobs: id: get_branch run: echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV - - name: Copy files to the server via SCP - run: | - echo "Deploying to /var/www/html/dev/${{ env.BRANCH_NAME }}/" - scp -r -o StrictHostKeyChecking=no ./build/* ${{ secrets.NEUROJ_SERVER_USER }}@${{ secrets.NEUROJ_SERVER }}:/var/www/html/dev/${{ env.BRANCH_NAME }}/ - - - name: Restart Server (Only in the deployed folder) - run: | - echo "Restarting services in /var/www/html/dev/${{ env.BRANCH_NAME }}/" - ssh -o StrictHostKeyChecking=no ${{ secrets.NEUROJ_SERVER_USER }}@${{ secrets.NEUROJ_SERVER }} << EOF - cd /var/www/html/dev/${{ env.BRANCH_NAME }}/ && pm2 restart all || echo "No PM2 processes found in this directory" - EOF + - name: Copy package to server + uses: NeuroJSON/SFTP-Deploy-Action@v1.2.5 + with: + server: ${{ secrets.NEUROJ_SERVER }} + username: ${{ secrets.NEUROJ_SERVER_USER }} + ssh_private_key: ${{ secrets.NEUROJ_SERVER_SSH_KEY }} + local_path: "./build/*" + remote_path: "${{ secrets.NEUROJ_CI_PATH }}/${{ env.BRANCH_NAME }}" diff --git a/src/modules/universe/NeuroJsonGraph.tsx b/src/modules/universe/NeuroJsonGraph.tsx index df0e59d..a7b571b 100644 --- a/src/modules/universe/NeuroJsonGraph.tsx +++ b/src/modules/universe/NeuroJsonGraph.tsx @@ -30,17 +30,22 @@ const NeuroJsonGraph: React.FC<{ // Define the datatype to color mapping const DATA_TYPE_COLORS: Record = { - mri: [79, 51, 130], - fmri: [10, 81, 20], - pet: [0, 105, 192], - meg: [156, 57, 0], - eeg: [134, 31, 55], - ieeg: [18, 109, 62], - beh: [12, 93, 210], - fmap: [255, 255, 59], - dwi: [200, 9, 12], - fnirs: [255, 193, 7], - phenotype: [255, 87, 34], + // mri: [79, 51, 130], // deep purple + mri: [160, 138, 233], // soft laender + anat: [160, 138, 233], + // fmri: [10, 81, 20], // dark green + fmri: [152, 202, 32], // bright lime green + func: [152, 202, 32], + + pet: [0, 105, 192], // deep blue + meg: [156, 57, 0], // dark reddish-brown + eeg: [134, 31, 55], // dark red-pink + ieeg: [18, 109, 62], // forest green + beh: [12, 93, 210], // bright blue + fmap: [255, 255, 59], // vivid yellow + dwi: [200, 9, 12], // deep red + fnirs: [255, 193, 7], // golden yellow + phenotype: [255, 87, 34], // vibrant orange-red }; // Function to blend colors based on datatypes @@ -64,9 +69,9 @@ const NeuroJsonGraph: React.FC<{ if (count === 0) count = 1; // Prevent division by zero - const avgR = Math.floor(totalR / count); - const avgG = Math.floor(totalG / count); - const avgB = Math.floor(totalB / count); + let avgR = Math.floor(totalR / count); + let avgG = Math.floor(totalG / count); + let avgB = Math.floor(totalB / count); return `rgb(${avgR}, ${avgG}, ${avgB})`; }; @@ -117,7 +122,7 @@ const NeuroJsonGraph: React.FC<{ nodes: registry.map((db) => { const color = blendColors(db.datatype); let size = - db.datasets > 100 ? Math.log(db.datasets) * 2.5 : db.datasets / 6; + db.datasets > 100 ? Math.log(db.datasets) * 2.5 : db.datasets / 7; size = Math.max(size, 4); return { @@ -172,9 +177,9 @@ const NeuroJsonGraph: React.FC<{ // Initialize 3D Force Graph const Graph = new ForceGraph3D(graphRef.current) .graphData(graphData) - .nodeRelSize(2) + .nodeRelSize(1) .nodeColor((node) => (node as NodeObject).color) - .linkWidth(1) + .linkWidth(2) .backgroundColor("rgba(0,0,0,0)") .nodeLabel("name") .onNodeHover((node) => { From d7d05a16de39341008f80522e339e97dd29c9ea6 Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Thu, 13 Mar 2025 10:19:09 -0400 Subject: [PATCH 13/20] Update GitHub Actions: Set PUBLIC_URL dynamically for branch-based deployment --- .github/workflows/build-deploy-zodiac.yml | 6 ++++-- src/App.tsx | 14 +++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-deploy-zodiac.yml b/.github/workflows/build-deploy-zodiac.yml index 31bd848..2c0f351 100644 --- a/.github/workflows/build-deploy-zodiac.yml +++ b/.github/workflows/build-deploy-zodiac.yml @@ -19,8 +19,10 @@ jobs: - name: Install dependencies run: yarn install --frozen-lockfile - - name: Build React App - run: yarn build + - name: Build React App with Dynamic PUBLIC_URL + run: | + echo "Building for /dev/${{ env.BRANCH_NAME}}/" + PUBLIC_URL="/dev/${{ env.BRANCH_NAME}}/" yarn build - name: Determine Branch Name id: get_branch diff --git a/src/App.tsx b/src/App.tsx index fb09efa..f078fb1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,13 +4,13 @@ import theme from "design/theme"; import { BrowserRouter } from "react-router-dom"; const App = () => { - return ( - - - - - - ); + return ( + + + + + + ); }; export default App; From bb2e0cf5ace309f8813e5397bf8ca6db8fcd832c Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Thu, 13 Mar 2025 10:26:56 -0400 Subject: [PATCH 14/20] Update GitHub Actions: Set PUBLIC_URL for dev-fan branch deployment --- .github/workflows/build-deploy-zodiac.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-deploy-zodiac.yml b/.github/workflows/build-deploy-zodiac.yml index 2c0f351..22c1d0c 100644 --- a/.github/workflows/build-deploy-zodiac.yml +++ b/.github/workflows/build-deploy-zodiac.yml @@ -21,8 +21,8 @@ jobs: - name: Build React App with Dynamic PUBLIC_URL run: | - echo "Building for /dev/${{ env.BRANCH_NAME}}/" - PUBLIC_URL="/dev/${{ env.BRANCH_NAME}}/" yarn build + echo "Building for /dev/dev-fan/" + PUBLIC_URL="/dev/dev-fan/" yarn build - name: Determine Branch Name id: get_branch From f8bc6c2bc2fdfa1a9ce3f2967092a0a574a68b13 Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Thu, 13 Mar 2025 15:03:14 -0400 Subject: [PATCH 15/20] Update GitHub Actions: Set PUBLIC_URL dynamically for branch-based deployment --- .github/workflows/build-deploy-zodiac.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-deploy-zodiac.yml b/.github/workflows/build-deploy-zodiac.yml index 22c1d0c..ce63c85 100644 --- a/.github/workflows/build-deploy-zodiac.yml +++ b/.github/workflows/build-deploy-zodiac.yml @@ -19,15 +19,15 @@ jobs: - name: Install dependencies run: yarn install --frozen-lockfile - - name: Build React App with Dynamic PUBLIC_URL - run: | - echo "Building for /dev/dev-fan/" - PUBLIC_URL="/dev/dev-fan/" yarn build - - name: Determine Branch Name id: get_branch run: echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV + - name: Build React App with Dynamic PUBLIC_URL + run: | + echo "Building for /dev/${{ env.BRANCH_NAME }}/" + PUBLIC_URL="/dev/${{ env.BRANCH_NAME }}/" yarn build + - name: Copy package to server uses: NeuroJSON/SFTP-Deploy-Action@v1.2.5 with: From 9887d3f632269695ad7a8b629aeaddf2d5e52b2a Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Thu, 13 Mar 2025 17:32:12 -0400 Subject: [PATCH 16/20] Fix validation workflow to include PUBLIC_URL --- .github/workflows/validate.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 7f0df57..30527af 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -25,7 +25,8 @@ jobs: run: yarn lint - name: Compile TypeScript - run: yarn build + run: | + PUBLIC_URL="/dev/${{ github.head_ref }}/" yarn build - name: Run Security Audit run: yarn audit --level moderate From 46d12ed9774f527df3de9c34be927d90d23c5907 Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Thu, 13 Mar 2025 18:00:56 -0400 Subject: [PATCH 17/20] Add lint script to package.json --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 58e3bed..757146a 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,8 @@ "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", - "eject": "react-scripts eject" + "eject": "react-scripts eject", + "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}' --ext .js,.jsx,.ts,.tsx" }, "browserslist": { "production": [ From 2a79b366dd9309a826832e2ce0fa14f478025a74 Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Thu, 13 Mar 2025 18:07:20 -0400 Subject: [PATCH 18/20] Temporarily disable lint step to test the workflow --- .github/workflows/validate.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 30527af..de76fdb 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -21,8 +21,8 @@ jobs: - name: Install dependencies run: yarn install - - name: Run Linter (Report Issues) - run: yarn lint + # - name: Run Linter (Report Issues) + # run: yarn lint - name: Compile TypeScript run: | From 343d164d443445cbfeed9b4f7ee354698da92d06 Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Fri, 14 Mar 2025 10:04:19 -0400 Subject: [PATCH 19/20] Upgrade axios to 1.8.2 to fix high-severity vulnerability --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 757146a..e5aec52 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@types/three": "^0.169.0", - "axios": "^1.4.0", + "axios": "1.8.2", "dayjs": "^1.11.10", "jwt-decode": "^3.1.2", "query-string": "^8.1.0", diff --git a/yarn.lock b/yarn.lock index 7489c6e..719f82b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3214,10 +3214,10 @@ axe-core@^4.10.0: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.2.tgz#85228e3e1d8b8532a27659b332e39b7fa0e022df" integrity sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w== -axios@^1.4.0: - version "1.7.9" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a" - integrity sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw== +axios@1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.8.2.tgz#fabe06e241dfe83071d4edfbcaa7b1c3a40f7979" + integrity sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" From f01065a0ae5ee6d34abd5b81ac6f5947b9b4836d Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Fri, 14 Mar 2025 10:31:47 -0400 Subject: [PATCH 20/20] Upgrade @babel/runtime and @babel/helpers to 7.26.10 --- package.json | 6 +++++- yarn.lock | 51 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index e5aec52..34dbd49 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,8 @@ "private": true, "dependencies": { "3d-force-graph": "^1.73.4", + "@babel/helpers": "7.26.10", + "@babel/runtime": "7.26.10", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@mui/icons-material": "^5.14.3", @@ -67,6 +69,8 @@ }, "resolutions": { "postcss": "^8.4.31", - "nth-check": "^2.0.1" + "nth-check": "^2.0.1", + "@babel/runtime": "7.26.10", + "@babel/helpers": "7.26.10" } } diff --git a/yarn.lock b/yarn.lock index 719f82b..b969880 100644 --- a/yarn.lock +++ b/yarn.lock @@ -271,13 +271,13 @@ "@babel/traverse" "^7.25.9" "@babel/types" "^7.25.9" -"@babel/helpers@^7.26.0": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.0.tgz#30e621f1eba5aa45fe6f4868d2e9154d884119a4" - integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw== +"@babel/helpers@7.26.10", "@babel/helpers@^7.26.0": + version "7.26.10" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.10.tgz#6baea3cd62ec2d0c1068778d63cb1314f6637384" + integrity sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g== dependencies: - "@babel/template" "^7.25.9" - "@babel/types" "^7.26.0" + "@babel/template" "^7.26.9" + "@babel/types" "^7.26.10" "@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.5", "@babel/parser@^7.20.7", "@babel/parser@^7.23.0", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.5": version "7.26.5" @@ -286,6 +286,13 @@ dependencies: "@babel/types" "^7.26.5" +"@babel/parser@^7.26.9": + version "7.26.10" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.10.tgz#e9bdb82f14b97df6569b0b038edd436839c57749" + integrity sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA== + dependencies: + "@babel/types" "^7.26.10" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz#cc2e53ebf0a0340777fff5ed521943e253b4d8fe" @@ -1103,17 +1110,10 @@ "@babel/plugin-transform-modules-commonjs" "^7.25.9" "@babel/plugin-transform-typescript" "^7.25.9" -"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.23.9", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" - integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/runtime@^7.20.13": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.7.tgz#f4e7fe527cd710f8dc0618610b61b4b060c3c341" - integrity sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ== +"@babel/runtime@7.26.10", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.13", "@babel/runtime@^7.23.9", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.26.10" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.10.tgz#a07b4d8fa27af131a633d7b3524db803eb4764c2" + integrity sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw== dependencies: regenerator-runtime "^0.14.0" @@ -1126,6 +1126,15 @@ "@babel/parser" "^7.25.9" "@babel/types" "^7.25.9" +"@babel/template@^7.26.9": + version "7.26.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.26.9.tgz#4577ad3ddf43d194528cff4e1fa6b232fa609bb2" + integrity sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/parser" "^7.26.9" + "@babel/types" "^7.26.9" + "@babel/traverse@7.23.2": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" @@ -1171,6 +1180,14 @@ "@babel/helper-string-parser" "^7.25.9" "@babel/helper-validator-identifier" "^7.25.9" +"@babel/types@^7.26.10", "@babel/types@^7.26.9": + version "7.26.10" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.10.tgz#396382f6335bd4feb65741eacfc808218f859259" + integrity sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"