Compare commits

..

3 commits

Author SHA1 Message Date
64d33253cc test login
Some checks failed
Build and Deploy Docker Image / build (push) Failing after 22s
2024-10-22 20:53:10 -04:00
2b2679b363
testing
Some checks failed
Build and Deploy Docker Image / build (push) Failing after 21s
2024-10-22 20:46:47 -04:00
d364b3c3ad
testing
Some checks failed
Build and Deploy Docker Image / build (push) Failing after 15s
2024-10-22 20:43:26 -04:00
23 changed files with 347 additions and 1725 deletions

View file

@ -0,0 +1,45 @@
name: Build and Deploy Docker Image
on:
push:
branches:
- ci-build
jobs:
build:
runs-on: docker
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Log in to Red Hat Registry
uses: https://github.com/redhat-actions/podman-login@v1
with:
password: ${{ secrets.PASSWORD }}
username: ${{ secrets.USERNAME }}
registry: git.thecodedom.com
- name: Buildah Action
uses: https://github.com/redhat-actions/buildah-build@v2
with:
image: my-new-image
tags: test
containerfiles: |
./Dockerfile
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
#
# - name: Log in to Gitea Container Registry
# uses: docker/login-action@v3
# with:
#
# - name: Build and push Docker image
# uses: docker/build-push-action@v6
# with:
# context: .
# push: true
# tags: git.thecodedom.com/dotechbro/dotechbro-website:latest

View file

@ -1,26 +0,0 @@
# Development Guide
## Commands
- **Start dev server**: `npm run dev`
- **Build for production**: `npm run build`
- **Lint code**: `npm run lint`
- **Preview production build**: `npm run preview`
## Code Style Guidelines
- **React Components**: Use functional components with hooks
- **Imports**: Group imports by: React/libraries, components, styles/assets
- **Formatting**: Use 2-space indentation, semicolons, single quotes
- **Naming**:
- Components: PascalCase (e.g., `Header.jsx`)
- Functions/variables: camelCase
- Files: Component files use .jsx extension
- **CSS**: Use Tailwind utility classes with component-specific CSS when needed
- **Error Handling**: Use try/catch blocks and provide user-friendly error messages
- **Props**: Use destructuring for component props
- **State Management**: Use React hooks (useState, useEffect) for component state
## Tech Stack
- React 18 w/ functional components
- React Router for navigation
- Tailwind CSS for styling
- Vite for build tool

View file

@ -22,10 +22,6 @@ FROM nginx:alpine
# Copy the built application from the previous stage
COPY --from=build /app/dist /usr/share/nginx/html
COPY dotechbro_nginx.conf /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/nginx.conf
# Expose port 80
EXPOSE 80

View file

@ -1,9 +0,0 @@
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
}

View file

@ -14,10 +14,5 @@
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
<script
defer
src="https://unami.smigz.com/script.js"
data-website-id="e07c8f76-9786-4201-a47a-482fd9d485a9"
></script>
</body>
</html>

View file

