feat: added animations and navbar goodies #1
5 changed files with 195 additions and 67 deletions
18
src/App.jsx
18
src/App.jsx
|
@ -1,18 +1,23 @@
|
||||||
// src/App.jsx
|
// src/App.jsx
|
||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
|
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
|
||||||
|
|
||||||
import Header from './components/Header';
|
import Header from './components/Header';
|
||||||
import Footer from './components/Footer';
|
import Footer from './components/Footer';
|
||||||
import Home from './components/Home';
|
import Home from './components/Home';
|
||||||
import About from './components/About';
|
import About from './components/About';
|
||||||
import Roadmap from './components/Roadmap';
|
import Roadmap from './components/Roadmap';
|
||||||
|
|
||||||
const App = () => (
|
const App = () => {
|
||||||
|
const [menuOpen, setMenuOpen] = useState(false);
|
||||||
|
|
||||||
|
const handleMenuToggle = (isOpen) => {
|
||||||
|
setMenuOpen(isOpen);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
<Header />
|
<Header onMenuToggle={handleMenuToggle} />
|
||||||
<main>
|
<main className={`page-content ${menuOpen ? 'dropdown-active' : ''}`}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home />} />
|
<Route path="/" element={<Home />} />
|
||||||
<Route path="/about" element={<About />} />
|
<Route path="/about" element={<About />} />
|
||||||
|
@ -22,5 +27,6 @@ const App = () => (
|
||||||
<Footer />
|
<Footer />
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default App;
|
export default App;
|
|
@ -22,3 +22,29 @@
|
||||||
transform: scaleX(1);
|
transform: scaleX(1);
|
||||||
transform-origin: bottom left;
|
transform-origin: bottom left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Header.css */
|
||||||
|
@keyframes dropdown {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-dropdown {
|
||||||
|
animation: dropdown 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content {
|
||||||
|
transition: margin-top 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content.dropdown-active {
|
||||||
|
margin-top: 150px;
|
||||||
|
/* Adjust based on the height of the dropdown menu */
|
||||||
|
}
|
|
@ -1,17 +1,41 @@
|
||||||
|
import { useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import './Header.css'; // Import the custom CSS file
|
import './Header.css'; // Import the custom CSS file
|
||||||
|
|
||||||
const Header = () => (
|
const Header = ({ onMenuToggle }) => {
|
||||||
<header className="bg-gray-900 text-white p-4 flex justify-between items-center">
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
const toggleMenu = () => {
|
||||||
|
setIsOpen(!isOpen);
|
||||||
|
onMenuToggle(!isOpen);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<header className="bg-gray-900 text-white p-4 flex justify-between items-center relative">
|
||||||
<div className="text-2xl font-bold">
|
<div className="text-2xl font-bold">
|
||||||
<Link to="/" className="relative">DoTechBro.org</Link>
|
<Link to="/" className="relative">DoTechBro.org</Link>
|
||||||
</div>
|
</div>
|
||||||
<nav className="space-x-4">
|
<div className="md:hidden">
|
||||||
<Link to="/" className="relative link-underline">Home</Link>
|
<button onClick={toggleMenu} className="focus:outline-none">
|
||||||
<Link to="/about" className="relative link-underline">About</Link>
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
<Link to="/roadmap" className="relative link-underline">Roadmaps</Link>
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d={isOpen ? "M6 18L18 6M6 6l12 12" : "M4 6h16M4 12h16m-7 6h7"}></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<nav className="hidden md:flex md:space-x-4">
|
||||||
|
<Link to="/" className="link-underline">Home</Link>
|
||||||
|
<Link to="/about" className="link-underline">About</Link>
|
||||||
|
<Link to="/roadmap" className="link-underline">Roadmaps</Link>
|
||||||
</nav>
|
</nav>
|
||||||
|
{isOpen && (
|
||||||
|
<div className="absolute top-full left-0 w-full bg-gray-900 text-white flex flex-col items-center md:hidden animate-dropdown">
|
||||||
|
<Link to="/" className="block py-2 link-underline" onClick={toggleMenu}>Home</Link>
|
||||||
|
<Link to="/about" className="block py-2 link-underline" onClick={toggleMenu}>About</Link>
|
||||||
|
<Link to="/roadmap" className="block py-2 link-underline" onClick={toggleMenu}>Roadmaps</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default Header;
|
export default Header;
|
23
src/components/Home.css
Normal file
23
src/components/Home.css
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/* Home.css */
|
||||||
|
.page-content {
|
||||||
|
transition: margin-top 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content.dropdown-active {
|
||||||
|
margin-top: 150px;
|
||||||
|
/* Adjust based on the height of the dropdown menu */
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-in {
|
||||||
|
animation: fadeIn 1s ease-in-out forwards;
|
||||||
|
}
|
|
@ -1,10 +1,40 @@
|
||||||
import { useState } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import FeaturedRoadmaps from './FeaturedRoadmaps';
|
import FeaturedRoadmaps from './FeaturedRoadmaps';
|
||||||
import MailingListDialog from './MailingListDialog';
|
import MailingListDialog from './MailingListDialog';
|
||||||
import roadmaps from '../roadmaps.json';
|
import roadmaps from '../roadmaps.json';
|
||||||
|
import './Home.css'; // Import the custom CSS file
|
||||||
|
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
const [dialogOpen, setDialogOpen] = useState(false);
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
|
const [menuOpen, setMenuOpen] = useState(false);
|
||||||
|
const sectionsRef = useRef([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
entry.target.classList.add('animate-fade-in');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ threshold: 0.1 }
|
||||||
|
);
|
||||||
|
|
||||||
|
sectionsRef.current.forEach((section) => {
|
||||||
|
if (section) {
|
||||||
|
observer.observe(section);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
sectionsRef.current.forEach((section) => {
|
||||||
|
if (section) {
|
||||||
|
observer.unobserve(section);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleDialogOpen = () => {
|
const handleDialogOpen = () => {
|
||||||
setDialogOpen(true);
|
setDialogOpen(true);
|
||||||
|
@ -14,10 +44,17 @@ const Home = () => {
|
||||||
setDialogOpen(false);
|
setDialogOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleMenuToggle = (isOpen) => {
|
||||||
|
setMenuOpen(isOpen);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div className={`page-content ${menuOpen ? 'dropdown-active' : ''}`}>
|
||||||
<div className="flex flex-col items-center justify-center w-full">
|
<div className="flex flex-col items-center justify-center w-full">
|
||||||
<div className="w-full p-8 flex flex-col md:flex-row items-center justify-center min-h-screen bg-gray-100">
|
<div
|
||||||
|
className="w-full p-8 flex flex-col md:flex-row items-center justify-center min-h-screen bg-gray-100 opacity-0"
|
||||||
|
ref={(el) => (sectionsRef.current[0] = el)}
|
||||||
|
>
|
||||||
<div className="md:w-1/2 flex flex-col items-center text-center">
|
<div className="md:w-1/2 flex flex-col items-center text-center">
|
||||||
<h2 className="text-6xl font-bold leading-tight">
|
<h2 className="text-6xl font-bold leading-tight">
|
||||||
Pivot into <span className="text-green-600">tech.</span>
|
Pivot into <span className="text-green-600">tech.</span>
|
||||||
|
@ -27,7 +64,10 @@ const Home = () => {
|
||||||
<p className="mt-4 text-lg max-w-2xl">
|
<p className="mt-4 text-lg max-w-2xl">
|
||||||
Empowering minorities to overcome barriers and succeed in the tech industry with confidence.
|
Empowering minorities to overcome barriers and succeed in the tech industry with confidence.
|
||||||
</p>
|
</p>
|
||||||
<button onClick={handleDialogOpen} className="mt-8 px-6 py-3 bg-green-600 text-white text-lg font-semibold rounded hover:bg-green-700 transition duration-300">
|
<button
|
||||||
|
className="mt-8 px-6 py-3 bg-green-600 text-white text-lg font-semibold rounded hover:bg-green-700 transition duration-300"
|
||||||
|
onClick={handleDialogOpen}
|
||||||
|
>
|
||||||
Start Today
|
Start Today
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -36,29 +76,38 @@ const Home = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full bg-gray-900 text-white py-16">
|
<div
|
||||||
|
className="w-full bg-gray-900 text-white py-16 opacity-0"
|
||||||
|
ref={(el) => (sectionsRef.current[1] = el)}
|
||||||
|
>
|
||||||
<FeaturedRoadmaps roadmaps={roadmaps} />
|
<FeaturedRoadmaps roadmaps={roadmaps} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full p-8 bg-white text-center my-16">
|
<div
|
||||||
|
className="w-full p-8 bg-white text-center my-16 opacity-0"
|
||||||
|
ref={(el) => (sectionsRef.current[2] = el)}
|
||||||
|
>
|
||||||
<h2 className="text-4xl font-bold mb-8">Testimonials</h2>
|
<h2 className="text-4xl font-bold mb-8">Testimonials</h2>
|
||||||
<p className="text-lg">Coming soon...</p>
|
<p className="text-lg">Coming soon...</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full p-8 bg-gray-900 text-white text-center">
|
<div
|
||||||
|
className="w-full p-8 bg-gray-900 text-white text-center opacity-0"
|
||||||
|
ref={(el) => (sectionsRef.current[3] = el)}
|
||||||
|
>
|
||||||
<h2 className="text-4xl font-bold mb-8">Join Our Community</h2>
|
<h2 className="text-4xl font-bold mb-8">Join Our Community</h2>
|
||||||
<p className="text-lg max-w-2xl mx-auto">
|
<p className="text-lg max-w-2xl mx-auto">
|
||||||
Connect with like-minded individuals, share your journey, and get support from our community.
|
Connect with like-minded individuals, share your journey, and get support from our community.
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button className="mt-8 px-6 py-3 bg-green-600 text-white text-lg font-semibold rounded hover:bg-green-700 transition duration-300">
|
||||||
onClick={handleDialogOpen}
|
|
||||||
className="mt-8 px-6 py-3 bg-green-600 text-white text-lg font-semibold rounded hover:bg-green-700 transition duration-300">
|
|
||||||
Join Now
|
Join Now
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MailingListDialog open={dialogOpen} onClose={handleDialogClose} />
|
<MailingListDialog open={dialogOpen} onClose={handleDialogClose} />
|
||||||
</div>
|
</div>
|
||||||
)
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Home;
|
export default Home;
|
Loading…
Reference in a new issue