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
10 changes: 9 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<title>DevilQuant</title>
<title>DevilQuant | Quantitative Finance at ASU</title>
<meta name="description" content="DevilQuant is the first quantitative finance club at Arizona State University. Students build real projects, compete, network, and work with industry professionals." />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="DevilQuant" />
<meta property="og:title" content="DevilQuant | Quantitative Finance at ASU" />
<meta property="og:description" content="The first quantitative finance club at Arizona State University. Build real projects, compete, and connect with industry professionals." />
<meta property="og:url" content="https://devilquant.com/" />
<meta property="og:image" content="https://devilquant.com/DQ.png" />
<meta name="twitter:card" content="summary" />
</head>
<body>
<div id="root"></div>
Expand Down
1 change: 0 additions & 1 deletion public/vite.svg

This file was deleted.

7 changes: 4 additions & 3 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react';
import { HashRouter as Router, Routes, Route, useLocation } from 'react-router-dom';
import { HashRouter as Router, Routes, Route } from 'react-router-dom';
import Navbar from './components/Navbar';
import Footer from './components/Footer';
import ScrollToTop from './components/ScrollToTop';
import Home from './pages/Home';
import About from './pages/About';
import Discord from './pages/redirects/Discord';
import SunDevilCentral from './pages/redirects/SunDevilCentral';
import LinkedIn from './pages/redirects/LinkedIn';
import Resources from './pages/Resources';
import Projects from './pages/Projects';
import NotFound from './pages/NotFound';