@ -1,52 +0,0 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" - "$http_cf_connecting_ip"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
server_tokens off;
#gzip on;
# CloudFlare Ips
real_ip_header CF-Connecting-IP;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
include /etc/nginx/conf.d/*.conf;
}

View file

@ -4,10 +4,8 @@ import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Header from './components/Header';
import Footer from './components/Footer';
import Home from './components/Home';
import NotFound from './components/NotFound';
import About from './components/About';
import Roadmap from './components/Roadmap';
import RoadmapDetail from './components/RoadmapDetail'; // Import the RoadmapDetail component
const App = () => {
const [menuOpen, setMenuOpen] = useState(false);
@ -23,10 +21,7 @@ const App = () => {
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/roadmap" element={<Roadmap />}>
<Route path=":id" element={<RoadmapDetail />} />
</Route>
<Route path="*" element={<NotFound />} />
<Route path="/roadmap" element={<Roadmap />} />
</Routes>
</main>
<Footer />

1
src/assets/react.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

After

Width:  |  Height:  |  Size: 4 KiB

View file

@ -1,39 +0,0 @@
const challenges = [
{
title: 'Lack of Representation',
content: 'The tech industry often lacks visible role models from similar backgrounds, which can deter individuals from pursuing careers in this field.',
solution: 'Mentorship Programs: Seek out mentorship opportunities with experienced professionals who understand your journey and can offer guidance, support, and valuable networking connections.',
},
{
title: 'Implicit Bias and Discrimination',
content: 'Unconscious biases and systemic discrimination can create barriers to entry and advancement for minorities in tech.',
solution: 'Empower Yourself: Develop strategies to counteract bias, such as documenting your achievements and seeking inclusive workplaces that prioritize diversity.',
},
{
title: 'Limited Access to Education and Resources',
content: 'Many underserved communities lack adequate exposure to technology and programming education, which can limit opportunities for entry into the tech field.',
solution: 'Educational Initiatives: Take advantage of free or affordable coding bootcamps, online courses, and community workshops that focus on tech skills.',
},
{
title: 'Financial Barriers',
content: 'The high costs of education, certification programs, and living expenses can pose significant challenges.',
solution: 'Scholarship and Grant Research: Look for scholarships and grants specifically aimed at minorities in tech. Building a strong portfolio can also demonstrate your skills to potential employers, making you a more competitive candidate.',
},
{
title: 'Impostor Syndrome',
content: 'Many individuals feel inadequate or fear being exposed as a fraud, which can hinder confidence and career advancement.',
solution: 'Build Confidence: Share your experiences with peers or mentors, and focus on celebrating your achievements, no matter how small. Joining support groups can also be beneficial.',
},
{
title: 'Networking Challenges',
content: 'Establishing connections within the tech community can feel daunting, especially for newcomers. However, strong professional relationships are essential for mentorship and job opportunities.',
solution: 'Engage in Networking Events: Actively participate in tech meetups, industry conferences, and hackathons. These events are excellent for learning and for building connections with others who share your passion.',
},
{
title: 'Work-Life Balance',
content: 'Balancing the demands of a tech career with personal and family responsibilities can be challenging, impacting overall well-being.',
solution: 'Prioritize Self-Care: Establish routines that include time for rest and personal interests. Engaging in hobbies, exercise, and family time can enhance your mental health and productivity in your tech career.',
},
];
export default challenges;

View file

@ -1,168 +1,12 @@
import React from 'react';
import { Link } from 'react-router-dom';
const About = () => {
return (
<div className="bg-dark-900 text-white">
{/* Hero Section */}
<section className="py-20 bg-gradient-to-b from-dark-800 to-dark-900">
<div className="container mx-auto px-6">
<div className="text-center max-w-3xl mx-auto">
<h1 className="text-4xl md:text-5xl font-bold mb-6">Our Mission</h1>
<p className="text-xl text-gray-300 leading-relaxed mb-8">
DoTechBro is dedicated to empowering minorities, particularly African Americans, to
successfully transition into the tech industry and thrive in their careers.
</p>
</div>
</div>
</section>
{/* Vision Section */}
<section className="py-16 bg-dark-800">
<div className="container mx-auto px-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-12 items-center">
<div>
<h2 className="text-3xl font-bold mb-6 bg-gradient-to-r from-primary-500 to-secondary-500 bg-clip-text text-transparent">Our Vision</h2>
<p className="text-gray-300 mb-6 leading-relaxed">
We envision a tech industry that reflects the diversity of our society, where
minorities have equal opportunities to innovate, lead, and succeed. Our goal is to
bridge the gap by providing targeted resources, mentorship, and community support.
</p>
<p className="text-gray-300 leading-relaxed">
By creating comprehensive roadmaps, curating high-quality learning materials, and
fostering a supportive community, we aim to give underrepresented individuals the
confidence and skills needed to thrive in technology careers.
</p>
</div>
<div className="bg-dark-700 p-8 rounded-xl shadow-lg">
<h3 className="text-2xl font-bold mb-4">Why We Started</h3>
<p className="text-gray-300 mb-4">
The tech industry has a well-documented diversity problem. Despite making up 13.4% of the
U.S. population, Black Americans represent only about 7% of the computing workforce.
We believe this isn't due to lack of talent or interest, but rather barriers to entry and lack of tailored resources.
</p>
<p className="text-gray-300">
DoTechBro was created to address these challenges head-on by providing clear pathways
into tech that acknowledge and overcome the unique obstacles minorities face.
</p>
</div>
</div>
</div>
</section>
{/* What We Do Section */}
<section className="py-16 bg-gradient-to-b from-dark-900 to-dark-800">
<div className="container mx-auto px-6">
<h2 className="text-3xl font-bold text-center mb-12">What We Do</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<div className="bg-dark-700 rounded-xl p-8 shadow-lg hover:shadow-xl transition-shadow duration-300">
<div className="text-primary-500 text-3xl mb-4">
<svg xmlns="http://www.w3.org/2000/svg" className="h-12 w-12" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
</svg>
</div>
<h3 className="text-xl font-bold mb-3">Career Roadmaps</h3>
<p className="text-gray-300">
We create tailored roadmaps for various tech career paths, breaking down complex journeys into manageable steps with
clear guidance and resources for each stage.
</p>
</div>
<div className="bg-dark-700 rounded-xl p-8 shadow-lg hover:shadow-xl transition-shadow duration-300">
<div className="text-primary-500 text-3xl mb-4">
<svg xmlns="http://www.w3.org/2000/svg" className="h-12 w-12" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
</svg>
</div>
<h3 className="text-xl font-bold mb-3">Resource Curation</h3>
<p className="text-gray-300">
We curate high-quality learning resources, from tutorials to practice projects, saving you time and helping you
focus on what actually works to build your skills.
</p>
</div>
<div className="bg-dark-700 rounded-xl p-8 shadow-lg hover:shadow-xl transition-shadow duration-300">
<div className="text-primary-500 text-3xl mb-4">
<svg xmlns="http://www.w3.org/2000/svg" className="h-12 w-12" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
</div>
<h3 className="text-xl font-bold mb-3">Community Building</h3>
<p className="text-gray-300">
We're building a supportive community where you can connect with others on similar journeys,
share experiences, and get guidance from those who've succeeded.
</p>
</div>
</div>
</div>
</section>
{/* Values */}
<section className="py-16 bg-dark-800">
<div className="container mx-auto px-6">
<h2 className="text-3xl font-bold text-center mb-6">Our Values</h2>
<p className="text-center text-gray-300 max-w-3xl mx-auto mb-12">
These core principles guide everything we do at DoTechBro and shape how we serve our community.
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="bg-dark-700 rounded-lg p-6 border-l-4 border-primary-500">
<h3 className="text-xl font-bold mb-2">Accessibility</h3>
<p className="text-gray-300">
We believe tech education should be accessible to everyone, regardless of background or prior experience.
</p>
</div>
<div className="bg-dark-700 rounded-lg p-6 border-l-4 border-primary-500">
<h3 className="text-xl font-bold mb-2">Authenticity</h3>
<p className="text-gray-300">
We keep it real about the challenges of breaking into tech while providing actionable solutions.
</p>
</div>
<div className="bg-dark-700 rounded-lg p-6 border-l-4 border-primary-500">
<h3 className="text-xl font-bold mb-2">Community</h3>
<p className="text-gray-300">
We believe in the power of community to overcome obstacles and accelerate growth.
</p>
</div>
<div className="bg-dark-700 rounded-lg p-6 border-l-4 border-primary-500">
<h3 className="text-xl font-bold mb-2">Excellence</h3>
<p className="text-gray-300">
We're committed to providing high-quality resources that actually prepare you for success in the industry.
</p>
</div>
</div>
</div>
</section>
{/* Call to Action */}
<section className="py-20 bg-gradient-to-b from-dark-800 to-dark-900">
<div className="container mx-auto px-6 text-center">
<h2 className="text-3xl font-bold mb-6">Ready to Start Your Tech Journey?</h2>
<p className="text-xl text-gray-300 mb-8 max-w-2xl mx-auto">
Join our community today and take the first step toward your career in tech.
</p>
<div className="flex flex-wrap justify-center gap-4">
<Link
to="/roadmap"
className="px-8 py-3 bg-primary-600 hover:bg-primary-700 text-white rounded-lg shadow-lg transition-colors"
>
Explore Roadmaps
</Link>
<Link
to="/"
className="px-8 py-3 border-2 border-primary-500 text-primary-400 hover:bg-primary-500/10 rounded-lg transition-colors"
>
Join Our Community
</Link>
</div>
</div>
</section>
</div>
);
};
const About = () => (
<div className="p-8 flex flex-col items-center justify-center min-h-screen bg-gray-100">
<h2 className="text-4xl font-bold text-center leading-tight">
About Us
</h2>
<p className="mt-2 text-xs text-center text-gray-600">
Do Tech Bro is dedicated to helping minorities, mainly African Americans, pivot into the tech field.
</p>
</div>
);
export default About;

View file

@ -1,75 +0,0 @@
import React, { useState } from 'react';
const Accordion = ({ items }) => {
const [openIndex, setOpenIndex] = useState(0); // Start with first item open
const toggleItem = (index) => {
setOpenIndex(openIndex === index ? null : index);
};
return (
<div className="w-full">
{items.map((item, index) => (
<div
key={index}
className={`mb-4 border border-dark-600 rounded-lg overflow-hidden transition-all duration-300 ${
openIndex === index ? 'shadow-lg' : 'shadow'
}`}
>
<button
onClick={() => toggleItem(index)}
className={`w-full flex items-center justify-between text-left p-5 font-medium transition-colors ${
openIndex === index
? 'bg-dark-700 text-white'
: 'bg-dark-800 text-gray-300 hover:bg-dark-700'
}`}
aria-expanded={openIndex === index}
>
<span className="text-lg">{item.title}</span>
<svg
xmlns="http://www.w3.org/2000/svg"
className={`h-5 w-5 transition-transform duration-300 ${openIndex === index ? 'transform rotate-180' : ''}`}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
<div
className={`overflow-hidden transition-all duration-300 ease-in-out ${
openIndex === index ? 'max-h-96' : 'max-h-0'
}`}
>
<div className="p-5 bg-dark-700 border-t border-dark-600">
<p className="text-gray-300 mb-4">{item.content}</p>
<div className="mt-4 border-l-4 border-primary-500 pl-4">
<p className="text-primary-400 font-semibold mb-2">Our Solution:</p>
<p className="text-gray-300">{item.solution}</p>
</div>
{item.resources && (
<div className="mt-4 pt-4 border-t border-dark-600">
<p className="text-white font-medium mb-2">Helpful Resources:</p>
<ul className="list-disc list-inside text-primary-400 space-y-1">
{item.resources.map((resource, i) => (
<li key={i}>
<a href={resource.url} className="hover:text-primary-300 transition-colors" target="_blank" rel="noopener noreferrer">
{resource.title}
</a>
</li>
))}
</ul>
</div>
)}
</div>
</div>
</div>
))}
</div>
);
};
export default Accordion;

View file

