Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions public/cursor.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 6 additions & 1 deletion src/App.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
/* Remove the restrictive max-width and padding */
#root {
width: 100%;
margin: 0;
padding: 0;
}

/* Force custom cursor globally */
* {
cursor: url('/cursor.svg') 4 0, auto !important;
}


.logo {
height: 6em;
padding: 1.5em;
Expand Down
4 changes: 4 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import HomePage from './components/HomePage';
import Books from './components/Books';
import Journey from './components/Journey';
import QuestionBank from './components/QuestionBank';
import PrivacyPolicy from './components/PrivacyPolicy';
import TermsOfUse from './components/TermsOfUse';
import ReactGA from 'react-ga4';
const trackingId = import.meta.env.VITE_APP_GA_TRACKING_ID;
if (trackingId) {
Expand All @@ -30,6 +32,8 @@ const App = () => {
<Route path="/books" element={<Books />} />
<Route path="/journey" element={<Journey />} />
<Route path="/questionbank" element={<QuestionBank />} />
<Route path="/privacy" element={<PrivacyPolicy />} />
<Route path="/terms" element={<TermsOfUse />} />
<Route path="*" element={<Error404 />} />
</Routes>
</div>
Expand Down
43 changes: 43 additions & 0 deletions src/components/BackToTopButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { useState, useEffect } from 'react';
import { ArrowUp } from 'lucide-react';

const BackToTopButton = () => {
const [isVisible, setIsVisible] = useState(false);

// Show button when page is scrolled down
const toggleVisibility = () => {
if (window.scrollY > 300) {
setIsVisible(true);
} else {
setIsVisible(false);
}
};

// Scroll to top smoothly
const scrollToTop = () => {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
};

useEffect(() => {
window.addEventListener('scroll', toggleVisibility);

return () => {
window.removeEventListener('scroll', toggleVisibility);
};
}, []);

return (
<button
className={`fixed bottom-8 right-8 z-50 p-3 rounded-full bg-gradient-to-r from-blue-500 to-indigo-600 text-white shadow-lg hover:from-blue-600 hover:to-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:focus:ring-offset-gray-900 transition-all duration-300 ${isVisible ? 'opacity-100 scale-100' : 'opacity-0 scale-90'}`}
onClick={scrollToTop}
aria-label="Go to top"
>
<ArrowUp className="w-6 h-6" />
</button>
);
};

export default BackToTopButton;
67 changes: 33 additions & 34 deletions src/components/Books.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React, { useState, useEffect } from 'react';
import React, { useState } from 'react';
import ReactGA from 'react-ga4';
import { Book, ExternalLink, Search } from 'lucide-react';
import Navbar from './Navbar';
import Footer from './Footer';
import { Helmet } from 'react-helmet';
import useDarkMode from './useDarkMode';

const books = [
{ title: 'Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow', author: 'Aurélien Géron', link: 'https://www.bayanbox.ir/view/9006149947423722897/Hands-On-Machine-Learning-with-Scikit-Learn-Keras-and-TensorFlow.pdf', category: 'Machine Learning' },
Expand Down Expand Up @@ -31,23 +32,10 @@ const articles = [
const Books = () => {
ReactGA.send({ hitType: 'pageview', page: window.location.pathname });

const [darkMode, setDarkMode] = useState(false);
const [darkMode, toggleDarkMode] = useDarkMode();
const [searchTerm, setSearchTerm] = useState('');
const [selectedCategory, setSelectedCategory] = useState('all');

useEffect(() => {
const savedDarkMode = localStorage.getItem('darkMode') === 'true';
setDarkMode(savedDarkMode);
document.documentElement.classList.toggle('dark', savedDarkMode);
}, []);

const toggleDarkMode = () => {
const newDarkMode = !darkMode;
setDarkMode(newDarkMode);
document.documentElement.classList.toggle('dark', newDarkMode);
localStorage.setItem('darkMode', newDarkMode);
};

const categories = ['all', ...new Set([...books, ...articles].map(item => item.category))];

const filteredBooks = books.filter(book =>
Expand Down Expand Up @@ -102,15 +90,18 @@ const Books = () => {
<div className="flex flex-col md:flex-row gap-4 mb-8">
<div className="relative flex-1">
<div className="absolute inset-y-0 left-3 flex items-center pointer-events-none">
<Search className="w-5 h-5 text-gray-400" />
<Search className={`w-5 h-5 ${darkMode ? 'text-gray-500' : 'text-gray-400'}`} />
</div>
<input
type="text"
placeholder="Search by title or author..."
className="w-full pl-10 pr-4 py-3 rounded-xl border border-gray-200 dark:border-gray-700
bg-white dark:bg-gray-800 text-gray-900 dark:text-white
className={`w-full pl-10 pr-4 py-3 rounded-xl border
${darkMode
? 'border-gray-700 bg-gray-800 text-white placeholder-gray-400'
: 'border-gray-200 bg-white text-gray-900 placeholder-gray-400'
}
shadow-sm focus:ring-2 focus:ring-blue-600 focus:border-transparent
transition-all duration-200"
transition-all duration-200`}
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
Expand All @@ -120,10 +111,12 @@ const Books = () => {
<button
key={category}
onClick={() => setSelectedCategory(category)}
className={`px-4 py-2 rounded-lg text-sm font-medium whitespace-nowrap
className={`px-4 py-2 rounded-lg text-sm font-medium whitespace-nowrap transition-all
${selectedCategory === category
? 'bg-blue-600 text-white'
: 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600'
: darkMode
? 'bg-gray-800 text-gray-300 hover:bg-gray-700 border border-gray-700'
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
}`}
>
{category.charAt(0).toUpperCase() + category.slice(1)}
Expand All @@ -142,16 +135,19 @@ const Books = () => {
{filteredBooks.map((book, index) => (
<div
key={index}
className={`bg-white dark:bg-gray-800 rounded-xl shadow-sm hover:shadow-md
transition-all duration-200 border border-gray-200 dark:border-gray-700`}
className={`rounded-xl shadow-sm hover:shadow-md transition-all duration-200
${darkMode
? 'bg-gray-800 border border-gray-700'
: 'bg-white border border-gray-200'
}`}
>
<div className="p-6">
<div className="flex items-start justify-between">
<div className="flex-1">
<h3 className="font-semibold text-lg mb-2 line-clamp-2">
<h3 className={`font-semibold text-lg mb-2 line-clamp-2 ${darkMode ? 'text-white' : 'text-gray-900'}`}>
{book.title}
</h3>
<p className="text-gray-600 dark:text-gray-400 text-sm mb-4">
<p className={`text-sm mb-4 ${darkMode ? 'text-gray-400' : 'text-gray-600'}`}>
by {book.author}
</p>
</div>
Expand All @@ -163,7 +159,7 @@ const Books = () => {
href={book.link}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 text-blue-600 dark:text-blue-400 hover:underline"
className={`inline-flex items-center gap-2 hover:underline ${darkMode ? 'text-blue-400' : 'text-blue-600'}`}
>
<span>Read Book</span>
<ExternalLink className="w-4 h-4" />
Expand All @@ -186,16 +182,19 @@ const Books = () => {
{filteredArticles.map((article, index) => (
<div
key={index}
className={`bg-white dark:bg-gray-800 rounded-xl shadow-sm hover:shadow-md
transition-all duration-200 border border-gray-200 dark:border-gray-700`}
className={`rounded-xl shadow-sm hover:shadow-md transition-all duration-200
${darkMode
? 'bg-gray-800 border border-gray-700'
: 'bg-white border border-gray-200'
}`}
>
<div className="p-6">
<div className="flex items-start justify-between">
<div className="flex-1">
<h3 className="font-semibold text-lg mb-2 line-clamp-2">
<h3 className={`font-semibold text-lg mb-2 line-clamp-2 ${darkMode ? 'text-white' : 'text-gray-900'}`}>
{article.title}
</h3>
<p className="text-gray-600 dark:text-gray-400 text-sm mb-4">
<p className={`text-sm mb-4 ${darkMode ? 'text-gray-400' : 'text-gray-600'}`}>
by {article.author}
</p>
</div>
Expand All @@ -207,7 +206,7 @@ const Books = () => {
href={article.link}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 text-blue-600 dark:text-blue-400 hover:underline"
className={`inline-flex items-center gap-2 hover:underline ${darkMode ? 'text-blue-400' : 'text-blue-600'}`}
>
<span>Read Article</span>
<ExternalLink className="w-4 h-4" />
Expand All @@ -222,8 +221,8 @@ const Books = () => {
{filteredBooks.length === 0 && filteredArticles.length === 0 && (
<div className="text-center py-12">
<div className="text-5xl mb-4">🔍</div>
<h3 className="text-xl font-semibold mb-2">No resources found</h3>
<p className="text-gray-600 dark:text-gray-400">
<h3 className={`text-xl font-semibold mb-2 ${darkMode ? 'text-white' : 'text-gray-900'}`}>No resources found</h3>
<p className={darkMode ? 'text-gray-400' : 'text-gray-600'}>
Try adjusting your search or filter to find what you're looking for.
</p>
</div>
Expand All @@ -236,4 +235,4 @@ const Books = () => {
);
};

export default Books;
export default Books;
17 changes: 4 additions & 13 deletions src/components/DeepLearningRoadmap.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import Navbar from './Navbar';
import categorizedDLVideos from '../../categorizedDLContent';
import Modal from './Modal';
import ReactGA from 'react-ga4';
import useDarkMode from './useDarkMode';
import BackToTopButton from './BackToTopButton';
import Footer from './Footer';

const topics = [
Expand All @@ -27,7 +29,7 @@ const DeepLearningRoadmap = () => {
ReactGA.send({ hitType: 'pageview', page: window.location.pathname });

const [selectedTopic, setSelectedTopic] = useState(null);
const [darkMode, setDarkMode] = useState(false);
const [darkMode, toggleDarkMode] = useDarkMode();
const [hoveredTopic, setHoveredTopic] = useState(null);
const [isMobile, setIsMobile] = useState(false);
const [topicProgress, setTopicProgress] = useState({});
Expand All @@ -45,10 +47,6 @@ const DeepLearningRoadmap = () => {
setTopicProgress(parsedProgress);
}

const savedDarkMode = localStorage.getItem('darkMode') === 'true';
setDarkMode(savedDarkMode);
document.documentElement.classList.toggle('dark', savedDarkMode);

const checkMobile = () => {
setIsMobile(window.innerWidth < 768);
};
Expand Down Expand Up @@ -149,14 +147,6 @@ const DeepLearningRoadmap = () => {
console.error('Error saving progress:', error);
}
};

// Toggle dark mode and persist in localStorage
const toggleDarkMode = () => {
const newDarkMode = !darkMode;
setDarkMode(newDarkMode);
document.documentElement.classList.toggle('dark', newDarkMode);
localStorage.setItem('darkMode', newDarkMode);
};

const overallProgress = calculateOverallProgress();

Expand Down Expand Up @@ -431,6 +421,7 @@ const DeepLearningRoadmap = () => {
/>
)}

<BackToTopButton />
<Footer darkMode={darkMode} />
</>
);
Expand Down
19 changes: 5 additions & 14 deletions src/components/GenerativeAIRoadmap.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import Modal from './Modal';
import Navbar from './Navbar';
import ReactGA from 'react-ga4';
import genai from "../../categorizedGenAIContent";
import useDarkMode from './useDarkMode';
import BackToTopButton from './BackToTopButton';
import Footer from './Footer';

const topics = [
Expand All @@ -25,7 +27,7 @@ const GenerativeAIRoadmap = () => {
ReactGA.send({ hitType: 'pageview', page: window.location.pathname });

const [selectedTopic, setSelectedTopic] = useState(null);
const [darkMode, setDarkMode] = useState(false);
const [darkMode, toggleDarkMode] = useDarkMode();
const [hoveredTopic, setHoveredTopic] = useState(null);
const [isMobile, setIsMobile] = useState(false);
const [topicProgress, setTopicProgress] = useState({});
Expand All @@ -43,10 +45,6 @@ const GenerativeAIRoadmap = () => {
setTopicProgress(parsedProgress);
}

const savedDarkMode = localStorage.getItem('darkMode') === 'true';
setDarkMode(savedDarkMode);
document.documentElement.classList.toggle('dark', savedDarkMode);

const checkMobile = () => {
setIsMobile(window.innerWidth < 768);
};
Expand Down Expand Up @@ -147,14 +145,6 @@ const GenerativeAIRoadmap = () => {
console.error('Error saving progress:', error);
}
};

// Toggle dark mode and persist in localStorage
const toggleDarkMode = () => {
const newDarkMode = !darkMode;
setDarkMode(newDarkMode);
document.documentElement.classList.toggle('dark', newDarkMode);
localStorage.setItem('darkMode', newDarkMode);
};

const overallProgress = calculateOverallProgress();

Expand Down Expand Up @@ -355,7 +345,7 @@ const GenerativeAIRoadmap = () => {
<link rel="canonical" href="https://mldl.study/genai" />
</Helmet>

<Navbar darkMode={darkMode} toggleDarkMode={() => setDarkMode(!darkMode)} isTransitioning={false} />
<Navbar darkMode={darkMode} toggleDarkMode={toggleDarkMode} isTransitioning={false} />

<div className={`min-h-screen ${darkMode ? 'bg-gray-900 text-white' : 'bg-gray-50 text-gray-900'}`}>
<div className="container mx-auto px-4 py-8">
Expand Down Expand Up @@ -497,6 +487,7 @@ const GenerativeAIRoadmap = () => {
/>
)}

<BackToTopButton />
<Footer darkMode={darkMode} />
</>
);
Expand Down
Loading