function AppContent() {
return (
Expand All @@ -23,15 +25,14 @@ function AppContent() {
<Route path="/discord" element={<Discord />} />
<Route path="/sundevilcentral" element={<SunDevilCentral />} />
<Route path="/linkedin" element={<LinkedIn />} />
<Route path="*" element={<NotFound />} />
</Routes>
</div>
<Footer />
</div>
);
}

import ScrollToTop from './components/ScrollToTop';

function App() {
return (
<Router>
Expand Down
Binary file removed src/assets/DQ.png
Binary file not shown.
Binary file modified src/assets/Headshots/Bhavana.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/Headshots/alex_pfp.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed src/assets/Headshots/alex_pfp.png
Binary file not shown.
Binary file removed src/assets/Headshots/bradley.jpeg
Binary file not shown.
Binary file added src/assets/Headshots/cedric.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed src/assets/Headshots/cedric.png
Binary file not shown.
Binary file removed src/assets/Headshots/jayden.jpeg
Binary file not shown.
Binary file added src/assets/Headshots/jayden.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed src/assets/background_video.mp4
Binary file not shown.
Binary file removed src/assets/old_background_video.mp4
Binary file not shown.
Binary file added src/assets/projects/data-lake.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/projects/odds-aggregator.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/projects/sentiment-scraper.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion src/assets/react.svg

This file was deleted.

25 changes: 3 additions & 22 deletions src/components/Hero.jsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,10 @@
import React from 'react';
import { Link } from 'react-router-dom';
import videoBg from '../assets/background_video.mp4';
import { DISCORD_URL } from '../data/links';

const Hero = () => {
return (
<div className="relative min-h-screen flex items-center justify-center overflow-hidden">
{/* Video Background */}
<div className="absolute inset-0 w-full h-full overflow-hidden">
<video
autoPlay
loop
muted
playsInline
className="w-full h-full object-cover"
>
<source
src={videoBg}
type="video/mp4"
/>
Your browser does not support the video tag.
</video>
{/* Dark Overlay */}
<div className="absolute inset-0 bg-black/70 backdrop-blur-[2px]"></div>
</div>

<div className="relative min-h-screen flex items-center justify-center overflow-hidden bg-black">
<div className="relative z-10 max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center pt-20">
<h1 className="text-4xl tracking-tight font-bold text-white sm:text-5xl md:text-6xl lg:text-7xl">
Devil<span className="text-neutral-400">Quant</span>
Expand All @@ -35,7 +16,7 @@ const Hero = () => {
<div className="mt-10 max-w-sm mx-auto sm:max-w-none sm:flex sm:justify-center gap-4">
<div>
<a
href="https://discord.com/invite/WJbhDmumXp"
href={DISCORD_URL}
target="_blank"
rel="noopener noreferrer"
className="w-full flex items-center justify-center px-8 py-3 text-base font-medium text-black bg-white hover:bg-neutral-200 md:py-4 md:text-lg transition-colors duration-200"
Expand Down
2 changes: 1 addition & 1 deletion src/components/LeaderCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react';
const LeaderCard = ({ name, role, bio, image, socialLinks }) => {
return (
<div className="bg-neutral-900 overflow-hidden border border-neutral-800 transition-all hover:border-neutral-600">
<div className="aspect-w-1 aspect-h-1 w-full bg-neutral-800 relative">
<div className="w-full bg-neutral-800 relative">
{image ? (
<img src={image} alt={name} className="w-full h-64 object-cover" />
) : (
Expand Down
41 changes: 8 additions & 33 deletions src/components/Navbar.jsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,23 @@
import React, { useEffect, useState } from 'react';
import React, { useState } from 'react';
import { Link, useLocation, useNavigate } from 'react-router-dom';

const Navbar = () => {
const location = useLocation();
const navigate = useNavigate();
const [scrolled, setScrolled] = useState(false);
const [isOpen, setIsOpen] = useState(false);
// The mobile menu is open only for the location it was opened on,
// so any navigation closes it.
const [openedAt, setOpenedAt] = useState(null);
const isOpen = openedAt === location.key;
const setIsOpen = (open) => setOpenedAt(open ? location.key : null);

// Navigate to a page and then scroll to a section by ID
// The target page scrolls to `scrollTo` once it has rendered.
const navigateToSection = (path, sectionId) => {
if (location.pathname === path) {
// Already on the page, just scroll
const el = document.getElementById(sectionId);
if (el) el.scrollIntoView({ behavior: 'smooth' });
} else {
navigate(path);
// Wait for the page to render, then scroll
setTimeout(() => {
const el = document.getElementById(sectionId);
if (el) el.scrollIntoView({ behavior: 'smooth' });
}, 100);
}
navigate(path, { state: { scrollTo: sectionId } });
};

// Check if we are on the home page
const isHome = location.pathname === '/';

useEffect(() => {
const handleScroll = () => {
const isScrolled = window.scrollY > 20;
if (isScrolled !== scrolled) {
setScrolled(isScrolled);
}
};

window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [scrolled]);

// Close mobile menu when location changes
useEffect(() => {
setIsOpen(false);
}, [location]);

// navbar background logic:
// - If Home page: ALWAYS transparent, no border
// - If NOT home page: dark background
Expand Down
8 changes: 6 additions & 2 deletions src/components/magicui/dot-pattern.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"use client"

import React, { useEffect, useId, useMemo, useRef, useState } from "react"
import React, { memo, useEffect, useId, useMemo, useRef, useState } from "react"
import { cn } from "../../lib/utils"

export function DotPattern({
function DotPatternBase({
width = 16,
height = 16,
x = 0,
Expand Down Expand Up @@ -101,3 +101,7 @@ export function DotPattern({
</svg>
)
}

// Memoized: the pattern can be ~1,000 animated nodes, so skip re-rendering it when
// the parent page re-renders with the same props (navigation state, year select).
export const DotPattern = memo(DotPatternBase)
7 changes: 5 additions & 2 deletions src/components/magicui/icon-cloud.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useEffect, useRef, useCallback } from "react";
import { memo, useEffect, useRef, useCallback } from "react";

function easeOutCubic(t) {
return 1 - Math.pow(1 - t, 3);
}

export function IconCloud({ images }) {
function IconCloudBase({ images }) {
const canvasRef = useRef(null);
const animationFrameRef = useRef(0);
const rotationRef = useRef({ x: 0, y: 0 });
Expand Down Expand Up @@ -270,3 +270,6 @@ export function IconCloud({ images }) {
/>
);
}

// Memoized: re-rendering restarts no work, so skip it when `images` is unchanged.
export const IconCloud = memo(IconCloudBase);
47 changes: 0 additions & 47 deletions src/components/magicui/interactive-grid-pattern.jsx

This file was deleted.

23 changes: 15 additions & 8 deletions src/components/magicui/pulse-grid.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import React, { useMemo } from 'react';

// Deterministic pseudo-random number in [0, 1) for a given seed. Rendering
// must be pure, so the pattern is fixed rather than using Math.random().
const random = (seed) => {
const x = Math.sin(seed * 12.9898) * 43758.5453;
return x - Math.floor(x);
};

export function PulseGrid({
spacing = 80,
baseOpacity = 0.08,
Expand All @@ -11,15 +18,15 @@ export function PulseGrid({
const hCount = Math.ceil(2000 / spacing);
const vCount = Math.ceil(2000 / spacing);

const makeLine = () => ({
delay: Math.random() * 6,
duration: 3 + Math.random() * 3, // 3-6s per cycle
willPulse: Math.random() < pulseChance,
const makeLine = (seed) => ({
delay: random(seed) * 6,
duration: 3 + random(seed + 0.1) * 3, // 3-6s per cycle
willPulse: random(seed + 0.2) < pulseChance,
});

return {
horizontal: Array.from({ length: hCount }, makeLine),
vertical: Array.from({ length: vCount }, makeLine),
horizontal: Array.from({ length: hCount }, (_, i) => makeLine(i + 1)),
vertical: Array.from({ length: vCount }, (_, i) => makeLine(i + 1001)),
};
}, [spacing, pulseChance]);

Expand All @@ -46,7 +53,7 @@ export function PulseGrid({
y2={i * spacing}
stroke="white"
strokeWidth="0.5"
opacity={line.willPulse ? baseOpacity : baseOpacity}
opacity={baseOpacity}
style={
line.willPulse
? {
Expand All @@ -65,7 +72,7 @@ export function PulseGrid({
y2="100%"
stroke="white"
strokeWidth="0.5"
opacity={line.willPulse ? baseOpacity : baseOpacity}
opacity={baseOpacity}
style={
line.willPulse
? {
Expand Down
4 changes: 3 additions & 1 deletion src/data/guides/general/landing-a-quant-internship.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { DISCORD_URL } from "../../links.js";

const guide = {
slug: "landing-a-quant-internship",
title: "Landing a Quant Internship",
Expand Down Expand Up @@ -207,7 +209,7 @@ const guide = {
<ul>
<li><strong>Simplify GitHub List:</strong> The definitive list for internships. Check the <a href="https://github.com/SimplifyJobs/Summer2026-Internships" target="_blank" rel="noopener noreferrer">Simplify GitHub</a> repository constantly.</li>
<li><strong>LinkedIn Jobs:</strong> Setup alerts on <a href="https://www.linkedin.com/jobs/" target="_blank" rel="noopener noreferrer">LinkedIn</a> for specific quant firm names.</li>
<li><strong>DevilQuant Discord Server:</strong> Our community actively tracks applications! Join the <a href="https://discord.com/invite/WJbhDmumXp" target="_blank" rel="noopener noreferrer">DevilQuant Discord</a> and once you become a member, you can go to the <code>#job-openings</code> channel to get live updates directly from the Simplify jobs list.</li>
<li><strong>DevilQuant Discord Server:</strong> Our community actively tracks applications! Join the <a href="${DISCORD_URL}" target="_blank" rel="noopener noreferrer">DevilQuant Discord</a> and once you become a member, you can go to the <code>#job-openings</code> channel to get live updates directly from the Simplify jobs list.</li>
</ul>
`,
}
Expand Down
10 changes: 6 additions & 4 deletions src/data/guides/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// A hidden guide has both its import and its list entry commented out.
// Uncomment both to show it again.
import gettingStartedWithQuant from './general/getting-started-with-quant.js';
import landingAnInternship from './general/landing-an-internship.js';
// import landingAnInternship from './general/landing-an-internship.js';
import landingAQuantInternship from './general/landing-a-quant-internship.js';

import pythonStockFetcher from './projects/python-stock-fetcher.js';
import smaTradingBot from './projects/sma-trading-bot.js';
import portfolioTracker from './projects/portfolio-tracker.js';
// import pythonStockFetcher from './projects/python-stock-fetcher.js';
// import smaTradingBot from './projects/sma-trading-bot.js';
// import portfolioTracker from './projects/portfolio-tracker.js';
import gettingStartedWithProjects from './projects/getting-started-with-projects.js';
import monteCarloSimulator from './projects/monte-carlo-simulator.js';
import portfolioOptimizer from './projects/portfolio-optimizer.js';
Expand Down
Loading