@ -3,75 +3,24 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faServer, faProjectDiagram, faCode } from '@fortawesome/free-solid-svg-icons';
const icons = {
"devops-sre": faServer,
"non-technical-tech": faProjectDiagram,
"development": faCode
"devops-sre": faServer,
"non-technical-tech": faProjectDiagram,
"development": faCode
};
const FeaturedRoadmaps = ({ roadmaps }) => (
<div className="container mx-auto px-6 py-12">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold mb-4">Featured Roadmaps</h2>
<p className="text-lg text-gray-300 max-w-2xl mx-auto">
Choose your tech path and follow our step-by-step guidance to build your career
</p>
<div className="p-8">
<h2 className="text-4xl font-bold text-center mb-8">Featured Roadmaps</h2>
<div className="flex flex-col md:flex-row justify-center items-center space-y-8 md:space-y-0 md:space-x-8">
{roadmaps.map((roadmap, index) => (
<Link key={index} to={`/roadmap/${roadmap.id}`} className="bg-white text-gray-900 p-8 rounded-lg shadow-lg w-full md:w-1/3 text-center transform transition-transform hover:scale-105">
<FontAwesomeIcon icon={icons[roadmap.id]} className="text-green-600 text-4xl mb-4" />
<h3 className="text-2xl font-semibold">{roadmap.title}</h3>
<p className="mt-4">{roadmap.description}</p>
</Link>
))}
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{roadmaps.map((roadmap, index) => (
<Link
key={index}
to={`/roadmap/${roadmap.id}`}
className="feature-card bg-dark-700 rounded-xl shadow-lg overflow-hidden hover:shadow-xl transition-all duration-300"
>
<div className="p-1 bg-gradient-to-r from-primary-500 to-secondary-500">
<div className="bg-dark-700 p-8 rounded-t-xl">
<div className="flex justify-center items-center w-16 h-16 mx-auto mb-6 rounded-full bg-dark-800 text-primary-500">
<FontAwesomeIcon icon={icons[roadmap.id]} className="text-3xl" />
</div>
<h3 className="text-2xl font-bold text-center mb-3">{roadmap.title}</h3>
<p className="text-gray-400 text-center mb-4">{roadmap.description}</p>
<div className="mt-6 flex justify-center">
<span className="inline-flex items-center text-primary-400 font-medium">
Explore roadmap
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 ml-1" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>
</span>
</div>
</div>
</div>
<div className="px-8 py-4 bg-dark-600 text-center">
<div className="flex justify-center space-x-2">
{['Beginner', 'Intermediate', 'Advanced'].map((level, i) => (
<span
key={i}
className={`text-xs px-2 py-1 rounded-full ${
i === 0 ? 'bg-primary-500/20 text-primary-300' :
'bg-dark-500 text-gray-400'
}`}
>
{level}
</span>
))}
</div>
</div>
</Link>
))}
</div>
<div className="mt-12 text-center">
<Link
to="/roadmap"
className="inline-flex items-center px-6 py-3 bg-dark-700 hover:bg-dark-600 text-white font-medium rounded-lg transition-colors duration-300"
>
View All Roadmaps
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 ml-2" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M10.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L12.586 11H5a1 1 0 110-2h7.586l-2.293-2.293a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>
</Link>
</div>
</div>
);
export default FeaturedRoadmaps;

View file

@ -1,95 +1,10 @@
// src/components/Footer.jsx
import React from 'react';
import { Link } from 'react-router-dom';
const Footer = () => {
const currentYear = new Date().getFullYear();
return (
<footer className="bg-dark-900 text-white py-12">
<div className="container mx-auto px-6">
<div className="grid grid-cols-1 md:grid-cols-4 gap-8">
{/* Logo and About */}
<div className="col-span-1 md:col-span-1">
<Link
to="/"
className="text-2xl font-bold bg-gradient-to-r from-primary-500 to-secondary-500 bg-clip-text text-transparent mb-4 block"
>
DoTechBro.org
</Link>
<p className="text-gray-400 mt-4">
Empowering minorities to succeed in tech through community support and targeted resources.
</p>
</div>
{/* Quick Links */}
<div className="col-span-1">
<h3 className="text-lg font-bold mb-4 text-white">Quick Links</h3>
<ul className="space-y-2">
<li>
<Link to="/" className="text-gray-400 hover:text-primary-400 transition-colors">Home</Link>
</li>
<li>
<Link to="/about" className="text-gray-400 hover:text-primary-400 transition-colors">About</Link>
</li>
<li>
<Link to="/roadmap" className="text-gray-400 hover:text-primary-400 transition-colors">Roadmaps</Link>
</li>
</ul>
</div>
{/* Roadmaps */}
<div className="col-span-1">
<h3 className="text-lg font-bold mb-4 text-white">Popular Roadmaps</h3>
<ul className="space-y-2">
<li>
<Link to="/roadmap" className="text-gray-400 hover:text-primary-400 transition-colors">Web Development</Link>
</li>
<li>
<Link to="/roadmap" className="text-gray-400 hover:text-primary-400 transition-colors">Data Science</Link>
</li>
<li>
<Link to="/roadmap" className="text-gray-400 hover:text-primary-400 transition-colors">UI/UX Design</Link>
</li>
</ul>
</div>
{/* Get in Touch */}
<div className="col-span-1">
<h3 className="text-lg font-bold mb-4 text-white">Get in Touch</h3>
<div className="flex space-x-4 mt-4">
<a href="#" className="text-gray-400 hover:text-primary-400 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="currentColor" viewBox="0 0 24 24">
<path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"/>
</svg>
</a>
<a href="#" className="text-gray-400 hover:text-primary-400 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/>
</svg>
</a>
<a href="#" className="text-gray-400 hover:text-primary-400 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="currentColor" viewBox="0 0 24 24">
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/>
</svg>
</a>
<a href="#" className="text-gray-400 hover:text-primary-400 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
</a>
</div>
</div>
</div>
<div className="border-t border-gray-800 mt-8 pt-8 text-center">
<p className="text-gray-400">
&copy; {currentYear} DoTechBro.org. All rights reserved.
</p>
</div>
</div>
</footer>
);
};
const Footer = () => (
<footer className="bg-gray-800 text-white p-4 text-center">
<p>&copy; {new Date().getFullYear()} Do Tech Bro. All rights reserved.</p>
</footer>
);
export default Footer;

View file

