Directory Structure:
└── ./
└── frontend
├── src
│ ├── components
│ │ ├── BrainRenderer.jsx
│ │ ├── ChatUploadPage.jsx
│ │ ├── Footer.jsx
│ │ ├── Hero.jsx
│ │ ├── Navbar.jsx
│ │ ├── Products.jsx
│ │ └── Research.jsx
│ ├── App.css
│ ├── App.jsx
│ ├── index.css
│ └── main.jsx
├── eslint.config.js
├── index.html
└── vite.config.js
---
File: /frontend/src/components/BrainRenderer.jsx
---
import React, { useEffect, useRef } from "react";
import * as THREE from "three";
const BrainRenderer = ({ file }) => {
const mountRef = useRef(null);
useEffect(() => {
if (!file) return;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(400, 400);
mountRef.current.appendChild(renderer.domElement);
const geometry = new THREE.SphereGeometry(1, 32, 32);
const material = new THREE.MeshBasicMaterial({ color: 0xff6347, wireframe: true
});
const brainModel = new THREE.Mesh(geometry, material);
scene.add(brainModel);
camera.position.z = 3;
const animate = () => {
requestAnimationFrame(animate);
brainModel.rotation.y += 0.01;
renderer.render(scene, camera);
};
animate();
return () => {
mountRef.current.removeChild(renderer.domElement);
};
}, [file]);
return <div ref={mountRef} className="w-full h-full flex justify-center items-
center" />;
};
export default BrainRenderer;
---
File: /frontend/src/components/ChatUploadPage.jsx
---
import React, { useState } from "react";
import { useDropzone } from "react-dropzone";
import BrainRenderer from "./BrainRenderer"; // Assuming this component renders the
3D model
import "tailwindcss/tailwind.css";
const ChatUploadPage = () => {
const [file, setFile] = useState(null);
const [showModal, setShowModal] = useState(false);
const { getRootProps, getInputProps } = useDropzone({
accept: ".nii,.nii.gz",
onDrop: (acceptedFiles) => {
setFile(acceptedFiles[0]);
setShowModal(true); // Show the modal when file is uploaded
},
});
return (
<div className="flex flex-col items-center justify-center h-screen bg-gray-900
text-white">
{/* Chat & Upload UI */}
<div {...getRootProps()} className="border-2 border-dashed p-10 rounded-lg
cursor-pointer bg-gray-800">
<input {...getInputProps()} />
<p>Drop your NIfTI file here or click to upload</p>
</div>
{/* Modal for Brain Rendering */}
{showModal && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center
justify-center">
<div className="bg-gray-800 p-6 rounded-lg relative w-3/4 h-3/4 flex
flex-col items-center">
<button
className="absolute top-4 right-4 bg-red-500 p-2 rounded-full"
onClick={() => setShowModal(false)}
>
✕
</button>
<h2 className="text-xl font-bold mb-4">Brain Segmentation Model</h2>
<div className="w-full h-full flex justify-center items-center">
<BrainRenderer file={file} />
</div>
</div>
</div>
)}
</div>
);
};
export default ChatUploadPage;
---
File: /frontend/src/components/Footer.jsx
---
function Footer() {
return (
<footer className="footer">
<div className="footer-content">
<div className="footer-section">
<h4>Frameworks</h4>
<a href="#next">Next.js</a>
<a href="#nuxt">Nuxt.js</a>
<a href="#gatsby">Gatsby</a>
</div>
<div className="footer-section">
<h4>Resources</h4>
<a href="#docs">Documentation</a>
<a href="#guides">Guides</a>
<a href="#blog">Blog</a>
</div>
<div className="footer-section">
<h4>Company</h4>
<a href="#about">About</a>
<a href="#careers">Careers</a>
<a href="#contact">Contact</a>
</div>
<div className="footer-section">
<h4>Legal</h4>
<a href="#privacy">Privacy Policy</a>
<a href="#terms">Terms of Service</a>
</div>
</div>
<div className="footer-bottom">
<p>© 2024 Vercel Inc.</p>
</div>
</footer>
)
}
export default Footer
---
File: /frontend/src/components/Hero.jsx
---
import { useNavigate } from 'react-router-dom'
function Hero() {
const navigate = useNavigate();
return (
<section className="hero">
<div className="hero-gradient"></div>
<div className="hero-content">
<h1>NeuroVision</h1>
<p className="hero-subtitle">
Experience AI-powered brain tumor segmentation with interactive
visualization and VQA
</p>
<div className="hero-cta">
<button className="primary-btn" onClick={() => navigate('/chat')}>
Get Started
</button>
<button className="secondary-btn" onClick={() => navigate('/articles')}>
About Our Model
</button>
</div>
</div>
</section>
)
}
export default Hero
---
File: /frontend/src/components/Navbar.jsx
---
import { useState } from 'react';
function Navbar({ scrolled }) {
const [menuOpen, setMenuOpen] = useState(false);
return (
<nav className={`navbar ${scrolled ? 'scrolled' : ''}`}>
<div className="nav-content">
{/* Left side of the navbar - Platform Name */}
<div className="nav-left">
<div className="platform-name">NeuroVision</div>
</div>
{/* Right side of the navbar - Menu Links */}
<div className="nav-right">
<div className="nav-links">
<a href="#products" className="nav-item">Products</a>
<a href="#research" className="nav-item">Research</a>
<a href="#contactUs" className="nav-item">Contact Us</a>
</div>
{/* Mobile menu button */}
<button className="menu-btn" onClick={() => setMenuOpen(!menuOpen)}>
<span></span>
<span></span>
<span></span>
</button>
</div>
</div>
{/* Mobile menu (shown when menuOpen is true) */}
{menuOpen && (
<div className="mobile-menu">
<a href="#products">Products</a>
<a href="#research">Research</a>
<a href="#contactUs">Contact Us</a>
</div>
)}
</nav>
);
}
export default Navbar;
---
File: /frontend/src/components/Products.jsx
---
function Products() {
return (
<section className="products">
<h2 className="section-heading">Our Products</h2> {/* Added section heading
*/}
<div className="products-grid">
{/* Chatbot Product Card */}
<div className="product-card">
<h3>
<span className="icon">💬</span>
AI-powered Chatbot
</h3>
<p>Engage with patients and medical professionals in real-time through a
smart chatbot interface.</p>
</div>
{/* Brain Tumor Segmentation Product Card */}
<div className="product-card">
<h3>
<span className="icon">🧠</span>
Brain Tumor Segmentation
</h3>
<p>Accurately detect and segment brain tumors in medical images with AI-
driven precision.</p>
</div>
</div>
</section>
);
}
export default Products;
---
File: /frontend/src/components/Research.jsx
---
function Research() {
return (
<section className="research">
<h2>Research on Brain Tumor Segmentation</h2>
<div className="research-content">
<div className="research-text">
<p>Explore cutting-edge research on brain tumor segmentation using AI-
powered models like UNet3D and Swin UNETR.</p>
<button className="primary-btn">Read More</button>
</div>
</div>
</section>
);
}
export default Research;
---
File: /frontend/src/App.css
---
/* Reset and base styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--background-color: #000;
--text-color: #fff;
--secondary-text: rgba(255, 255, 255, 0.6);
--border-color: rgba(255, 255, 255, 0.1);
--accent-color: #fff;
--hover-color: rgba(255, 255, 255, 0.1);
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
line-height: 1.6;
color: var(--text-color);
background: var(--background-color);
}
/* Navbar styles */
.nav-content {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
}
.nav-right {
display: flex;
align-items: center;
gap: 2rem; /* Adds space between menu items */
}
.nav-links {
display: flex;
gap: 2rem; /* Controls spacing between Products, Research, and Contact Us */
}
.nav-item {
text-decoration: none;
color: inherit;
font-weight: bold;
}
/* Mobile menu button styling */
.menu-btn {
display: none; /* Hide by default on desktop */
}
/* Responsive styling */
@media (max-width: 768px) {
.nav-links {
display: none; /* Hide normal links */
}
.menu-btn {
display: block; /* Show mobile menu button */
}
.mobile-menu {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem;
}
}
/* Hero section styles */
.hero {
padding: 120px 20px 60px;
text-align: center;
max-width: 1200px;
margin: 0 auto;
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
position: relative;
}
.hero h1 {
font-size: 120px;
line-height: 1.1;
margin-bottom: 24px;
color: var(--text-color);
font-weight: 800;
}
.hero-subtitle {
font-size: 20px;
color: var(--secondary-text);
max-width: 600px;
margin: 0 auto 40px;
}
.hero-cta {
display: flex;
gap: 16px;
justify-content: center;
margin-bottom: 60px;
}
.primary-btn, .secondary-btn {
padding: 12px 32px;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
transition: all 0.2s ease;
font-weight: 500;
}
.primary-btn {
background: var(--text-color);
color: var(--background-color);
border: none;
}
.secondary-btn {
background: var(--text-color);
color: var(--background-color);
border: none;
}
.hero-gradient {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -30%);
width: 800px;
height: 800px;
background: radial-gradient(circle at center,
rgba(0, 255, 255, 0.15) 0%,
rgba(255, 0, 255, 0.15) 25%,
rgba(255, 255, 0, 0.15) 50%,
rgba(0, 0, 0, 0) 70%
);
pointer-events: none;
z-index: 1;
}
.hero-content {
position: relative;
z-index: 2;
}
/* Products section styles */
.products {
padding: 3rem 1.5rem;
background-color: #000;
text-align: center;
}
.section-heading {
font-size: 2rem;
font-weight: bold;
margin-bottom: 2rem;
color: #333;
}
/* Grid layout for the product cards */
.products-grid {
display: grid;
grid-template-columns: 1fr; /* 1 column for vertical layout */
gap: 2rem;
max-width: 1200px;
margin: 0 auto;
}
/* Product Card Styles */
.product-card {
background-color: #fff;
padding: 2rem;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transition: transform 300ms ease, box-shadow 300ms ease;
cursor: pointer; /* Makes the card clickable */
}
.product-card:hover {
transform: translateY(-10px); /* Slight enlargement effect on hover */
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15); /* Stronger shadow on hover */
}
/* Product Card Header */
/* Reset and base styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--background-color: #000;
--text-color: #fff;
--secondary-text: rgba(255, 255, 255, 0.6);
--border-color: rgba(255, 255, 255, 0.1);
--accent-color: #fff;
--hover-color: rgba(255, 255, 255, 0.1);
}
/* Body and general styles */
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
line-height: 1.6;
color: var(--text-color);
background: var(--background-color);
}
/* Products section styles */
.products {
padding: 3rem 1.5rem;
background-color: #1c1c1c; /* Dark background for products section */
text-align: center;
}
.section-heading {
font-size: 2rem;
font-weight: bold;
margin-bottom: 2rem;
color: var(--text-color);
}
/* Grid layout for the product cards side-by-side */
.products-grid {
display: grid;
grid-template-columns: 1fr 1fr; /* 2 columns for side-by-side layout */
gap: 2rem;
max-width: 1200px;
margin: 0 auto;
}
/* Product Card Styles */
.product-card {
background-color: #4f0fc5da; /* Dark card background */
padding: 2rem;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transition: transform 300ms ease, box-shadow 300ms ease;
cursor: pointer; /* Makes the card clickable */
width: 100%; /* Ensures the cards fill their grid area */
height: 350px; /* Fixed height to make cards longer */
color: var(--text-color); /* Text color */
}
.product-card:hover {
transform: translateY(-10px); /* Slight enlargement effect on hover */
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15); /* Stronger shadow on hover */
}
/* Product Card Header */
.product-card h3 {
font-size: 1.5rem;
color: var(--text-color);
margin-bottom: 1rem;
}
/* Icon Styling */
.product-card .icon {
font-size: 2.5rem;
margin-right: 0.5rem;
color: var(--accent-color); /* Accent color */
}
/* Product Description Styling */
.product-card p {
color: var(--secondary-text);
font-size: 1rem;
line-height: 1.5;
}
/* Mobile responsiveness */
@media (max-width: 768px) {
.products-grid {
grid-template-columns: 1fr; /* Single column for smaller screens */
}
.product-card {
height: 300px; /* Adjust height for mobile */
}
}
/* Research section styles */
/* Research Section Styling */
.research {
padding: 120px 20px 60px;
text-align: center;
max-width: 1200px;
margin: 0 auto;
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
position: relative;
}
.research h2 {
font-size: 64px; /* Reduced from 72px */
line-height: 1.1;
margin-bottom: 24px;
color: var(--text-color);
font-weight: 800;
}
.research-content {
display: flex;
justify-content: center;
align-items: center; /* Aligns elements properly */
gap: 2rem;
max-width: 1200px;
margin: 0 auto;
position: relative;
z-index: 2;
flex-wrap: wrap; /* Allows better responsiveness */
}
.research-text {
max-width: 600px;
text-align: left; /* Aligns text properly */
}
.research-text p {
font-size: 20px;
color: var(--secondary-text);
margin-bottom: 40px;
}
.primary-btn {
padding: 12px 32px;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
transition: all 0.2s ease;
font-weight: 500;
background: var(--text-color);
color: var(--background-color);
border: none;
}
.research-card {
background-color: #fff;
padding: 2rem;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
flex-basis: 400px; /* Prevents stretching */
min-width: 300px; /* Ensures responsiveness */
text-align: left;
}
/* Gradient effect similar to the hero */
.research-gradient {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -30%);
width: 800px;
height: 800px;
background: radial-gradient(circle at center,
rgba(0, 255, 255, 0.15) 0%,
rgba(255, 0, 255, 0.15) 25%,
rgba(255, 255, 0, 0.15) 50%,
rgba(0, 0, 0, 0) 70%
);
pointer-events: none;
z-index: 1;
}
/* Mobile responsiveness */
@media (max-width: 768px) {
.research-content {
flex-direction: column;
align-items: center;
text-align: center;
}
.research h2 {
font-size: 48px; /* Further reduce for mobile */
}
.research-card {
max-width: 90%;
}
}
/* Footer styles */
.footer {
border-top: 1px solid var(--border-color);
padding: 80px 20px 40px;
}
.footer-content {
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 40px;
}
.footer-section h4 {
margin-bottom: 20px;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--secondary-text);
}
.footer-section a {
display: block;
color: var(--text-color);
text-decoration: none;
margin-bottom: 12px;
font-size: 14px;
transition: color 0.2s ease;
}
.footer-section a:hover {
color: var(--secondary-text);
}
.footer-bottom {
max-width: 1200px;
margin: 60px auto 0;
padding-top: 20px;
border-top: 1px solid var(--border-color);
text-align: center;
font-size: 14px;
color: var(--secondary-text);
}
/* Mobile styles */
@media (max-width: 768px) {
.hero h1 {
font-size: 48px;
}
.features-grid,
.deploy-content {
grid-template-columns: 1fr;
}
.hero-gradient {
width: 100%;
height: 100%;
}
}
/* Chat styles */
.chat-container {
max-width: 1000px;
margin: 80px auto;
height: calc(100vh - 160px);
display: flex;
flex-direction: column;
background: var(--background-color);
border: 1px solid var(--border-color);
border-radius: 8px;
}
.chat-messages {
flex: 1;
overflow-y: auto;
padding: 20px;
}
.message {
margin-bottom: 20px;
display: flex;
align-items: flex-start;
}
.message.user {
justify-content: flex-end;
}
.message-content {
max-width: 80%;
padding: 12px 16px;
border-radius: 8px;
line-height: 1.5;
}
.message.assistant .message-content {
background: var(--hover-color);
color: var(--text-color);
}
.message.user .message-content {
background: var(--accent-color);
color: var(--background-color);
}
.chat-input-container {
padding: 20px;
border-top: 1px solid var(--border-color);
display: flex;
gap: 10px;
}
.chat-input {
flex: 1;
padding: 12px;
border: 1px solid var(--border-color);
border-radius: 6px;
background: var(--background-color);
color: var(--text-color);
}
.chat-submit {
padding: 12px 24px;
background: var(--accent-color);
color: var(--background-color);
border: none;
border-radius: 6px;
cursor: pointer;
}
/* Articles styles */
.articles-container {
max-width: 1200px;
margin: 80px auto;
padding: 0 20px;
}
.articles-container h1 {
font-size: 48px;
margin-bottom: 40px;
text-align: center;
}
.articles-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 30px;
padding: 20px 0;
}
.article-card {
background: rgba(255, 255, 255, 0.02);
border: 1px solid var(--border-color);
border-radius: 12px;
padding: 24px;
transition: all 0.3s ease;
}
.article-card:hover {
transform: translateY(-5px);
background: rgba(255, 255, 255, 0.05);
}
.article-category {
display: inline-block;
padding: 4px 12px;
background: var(--hover-color);
border-radius: 20px;
font-size: 12px;
margin-bottom: 16px;
}
.article-card h2 {
font-size: 24px;
margin-bottom: 12px;
}
.article-card p {
color: var(--secondary-text);
margin-bottom: 20px;
}
.article-btn {
background: transparent;
color: var(--text-color);
border: 1px solid var(--border-color);
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s ease;
}
.article-btn:hover {
background: var(--hover-color);
}
---
File: /frontend/src/App.jsx
---
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import './App.css';
import Navbar from './components/Navbar';
import Hero from './components/Hero';
import Products from './components/Products';
import Research from './components/Research';
import Footer from './components/Footer';
import ChatUploadPage from './components/ChatUploadPage';
function HomePage() {
return (
<>
<Hero />
<Products />
<Research />
</>
);
}
function App() {
return (
<Router>
<div className="app">
<Navbar />
<main>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/chat" element={<ChatUploadPage />} />
</Routes>
</main>
<Footer />
</div>
</Router>
);
}
export default App;
---
File: /frontend/src/index.css
---
/* Reset default styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
---
File: /frontend/src/main.jsx
---
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx'
import './index.css'
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
)
---
File: /frontend/eslint.config.js
---
import js from '@eslint/js'
import globals from 'globals'
import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
export default [
{ ignores: ['dist'] },
{
files: ['**/*.{js,jsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
settings: { react: { version: '18.3' } },
plugins: {
react,
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...js.configs.recommended.rules,
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
...reactHooks.configs.recommended.rules,
'react/jsx-no-target-blank': 'off',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
]
---
File: /frontend/index.html
---
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
---
File: /frontend/vite.config.js
---
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
})