Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"react-dom": "^19.2.7",
"react-error-boundary": "^5.0.0",
"react-router-dom": "^7.18.1",
"three": "^0.185.1",
"zustand": "^5.0.6"
},
"devDependencies": {
Expand All @@ -38,6 +39,7 @@
"@types/node": "^24.13.2",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@types/three": "^0.185.1",
"@vitejs/plugin-react": "^6.0.3",
"jsdom": "^26.1.0",
"oxlint": "^1.71.0",
Expand Down
163 changes: 101 additions & 62 deletions src/features/globe/GlobeView.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useRef } from 'react';
import { useGlobe } from './useGlobe';
import { NATIONS } from './nations.constants';

Check warning on line 3 in src/features/globe/GlobeView.tsx

View workflow job for this annotation

GitHub Actions / Type-check · Lint · Format · Test · Build

eslint(no-unused-vars)

Identifier 'NATIONS' is imported but never used.

Check warning on line 3 in src/features/globe/GlobeView.tsx

View workflow job for this annotation

GitHub Actions / Type-check · Lint · Format · Test · Build

eslint(no-unused-vars)

Identifier 'NATIONS' is imported but never used.
import '@/styles/components/overlay.css';
import '@/styles/components/country-list.css';

Expand All @@ -16,74 +16,113 @@
*/
export const GlobeView: React.FC<GlobeViewProps> = ({ onEnterApp }) => {
const containerRef = useRef<HTMLDivElement | null>(null);
const { activeCountry, flyTo, resumeRotation } = useGlobe(containerRef);
useGlobe(containerRef);

return (
<div
style={{
position: 'relative',
width: '100vw',
height: '100vh',
overflow: 'hidden',
backgroundColor: '#000',
}}
aria-label="Interactive 3D Globe showing live national stock market overlays"
>
{/* ── UI Overlay ───────────────────────────────────────────────── */}
<div
id="ui-overlay"
className="home-overlay"
role="complementary"
aria-label="Market controls"
>
<h1 className="home-overlay-title">National Stock Indices</h1>
<p className="home-overlay-status">Live WebGL Market Volatility Overlay</p>

{/* Country legend — now uses <button> for keyboard accessibility */}
<nav className="country-list" aria-label="Country market selector">
{NATIONS.map((nation) => (
<button
key={nation.name}
type="button"
className={`country-item ${activeCountry === nation.name ? 'active' : ''}`}
onClick={() => flyTo(nation.name, nation.lat, nation.lng)}
aria-pressed={activeCountry === nation.name}
aria-label={`Focus globe on ${nation.name}`}
>
<div className="country-info">
<span className="country-flag" aria-hidden="true">
{nation.flag}
</span>
<span>{nation.name}</span>
</div>
<div
className="country-indicator"
style={{ color: nation.color, backgroundColor: nation.color }}
aria-hidden="true"
/>
</button>
))}
</nav>
<div className="landing-page">
{/* ── Fixed Overlays (Visible across scrolling) ────────────────── */}
<div className="shooting-star-container">
{/* White Comets */}
<div className="shooting-star comet-1"></div>
<div className="shooting-star comet-2"></div>
<div className="shooting-star comet-3"></div>
<div className="shooting-star comet-4"></div>
<div className="shooting-star comet-5"></div>

{/* Violet Comets */}
<div className="shooting-star violet-comet comet-violet-1"></div>
<div className="shooting-star violet-comet comet-violet-2"></div>
<div className="shooting-star violet-comet comet-violet-3"></div>
</div>

{activeCountry && (
<button type="button" className="resume-rotate-btn" onClick={resumeRotation}>
↺ Resume Rotation
</button>
)}
<div className="twinkling-stars">
{/* Normal stars */}
<div className="star star-1"></div>
<div className="star star-2"></div>
<div className="star star-3"></div>
<div className="star star-4"></div>
<div className="star star-5"></div>
<div className="star star-6"></div>
<div className="star star-7"></div>
<div className="star star-8"></div>
<div className="star star-9"></div>
<div className="star star-10"></div>

{/* Big stars */}
<div className="big-star big-star-1"></div>
<div className="big-star big-star-2"></div>
<div className="big-star big-star-3"></div>
<div className="big-star big-star-4"></div>
<div className="big-star big-star-5"></div>
<div className="big-star big-star-6"></div>

<button type="button" className="terminal-enter-btn" onClick={onEnterApp}>
Access Terminal
</button>
{/* Mega stars */}
<div className="mega-star mega-star-1"></div>
<div className="mega-star mega-star-2"></div>
<div className="mega-star mega-star-3"></div>
</div>

{/* ── Globe Canvas ─────────────────────────────────────────────── */}
<div
ref={containerRef}
style={{ width: '100%', height: '100%' }}
id="globeViz"
role="img"
aria-label="3D globe visualization — rotate with mouse, scroll to pan"
/>
{/* ── Section 1: Hero (100vh) ──────────────────────────────────── */}
<section className="hero-section">
{/* Navbar */}
<header className="globe-navbar">
<div className="nav-brand">
<span className="logo-icon">x</span>
<span className="brand-text">Discipline Co-pilot</span>
</div>

<div className="nav-search">
<span className="search-icon">🔍</span>
<input type="text" placeholder="Search (Ctrl+K)" />
</div>
Comment on lines +74 to +77

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Search input lacks an accessible name.

The placeholder is not a substitute for a label; screen-reader users get no name for this field. Add an aria-label (or associated <label>).

♿ Proposed fix
-            <input type="text" placeholder="Search (Ctrl+K)" />
+            <input type="text" placeholder="Search (Ctrl+K)" aria-label="Search" />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="nav-search">
<span className="search-icon">🔍</span>
<input type="text" placeholder="Search (Ctrl+K)" />
</div>
<div className="nav-search">
<span className="search-icon">🔍</span>
<input type="text" placeholder="Search (Ctrl+K)" aria-label="Search" />
</div>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/globe/GlobeView.tsx` around lines 74 - 77, Add an accessible
name to the search input in the GlobeView component by adding a descriptive
aria-label or associating it with a visible label; retain the existing
placeholder as optional guidance.


<nav className="nav-links">
<a href="#" className="active">Products</a>
<a href="#">Community</a>
<a href="#">Markets</a>
<a href="#">Brokers</a>
<a href="#">More</a>
</nav>

<div className="nav-profile">
<button className="nav-login-btn" onClick={onEnterApp}>Log in</button>
</div>
</header>

{/* Hero Content */}
<div className="globe-hero">
<h1>Look First Then Leap</h1>

<div className="billing-toggle">
<label className="radio-label">
<input type="radio" name="billing" />
<span className="radio-custom"></span>
Monthly
</label>
<label className="radio-label">
<input type="radio" name="billing" defaultChecked />
<span className="radio-custom"></span>
Annually
</label>
<span className="discount-badge">Save up to 17% 🤑</span>
</div>
</div>
</section>

{/* ── Section 2: Globe (100vh) ─────────────────────────────────── */}
<section className="globe-section">
<div className="globe-glow"></div>

<div className="globe-wrapper">
<div
ref={containerRef}
style={{ width: '100%', height: '100%' }}
id="globeViz"
role="img"
aria-label="3D globe visualization"
/>
</div>
</section>
</div>
);
};
Loading
Loading