@ -1,50 +1,50 @@
/* src/components/Header.css */
.link-underline {
position: relative;
display: inline-block;
font-weight: 500;
padding: 0.25rem 0;
}
.link-underline::after {
content: '';
position: absolute;
width: 100%;
height: 2px;
bottom: 0;
left: 0;
background-color: var(--color-primary);
transform: scaleX(0);
transform-origin: bottom right;
transition: transform 0.3s ease;
}
.link-underline:hover::after {
transform: scaleX(1);
transform-origin: bottom left;
}
/* Animations */
@keyframes dropdown {
from {
opacity: 0;
transform: translateY(-8px);
/* src/components/Header.css */
.link-underline {
position: relative;
display: inline-block;
}
to {
opacity: 1;
transform: translateY(0);
.link-underline::after {
content: '';
position: absolute;
width: 100%;
height: 2px;
bottom: -2px;
left: 0;
background-color: #38a169;
/* Darker green color */
transform: scaleX(0);
transform-origin: bottom right;
transition: transform 0.3s ease-out;
}
}
.animate-dropdown {
animation: dropdown 0.3s ease;
}
.link-underline:hover::after {
transform: scaleX(1);
transform-origin: bottom left;
}
/* Responsive layout adjustments */
.page-content {
transition: margin-top 0.3s ease;
}
/* Header.css */
@keyframes dropdown {
from {
opacity: 0;
transform: translateY(-10px);
}
.page-content.dropdown-active {
margin-top: 12rem;
}
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

@ -7,48 +7,31 @@ const Header = ({ onMenuToggle }) => {
const toggleMenu = () => {
setIsOpen(!isOpen);
if (onMenuToggle) onMenuToggle(!isOpen);
onMenuToggle(!isOpen);
};
return (
<header className="bg-dark-800 text-white py-4 px-6 flex justify-between items-center relative shadow-md">
<div className="flex items-center">
<Link
to="/"
className="text-2xl font-bold bg-gradient-to-r from-primary-500 to-secondary-500 bg-clip-text text-transparent hover:opacity-90 transition-opacity duration-300"
>
DoTechBro.org
</Link>
<header className="bg-gray-900 text-white p-4 flex justify-between items-center relative">
<div className="text-2xl font-bold">
<Link to="/" className="relative">DoTechBro.org</Link>
</div>
<div className="md:hidden">
<button
onClick={toggleMenu}
className="p-2 rounded-md hover:bg-dark-700 focus:outline-none focus:ring-2 focus:ring-primary-500 transition-colors"
aria-label={isOpen ? "Close menu" : "Open menu"}
aria-expanded={isOpen}
>
<button onClick={toggleMenu} className="focus:outline-none">
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<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:items-center md:space-x-8">
<Link to="/" className="link-underline text-white hover:text-primary-400 transition-colors">Home</Link>
<Link to="/about" className="link-underline text-white hover:text-primary-400 transition-colors">About</Link>
<Link to="/roadmap" className="link-underline text-white hover:text-primary-400 transition-colors">Roadmaps</Link>
<Link to="/roadmap" className="ml-4 bg-primary-600 hover:bg-primary-700 text-white py-2 px-4 rounded-lg transition-colors shadow-sm">Get Started</Link>
<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>
{isOpen && (
<div className="absolute top-full left-0 w-full bg-dark-800 text-white shadow-lg rounded-b-lg z-50 md:hidden animate-dropdown">
<div className="flex flex-col py-3 px-6 space-y-4">
<Link to="/" className="py-2 link-underline text-white hover:text-primary-400 transition-colors" onClick={toggleMenu}>Home</Link>
<Link to="/about" className="py-2 link-underline text-white hover:text-primary-400 transition-colors" onClick={toggleMenu}>About</Link>
<Link to="/roadmap" className="py-2 link-underline text-white hover:text-primary-400 transition-colors" onClick={toggleMenu}>Roadmaps</Link>
<Link to="/roadmap" className="bg-primary-600 hover:bg-primary-700 text-white py-2 px-4 rounded-lg text-center transition-colors shadow-sm" onClick={toggleMenu}>Get Started</Link>
</div>
<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>

View file

@ -1,60 +1,23 @@
/* Home.css */
.page-content {
transition: margin-top 0.3s ease;
transition: margin-top 0.5s ease-in-out;
}
.page-content.dropdown-active {
margin-top: 12rem;
margin-top: 150px;
/* Adjust based on the height of the dropdown menu */
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.animate-fade-in {
animation: fadeIn 0.8s ease-out forwards;
}
/* Gradient text effect for headings */
.gradient-text {
background-clip: text;
-webkit-background-clip: text;
color: transparent;
background-image: linear-gradient(to right, var(--color-primary), var(--color-secondary));
}
/* Hover effects for cards */
.feature-card {
transition: all 0.3s ease;
}
.feature-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
}
/* Button hover effects */
.hover-scale {
transition: transform 0.3s ease;
}
.hover-scale:hover {
transform: scale(1.05);
}
/* Image effects */
.image-hover {
transition: all 0.5s ease;
}
.image-hover:hover {
transform: rotate(2deg) scale(1.02);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.3);
animation: fadeIn 1s ease-in-out forwards;
}

View file

@ -1,202 +1,123 @@
import React, { useState, useEffect, useRef } from "react";
import { Link } from "react-router-dom";
import FeaturedRoadmaps from "./FeaturedRoadmaps";
import MailingListDialog from "./MailingListDialog";
import roadmaps from "../roadmaps.json";
import "./Home.css"; // Import the custom CSS file
const Home = () => {
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 = () => {
setDialogOpen(true);
};
const handleDialogClose = () => {
setDialogOpen(false);
};
const handleMenuToggle = (isOpen) => {
setMenuOpen(isOpen);
};
return (
<div className={`page-content ${menuOpen ? "dropdown-active" : ""}`}>
{/* Hero Section */}
<section
className="w-full py-16 md:py-24 bg-gradient-to-b from-dark-900 to-dark-800 text-white opacity-0"
ref={(el) => (sectionsRef.current[0] = el)}
>
<div className="container mx-auto px-6 flex flex-col md:flex-row items-center justify-between gap-12">
<div className="md:w-1/2 flex flex-col items-start">
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold leading-tight mb-4">
Pivot into <span className="text-primary-500">tech</span>
<br />
<span className="font-medium text-3xl md:text-4xl lg:text-5xl">with a head start</span>
</h1>
<p className="text-lg text-gray-300 mb-8 max-w-lg">
Empowering minorities to overcome barriers and succeed in the tech
industry with confidence and community support.
</p>
<div className="flex flex-wrap gap-4">
<button
className="px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-medium rounded-lg shadow-lg transition-colors duration-300 transform hover:scale-105"
onClick={handleDialogOpen}
data-umami-event="Start Today Button"
>
Start Your Journey
</button>
<Link
to="/roadmap"
className="px-6 py-3 bg-transparent border-2 border-primary-500 text-primary-400 font-medium rounded-lg hover:bg-primary-500/10 transition-colors duration-300"
>
Explore Roadmaps
</Link>
</div>
</div>
<div className="mt-8 md:mt-0 md:w-1/2 flex justify-center">
<img
src="/hero-logo.png"
alt="Tech illustration"
className="w-full max-w-md rounded-lg shadow-2xl transform hover:rotate-1 transition-transform duration-500"
/>
</div>
</div>
</section>
{/* Features Section */}
<section
className="w-full py-16 bg-dark-800 text-white opacity-0"
ref={(el) => (sectionsRef.current[1] = el)}
>
<div className="container mx-auto px-6">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold mb-4">Why Choose Our Roadmaps</h2>
<p className="text-lg text-gray-300 max-w-2xl mx-auto">
Our carefully designed roadmaps will guide you through your tech journey with clear steps and resources.
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<div className="bg-dark-700 p-8 rounded-xl shadow-lg hover:shadow-xl transition-shadow">
<div className="text-primary-500 text-4xl mb-4">
<svg xmlns="http://www.w3.org/2000/svg" className="h-12 w-12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" />
</svg>
</div>
<h3 className="text-2xl font-bold mb-2">Curated Resources</h3>
<p className="text-gray-300">
Hand-picked learning resources tested and approved by industry professionals.
</p>
</div>
<div className="bg-dark-700 p-8 rounded-xl shadow-lg hover:shadow-xl transition-shadow">
<div className="text-primary-500 text-4xl mb-4">
<svg xmlns="http://www.w3.org/2000/svg" className="h-12 w-12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path strokeLinecap="round" strokeLinejoin="round" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
</div>
<h3 className="text-2xl font-bold mb-2">Community Support</h3>
<p className="text-gray-300">
Join a community of like-minded individuals on similar journeys.
</p>
</div>
<div className="bg-dark-700 p-8 rounded-xl shadow-lg hover:shadow-xl transition-shadow">
<div className="text-primary-500 text-4xl mb-4">
<svg xmlns="http://www.w3.org/2000/svg" className="h-12 w-12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path strokeLinecap="round" strokeLinejoin="round" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
</svg>
</div>
<h3 className="text-2xl font-bold mb-2">Clear Progression</h3>
<p className="text-gray-300">
Step-by-step guidance from basics to advanced topics with practical challenges.
</p>
</div>
</div>
</div>
</section>
{/* Featured Roadmaps Section */}
<section
className="w-full py-16 bg-gradient-to-b from-dark-800 to-dark-700 text-white opacity-0"
ref={(el) => (sectionsRef.current[2] = el)}
>
<FeaturedRoadmaps roadmaps={roadmaps} />
</section>
{/* Testimonials (Coming Soon) */}
<section
className="w-full py-16 bg-dark-700 text-white opacity-0"
ref={(el) => (sectionsRef.current[3] = el)}
>
<div className="container mx-auto px-6 text-center">
<h2 className="text-3xl md:text-4xl font-bold mb-8">Success Stories</h2>
<div className="bg-dark-600 p-8 rounded-xl shadow-lg max-w-2xl mx-auto">
<p className="text-xl italic mb-6">
"Testimonials from our successful community members coming soon... Join us and become one of our success stories!"
</p>
<div className="flex justify-center">
<Link to="/about" className="text-primary-400 hover:text-primary-300 transition-colors font-medium">
Learn more about our mission
</Link>
</div>
</div>
</div>
</section>
{/* Call to Action */}
<section
className="w-full py-16 bg-gradient-to-b from-dark-700 to-dark-900 text-white opacity-0"
ref={(el) => (sectionsRef.current[4] = el)}
>
<div className="container mx-auto px-6 text-center">
<h2 className="text-3xl md:text-4xl font-bold mb-4">Ready to Start Your Tech Journey?</h2>
<p className="text-lg text-gray-300 max-w-2xl mx-auto mb-8">
Join our community today and get access to all our roadmaps, resources, and supportive network.
</p>
<button
onClick={handleDialogOpen}
className="px-8 py-4 bg-primary-600 hover:bg-primary-700 text-white text-lg font-medium rounded-lg shadow-lg transition-all duration-300 transform hover:scale-105"
data-umami-event="Join Now Button"
>
Join Our Community
</button>
</div>
</section>
<MailingListDialog open={dialogOpen} onClose={handleDialogClose} />
</div>
);
};
export default Home;
import React, { useState, useEffect, useRef } from "react";
import FeaturedRoadmaps from "./FeaturedRoadmaps";
import MailingListDialog from "./MailingListDialog";
import roadmaps from "../roadmaps.json";
import "./Home.css"; // Import the custom CSS file
const Home = () => {
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 = () => {
setDialogOpen(true);
};
const handleDialogClose = () => {
setDialogOpen(false);
};
const handleMenuToggle = (isOpen) => {
setMenuOpen(isOpen);
};
return (
<div className={`page-content ${menuOpen ? "dropdown-active" : ""}`}>
<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 opacity-0"
ref={(el) => (sectionsRef.current[0] = el)}
>
<div className="md:w-1/2 flex flex-col items-center text-center">
<h2 className="text-6xl font-bold leading-tight">
Pivot into <span className="text-green-600">tech.</span>
<br />
<span className="font-semibold">with a head start</span>
</h2>
<p className="mt-4 text-lg max-w-2xl">
Empowering minorities to overcome barriers and succeed in the tech
industry with confidence.
</p>
<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
</button>
</div>
<div className="mt-8 md:mt-0 md:w-1/2 flex justify-center">
<img
src="/hero-logo.png"
alt="Tech illustration"
className="w-full max-w-md rounded-lg shadow-lg"
/>
</div>
</div>
<div
className="w-full bg-gray-900 text-white py-16 opacity-0"
ref={(el) => (sectionsRef.current[1] = el)}
>
<FeaturedRoadmaps roadmaps={roadmaps} />
</div>
<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>
<p className="text-lg">Coming soon...</p>
</div>
<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>
<p className="text-lg max-w-2xl mx-auto">
Connect with like-minded individuals, share your journey, and get
support from our community.
</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"
>
Join Now
</button>
</div>
<MailingListDialog open={dialogOpen} onClose={handleDialogClose} />
</div>
</div>
);
};
export default Home;

View file

@ -6,50 +6,6 @@ import DialogContentText from "@mui/material/DialogContentText";
import DialogTitle from "@mui/material/DialogTitle";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
import { createTheme, ThemeProvider } from '@mui/material/styles';
// Create a custom theme that matches our design system
const theme = createTheme({
palette: {
primary: {
main: '#22c55e', // primary-600 color
},
secondary: {
main: '#6366f1', // secondary-500 color
},
background: {
default: '#0f172a', // dark-900 color
paper: '#1e293b', // dark-800 color
},
text: {
primary: '#f8fafc',
secondary: '#94a3b8',
},
},
typography: {
fontFamily: 'Inter, system-ui, sans-serif',
},
shape: {
borderRadius: 8,
},
components: {
MuiButton: {
styleOverrides: {
root: {
textTransform: 'none',
fontWeight: 500,
},
},
},
MuiDialog: {
styleOverrides: {
paper: {
borderRadius: 12,
},
},
},
},
});
const MailingListDialog = ({ open, onClose }) => {
const [name, setName] = useState("");
@ -62,19 +18,6 @@ const MailingListDialog = ({ open, onClose }) => {
setError("");
setSuccess("");
// Basic validation
if (!name.trim() || !email.trim()) {
setError("Please fill in all fields");
return;
}
// Email validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
setError("Please enter a valid email address");
return;
}
const form = document.createElement("form");
form.action = "https://tech.us9.list-manage.com/subscribe/post";
form.method = "POST";
@ -102,141 +45,63 @@ const MailingListDialog = ({ open, onClose }) => {
setSuccess("Thank you for subscribing!");
setName("");
setEmail("");
// Close the dialog after a short delay to allow user to see the success message
setTimeout(() => {
onClose();
}, 1500);
onClose();
};
return (
<ThemeProvider theme={theme}>
<Dialog
open={open}
onClose={onClose}
PaperProps={{
sx: {
bgcolor: 'background.paper',
color: 'text.primary',
maxWidth: '500px',
width: '100%',
}
}}
>
<DialogTitle sx={{ fontSize: '1.5rem', fontWeight: 700, pb: 1 }}>
Join Our Community
</DialogTitle>
<DialogContent>
<DialogContentText sx={{ color: 'text.secondary', mb: 3 }}>
Get exclusive access to roadmaps, resources, and updates to accelerate your tech journey.
<Dialog open={open} onClose={onClose}>
<DialogTitle>Join Our Mailing List</DialogTitle>
<DialogContent>
<DialogContentText>
Stay updated with the latest news and updates from Do Tech Bro.
</DialogContentText>
<TextField
autoFocus
margin="dense"
id="name"
label="Name"
type="text"
fullWidth
variant="outlined"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<TextField
margin="dense"
id="email"
label="Email Address"
type="email"
fullWidth
variant="outlined"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<DialogContentText className="mt-2 text-xs text-gray-600">
We promise not to sell your information or email you more than once or
twice a month.
</DialogContentText>
{error && (
<DialogContentText className="mt-2 text-xs text-red-600">
{error}
</DialogContentText>
<TextField
autoFocus
margin="dense"
id="name"
label="Full Name"
type="text"
fullWidth
variant="outlined"
value={name}
onChange={(e) => setName(e.target.value)}
sx={{
mb: 2,
'& .MuiOutlinedInput-root': {
'& fieldset': {
borderColor: 'rgba(148, 163, 184, 0.2)',
},
'&:hover fieldset': {
borderColor: 'primary.main',
},
},
'& .MuiInputLabel-root': {
color: 'text.secondary',
},
'& .MuiInputBase-input': {
color: 'text.primary',
}
}}
/>
<TextField
margin="dense"
id="email"
label="Email Address"
type="email"
fullWidth
variant="outlined"
value={email}
onChange={(e) => setEmail(e.target.value)}
sx={{
mb: 2,
'& .MuiOutlinedInput-root': {
'& fieldset': {
borderColor: 'rgba(148, 163, 184, 0.2)',
},
'&:hover fieldset': {
borderColor: 'primary.main',
},
},
'& .MuiInputLabel-root': {
color: 'text.secondary',
},
'& .MuiInputBase-input': {
color: 'text.primary',
}
}}
/>
<DialogContentText sx={{ mt: 2, fontSize: '0.85rem', color: 'text.secondary', opacity: 0.8 }}>
We promise not to sell your information or email you more than once or
twice a month.
)}
{success && (
<DialogContentText className="mt-2 text-xs text-green-600">
{success}
</DialogContentText>
{error && (
<DialogContentText sx={{ mt: 2, color: '#ef4444', fontSize: '0.875rem' }}>
{error}
</DialogContentText>
)}
{success && (
<DialogContentText sx={{ mt: 2, color: 'primary.main', fontSize: '0.875rem' }}>
{success}
</DialogContentText>
)}
</DialogContent>
<DialogActions sx={{ px: 3, pb: 3 }}>
<Button
onClick={onClose}
sx={{
color: 'text.secondary',
'&:hover': {
backgroundColor: 'rgba(148, 163, 184, 0.1)',
}
}}
>
Cancel
</Button>
<Button
onClick={handleSubmit}
variant="contained"
color="primary"
sx={{
px: 4,
'&:hover': {
backgroundColor: 'primary.dark',
}
}}
>
Subscribe
</Button>
</DialogActions>
</Dialog>
</ThemeProvider>
)}
</DialogContent>
<DialogActions>
<Button onClick={onClose} color="primary">
Cancel
</Button>
<Button onClick={handleSubmit} color="primary">
Subscribe
</Button>
</DialogActions>
</Dialog>
);
};
export default MailingListDialog;
export default MailingListDialog;

View file

@ -1,47 +0,0 @@
import { Link } from 'react-router-dom';
const NotFound = () => {
return (
<div className="flex flex-col items-center justify-center min-h-screen bg-dark-900 text-white px-4">
<div className="text-center max-w-lg">
<h1 className="text-8xl font-bold bg-gradient-to-r from-primary-500 to-secondary-500 bg-clip-text text-transparent mb-6">404</h1>
<h2 className="text-3xl font-bold mb-4">Page Not Found</h2>
<p className="text-gray-300 mb-8">
Oops! The page you're looking for doesn't exist or has been moved to a different location.
</p>
<div className="flex flex-wrap justify-center gap-4">
<Link
to="/"
className="px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-medium rounded-lg shadow-lg transition-colors"
>
Return Home
</Link>
<Link
to="/roadmap"
className="px-6 py-3 border-2 border-primary-500 text-primary-400 hover:bg-primary-500/10 font-medium rounded-lg transition-colors"
>
Explore Roadmaps
</Link>
</div>
<div className="mt-16">
<p className="text-gray-400 mb-2">
Think this is a mistake? Let us know!
</p>
<a
href="mailto:support@dotechbro.org"
className="text-primary-400 hover:text-primary-300 transition-colors"
>
support@dotechbro.org
</a>
</div>
</div>
</div>
);
};
export default NotFound;

View file

@ -1,145 +1,12 @@
import { Outlet, useLocation, Link } from 'react-router-dom';
import challenges from '../challenges';
import roadmaps from '../roadmaps.json';
import Accordion from './Accordion';
const Roadmap = () => {
const location = useLocation();
const isRootPath = location.pathname === '/roadmap';
return (
<div className="bg-dark-900 text-white min-h-screen">
{isRootPath ? (
<>
{/* Hero Section */}
<section className="py-16 md:py-24 bg-gradient-to-b from-dark-800 to-dark-900">
<div className="container mx-auto px-6">
<div className="max-w-3xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-6">Tech Career Roadmaps</h1>
<p className="text-xl text-gray-300 leading-relaxed mb-8">
Structured pathways to help you navigate your journey into tech, with step-by-step guidance
and curated resources tailored for minorities entering the industry.
</p>
<div className="inline-flex items-center justify-center p-1 rounded-lg bg-gradient-to-r from-primary-500 to-secondary-500">
<a href="#roadmaps" className="bg-dark-800 text-white font-medium px-6 py-3 rounded-md hover:bg-dark-700 transition-colors">
Explore Roadmaps
</a>
</div>
</div>
</div>
</section>
{/* Challenges Section */}
<section className="py-16 bg-dark-800" id="challenges">
<div className="container mx-auto px-6">
<div className="max-w-3xl mx-auto">
<h2 className="text-3xl font-bold mb-8 text-center">Common Challenges</h2>
<p className="text-lg text-gray-300 text-center mb-12">
We understand the unique obstacles minorities face when entering tech.
Here's how our roadmaps address these challenges.
</p>
<Accordion items={challenges} />
</div>
</div>
</section>
{/* Roadmaps Section */}
<section className="py-16 bg-gradient-to-b from-dark-900 to-dark-800" id="roadmaps">
<div className="container mx-auto px-6">
<h2 className="text-3xl font-bold text-center mb-6">Available Roadmaps</h2>
<p className="text-lg text-gray-300 text-center max-w-3xl mx-auto mb-12">
Select a roadmap that aligns with your interests and goals. Each provides a clear path
from beginner to professional.
</p>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{roadmaps.map((roadmap, index) => (
<Link
key={index}
to={`/roadmap/${roadmap.id}`}
className="group bg-dark-700 rounded-xl overflow-hidden shadow-lg hover:shadow-xl transition-all duration-300 flex flex-col h-full"
>
<div className="p-1 bg-gradient-to-r from-primary-500 to-secondary-500">
<div className="bg-dark-700 p-6 flex-grow">
<h3 className="text-2xl font-bold mb-4 group-hover:text-primary-400 transition-colors">
{roadmap.title}
</h3>
<p className="text-gray-300 mb-6">{roadmap.description}</p>
<div className="flex flex-wrap gap-2 mb-4">
{['Beginner-Friendly', 'Step-by-Step', 'Resource Links'].map((tag, i) => (
<span key={i} className="text-xs bg-dark-600 text-gray-300 px-2 py-1 rounded-full">
{tag}
</span>
))}
</div>
</div>
</div>
<div className="p-4 bg-dark-600 text-primary-400 font-medium flex justify-between items-center">
<span>View Roadmap</span>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 transform group-hover:translate-x-1 transition-transform" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14 5l7 7m0 0l-7 7m7-7H3" />
</svg>
</div>
</Link>
))}
</div>
</div>
</section>
{/* Coming Soon Section */}
<section className="py-16 bg-dark-800">
<div className="container mx-auto px-6">
<div className="bg-gradient-to-r from-dark-700 to-dark-600 rounded-xl p-8 max-w-4xl mx-auto">
<h3 className="text-2xl font-bold mb-4 text-center">More Roadmaps Coming Soon</h3>
<div className="flex flex-col md:flex-row items-center gap-8">
<div className="md:w-3/4">
<p className="text-gray-300 mb-4">
We're actively developing additional roadmaps for various tech roles including:
</p>
<ul className="list-disc list-inside text-gray-300 mb-4 space-y-2">
<li>Cloud Engineering</li>
<li>Machine Learning & AI</li>
<li>Product Management</li>
<li>Cybersecurity</li>
<li>Mobile App Development</li>
</ul>
<p className="text-gray-300">
Subscribe to our newsletter to get notified when new roadmaps are released.
</p>
</div>
<div className="md:w-1/4 flex justify-center">
<div className="w-24 h-24 rounded-full bg-dark-500 flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" className="h-12 w-12 text-primary-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
</div>
</div>
</div>
</div>
</div>
</section>
{/* Contribute Section */}
<section className="py-16 bg-gradient-to-b from-dark-800 to-dark-900">
<div className="container mx-auto px-6 text-center">
<h3 className="text-3xl font-bold mb-6">Open Source Collaboration</h3>
<p className="text-lg text-gray-300 mb-8 max-w-2xl mx-auto">
These roadmaps are open source and we welcome contributions from the community.
Help us improve these resources for everyone.
</p>
<div className="inline-block bg-gradient-to-r from-primary-500 to-secondary-500 p-0.5 rounded-lg">
<button className="px-8 py-3 bg-dark-800 hover:bg-dark-700 text-white font-medium rounded-md transition-colors">
Contribute on GitHub
</button>
</div>
</div>
</section>
</>
) : (
<Outlet />
)}
const Roadmap = () => (
<div className="p-8 flex flex-col items-center justify-center min-h-screen bg-gray-100">
<h2 className="text-4xl font-bold text-center leading-tight">
Roadmaps
</h2>
<p className="mt-4 text-lg text-center max-w-2xl">
Explore our detailed roadmaps to guide your journey into the tech industry.
</p>
</div>
);
};
);
export default Roadmap;
export default Roadmap;

View file

@ -1,243 +0,0 @@
// src/components/RoadmapDetail.jsx
import React, { useState, useEffect } from 'react';
import { useParams, Link } from 'react-router-dom';
import roadmaps from '../roadmaps.json';
const RoadmapDetail = () => {
const { id } = useParams();
const [roadmap, setRoadmap] = useState(null);
const [activeStep, setActiveStep] = useState(0);
useEffect(() => {
// Find the roadmap with the matching id
const foundRoadmap = roadmaps.find(r => r.id === id);
if (foundRoadmap) {
setRoadmap(foundRoadmap);
}
}, [id]);
if (!roadmap) {
return (
<div className="container mx-auto px-6 py-16 text-center">
<h2 className="text-3xl font-bold mb-4">Roadmap Not Found</h2>
<p className="text-gray-300 mb-8">We couldn't find the roadmap you're looking for.</p>
<Link
to="/roadmap"
className="px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white rounded-lg transition-colors"
>
View All Roadmaps
</Link>
</div>
);
}
// Mock data for steps (this would come from the roadmap data in a real implementation)
const steps = [
{
title: "Getting Started",
description: "Begin your journey by understanding the fundamentals and setting up your learning environment.",
content: `
<p>Welcome to your tech journey! This first phase is all about building a solid foundation. You'll get familiar with key concepts, tools, and start building habits that will serve you throughout your career.</p>
<h4>Key Objectives:</h4>
<ul>
<li>Understand the field and career opportunities</li>
<li>Set up your development environment</li>
<li>Learn the fundamental concepts</li>
<li>Build your first small projects</li>
</ul>
`,
resources: [
{ title: "Free Code Camp", url: "https://www.freecodecamp.org/" },
{ title: "The Odin Project", url: "https://www.theodinproject.com/" },
{ title: "MDN Web Docs", url: "https://developer.mozilla.org/" }
]
},
{
title: "Building Skills",
description: "Develop core technical skills and start working on meaningful projects.",
content: `
<p>Now that you have the basics down, it's time to deepen your knowledge and start applying what you've learned to more complex problems and projects.</p>
<h4>Key Objectives:</h4>
<ul>
<li>Master core programming concepts</li>
<li>Learn industry-standard tools and frameworks</li>
<li>Build a portfolio of projects</li>
<li>Practice problem-solving skills</li>
</ul>
`,
resources: [
{ title: "LeetCode", url: "https://leetcode.com/" },
{ title: "GitHub Learning Lab", url: "https://lab.github.com/" },
{ title: "Codecademy", url: "https://www.codecademy.com/" }
]
},
{
title: "Professional Development",
description: "Prepare for the job market and develop professional skills.",
content: `
<p>Technical skills are just one part of a successful tech career. In this phase, you'll focus on the professional aspects of working in tech and prepare for your job search.</p>
<h4>Key Objectives:</h4>
<ul>
<li>Create a professional resume and online presence</li>
<li>Develop interview skills (technical and behavioral)</li>
<li>Build your network and find mentors</li>
<li>Learn about industry practices and workflows</li>
</ul>
`,
resources: [
{ title: "Tech Interview Handbook", url: "https://www.techinterviewhandbook.org/" },
{ title: "LinkedIn Learning", url: "https://www.linkedin.com/learning/" },
{ title: "AngelList", url: "https://angel.co/jobs" }
]
},
{
title: "Landing Your First Role",
description: "Strategies for job searching and excelling in your first position.",
content: `
<p>This is where all your hard work comes together. You'll apply for jobs, go through interviews, and start your professional journey in tech.</p>
<h4>Key Objectives:</h4>
<ul>
<li>Develop an effective job search strategy</li>
<li>Prepare for technical and behavioral interviews</li>
<li>Evaluate job offers and negotiate compensation</li>
<li>Plan for success in your first 90 days</li>
</ul>
`,
resources: [
{ title: "Hired", url: "https://hired.com/" },
{ title: "Glassdoor", url: "https://www.glassdoor.com/" },
{ title: "Blind", url: "https://www.teamblind.com/" }
]
}
];
return (
<div className="container mx-auto px-6 py-16">
{/* Roadmap Header */}
<div className="mb-16 text-center">
<Link to="/roadmap" className="text-primary-400 hover:text-primary-300 transition-colors inline-flex items-center mb-6">
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z" clipRule="evenodd" />
</svg>
Back to Roadmaps
</Link>
<h1 className="text-4xl md:text-5xl font-bold mb-4">{roadmap.title}</h1>
<p className="text-xl text-gray-300 max-w-3xl mx-auto">{roadmap.description}</p>
</div>
{/* Progress Indicator */}
<div className="mb-12">
<div className="relative">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t-2 border-dark-600"></div>
</div>
<div className="relative flex justify-between">
{steps.map((step, index) => (
<button
key={index}
onClick={() => setActiveStep(index)}
className={`flex items-center justify-center w-12 h-12 rounded-full text-lg font-bold ${
index === activeStep
? 'bg-primary-500 text-white shadow-lg'
: index < activeStep
? 'bg-primary-800 text-primary-200'
: 'bg-dark-600 text-gray-400'
} transition-all duration-300`}
>
{index + 1}
</button>
))}
</div>
</div>
<div className="mt-4 flex justify-between">
{steps.map((step, index) => (
<div key={index} className={`text-center w-1/4 px-2 ${
index === activeStep ? 'text-white' : 'text-gray-400'
}`}>
<h4 className="font-medium text-sm md:text-base truncate">{step.title}</h4>
</div>
))}
</div>
</div>
{/* Active Step Content */}
<div className="bg-dark-800 rounded-xl shadow-lg overflow-hidden">
<div className="p-1 bg-gradient-to-r from-primary-500 to-secondary-500">
<div className="bg-dark-800 p-8">
<h2 className="text-3xl font-bold mb-2">{steps[activeStep].title}</h2>
<p className="text-xl text-gray-300 mb-6">{steps[activeStep].description}</p>
<div className="prose prose-invert max-w-none mb-8" dangerouslySetInnerHTML={{ __html: steps[activeStep].content }}></div>
<div className="bg-dark-700 p-6 rounded-lg">
<h3 className="text-xl font-bold mb-4">Recommended Resources</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{steps[activeStep].resources.map((resource, index) => (
<a
key={index}
href={resource.url}
target="_blank"
rel="noopener noreferrer"
className="bg-dark-600 hover:bg-dark-500 p-4 rounded-lg transition-colors flex items-center"
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mr-2 text-primary-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
<span>{resource.title}</span>
</a>
))}
</div>
</div>
</div>
</div>
</div>
{/* Navigation Buttons */}
<div className="mt-8 flex justify-between">
<button
onClick={() => setActiveStep(Math.max(0, activeStep - 1))}
disabled={activeStep === 0}
className={`flex items-center px-6 py-3 rounded-lg transition-colors ${
activeStep === 0
? 'bg-dark-700 text-gray-500 cursor-not-allowed'
: 'bg-dark-700 hover:bg-dark-600 text-white'
}`}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
Previous Step
</button>
<button
onClick={() => setActiveStep(Math.min(steps.length - 1, activeStep + 1))}
disabled={activeStep === steps.length - 1}
className={`flex items-center px-6 py-3 rounded-lg transition-colors ${
activeStep === steps.length - 1
? 'bg-dark-700 text-gray-500 cursor-not-allowed'
: 'bg-primary-600 hover:bg-primary-700 text-white'
}`}
>
Next Step
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 ml-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
{/* Community Support Section */}
<div className="mt-16 bg-dark-700 rounded-xl p-8 text-center">
<h3 className="text-2xl font-bold mb-4">Need Support?</h3>
<p className="text-gray-300 mb-6">
Join our community to connect with mentors and peers who are on similar journeys.
Get answers to your questions and share your progress.
</p>
<button className="px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white rounded-lg transition-colors">
Join Our Community
</button>
</div>
</div>
);
};
export default RoadmapDetail;

View file

@ -4,184 +4,65 @@
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.95);
background-color: #0f172a;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Base typography scale */
--font-size-xs: 0.75rem;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
--font-size-3xl: 1.875rem;
--font-size-4xl: 2.25rem;
--font-size-5xl: 3rem;
/* Spacing scale */
--spacing-0: 0;
--spacing-1: 0.25rem;
--spacing-2: 0.5rem;
--spacing-3: 0.75rem;
--spacing-4: 1rem;
--spacing-6: 1.5rem;
--spacing-8: 2rem;
--spacing-12: 3rem;
--spacing-16: 4rem;
/* Colors */
--color-primary: #22c55e;
--color-primary-dark: #15803d;
--color-primary-light: #4ade80;
--color-secondary: #6366f1;
--color-secondary-dark: #4338ca;
--color-secondary-light: #818cf8;
--color-dark: #0f172a;
--color-dark-lighter: #1e293b;
--color-gray: #64748b;
--color-gray-light: #94a3b8;
}
a {
font-weight: 500;
color: var(--color-secondary);
color: #646cff;
text-decoration: inherit;
transition: color 0.2s ease;
}
a:hover {
color: var(--color-secondary-light);
color: #535bf2;
}
body {
margin: 0;
display: flex;
flex-direction: column;
place-items: center;
min-width: 320px;
min-height: 100vh;
overflow-x: hidden;
background-color: var(--color-dark);
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
font-weight: 700;
line-height: 1.2;
}
h1 {
font-size: var(--font-size-4xl);
margin-bottom: var(--spacing-6);
}
h2 {
font-size: var(--font-size-3xl);
margin-bottom: var(--spacing-4);
}
h3 {
font-size: var(--font-size-2xl);
margin-bottom: var(--spacing-3);
}
p {
margin-top: 0;
margin-bottom: var(--spacing-4);
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 0.5rem;
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: var(--color-dark-lighter);
background-color: #1a1a1a;
cursor: pointer;
transition: all 0.2s ease;
transition: border-color 0.25s;
}
button:hover {
border-color: var(--color-primary);
background-color: rgba(34, 197, 94, 0.1);
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
/* Custom utility classes */
.container {
width: 100%;
max-width: 1280px;
margin: 0 auto;
padding: 0 1rem;
}
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.5rem 1.5rem;
font-weight: 500;
border-radius: 0.5rem;
transition: all 0.2s ease;
}
.btn-primary {
background-color: var(--color-primary);
color: #fff;
}
.btn-primary:hover {
background-color: var(--color-primary-dark);
}
.btn-secondary {
background-color: var(--color-secondary);
color: #fff;
}
.btn-secondary:hover {
background-color: var(--color-secondary-dark);
}
.btn-outline {
background-color: transparent;
border: 1px solid var(--color-primary);
color: var(--color-primary);
}
.btn-outline:hover {
background-color: var(--color-primary);
color: #fff;
outline: 4px auto -webkit-focus-ring-color;
}
@media (prefers-color-scheme: light) {
:root {
color: #334155;
background-color: #f8fafc;
--color-dark: #f8fafc;
--color-dark-lighter: #f1f5f9;
color: #213547;
background-color: #ffffff;
}
body {
background-color: #f8fafc;
a:hover {
color: #747bff;
}
button {
background-color: #e2e8f0;
}
button:hover {
background-color: rgba(34, 197, 94, 0.1);
background-color: #f9f9f9;
}
}

View file

@ -6,116 +6,9 @@ export default {
],
theme: {
extend: {
colors: {
primary: {
50: '#f0fdf4',
100: '#dcfce7',
200: '#bbf7d0',
300: '#86efac',
400: '#4ade80',
500: '#22c55e',
600: '#16a34a',
700: '#15803d',
800: '#166534',
900: '#14532d',
950: '#052e16',
},
secondary: {
50: '#eef2ff',
100: '#e0e7ff',
200: '#c7d2fe',
300: '#a5b4fc',
400: '#818cf8',
500: '#6366f1',
600: '#4f46e5',
700: '#4338ca',
800: '#3730a3',
900: '#312e81',
950: '#1e1b4b',
},
dark: {
50: '#f9fafb',
100: '#f3f4f6',
200: '#e5e7eb',
300: '#d1d5db',
400: '#9ca3af',
500: '#6b7280',
600: '#4b5563',
700: '#374151',
800: '#1f2937',
900: '#111827',
950: '#030712',
},
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
inter: ['Inter', 'sans-serif'],
},
fontSize: {
xs: ['0.75rem', { lineHeight: '1rem' }],
sm: ['0.875rem', { lineHeight: '1.25rem' }],
base: ['1rem', { lineHeight: '1.5rem' }],
lg: ['1.125rem', { lineHeight: '1.75rem' }],
xl: ['1.25rem', { lineHeight: '1.75rem' }],
'2xl': ['1.5rem', { lineHeight: '2rem' }],
'3xl': ['1.875rem', { lineHeight: '2.25rem' }],
'4xl': ['2.25rem', { lineHeight: '2.5rem' }],
'5xl': ['3rem', { lineHeight: '1.16' }],
'6xl': ['3.75rem', { lineHeight: '1.16' }],
},
spacing: {
'0': '0',
'1': '0.25rem',
'2': '0.5rem',
'3': '0.75rem',
'4': '1rem',
'5': '1.25rem',
'6': '1.5rem',
'8': '2rem',
'10': '2.5rem',
'12': '3rem',
'16': '4rem',
'20': '5rem',
'24': '6rem',
'32': '8rem',
'40': '10rem',
'48': '12rem',
'56': '14rem',
'64': '16rem',
'72': '18rem',
'80': '20rem',
'96': '24rem',
},
borderRadius: {
'none': '0',
'sm': '0.125rem',
DEFAULT: '0.25rem',
'md': '0.375rem',
'lg': '0.5rem',
'xl': '0.75rem',
'2xl': '1rem',
'3xl': '1.5rem',
'full': '9999px',
},
boxShadow: {
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
DEFAULT: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
'2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
inner: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)',
none: 'none',
},
animation: {
'dropdown': 'dropdown 0.3s ease-in-out',
},
keyframes: {
dropdown: {
'0%': { opacity: 0, transform: 'translateY(-10px)' },
'100%': { opacity: 1, transform: 'translateY(0)' },
},
},
},
},
plugins: [],