Merge pull request 'feat: added animations and navbar goodies' (#1) from feat-mobile-menu into main
All checks were successful
Build and Deploy Docker Image / build (push) Successful in 39s

Reviewed-on: #1
This commit is contained in:
Mike 2024-10-22 07:42:24 -04:00
commit 258d1e77c4
5 changed files with 195 additions and 67 deletions

View file

@ -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 />} />
@ -21,6 +26,7 @@ const App = () => (
</main> </main>
<Footer /> <Footer />
</Router> </Router>
); );
};
export default App; export default App;

View file

@ -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 */
}

View file

@ -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
View 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;
}

View file

@ -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;