Skip to content

Commit 3da5542

Browse files
Add files via upload
1 parent e94ecfc commit 3da5542

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+11733
-0
lines changed

src/App.css

Lines changed: 474 additions & 0 deletions
Large diffs are not rendered by default.

src/App.js

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import './App.css';
2+
import React, { useState } from 'react';
3+
import { BrowserRouter as Router, Routes, Route, Link, useLocation, useNavigate } from 'react-router-dom';
4+
import Home from './components/Home';
5+
import Services from './components/Services';
6+
import About from './components/About';
7+
import Contact from './components/Contact';
8+
import Blog from './components/Blog';
9+
import Auth from './components/Auth';
10+
import User from './components/User';
11+
import Admin from './components/Admin';
12+
import UserDropdown from './components/UserDropdown';
13+
import techbloggerLogo from '../src/techblogger.png';
14+
15+
16+
// Logout component
17+
function Logout() {
18+
const navigate = useNavigate();
19+
20+
React.useEffect(() => {
21+
// Clear authentication data
22+
localStorage.removeItem('username');
23+
24+
// Redirect to home page
25+
navigate('/', { replace: true });
26+
}, [navigate]);
27+
28+
return (
29+
<div style={{
30+
display: 'flex',
31+
justifyContent: 'center',
32+
alignItems: 'center',
33+
height: '100vh',
34+
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
35+
color: 'white'
36+
}}>
37+
<div style={{ textAlign: 'center' }}>
38+
<h2>Logging out...</h2>
39+
<p>You have been successfully logged out.</p>
40+
</div>
41+
</div>
42+
);
43+
}
44+
45+
function AnimatedMain() {
46+
const location = useLocation();
47+
const [animate, setAnimate] = useState(true);
48+
49+
React.useEffect(() => {
50+
setAnimate(false);
51+
const timeout = setTimeout(() => setAnimate(true), 10);
52+
return () => clearTimeout(timeout);
53+
}, [location.pathname]);
54+
55+
return (
56+
<main className={animate ? 'route-fade-in' : ''}>
57+
<header className="header-container">
58+
<div className="logo-container">
59+
<a href="/"><img src={techbloggerLogo} alt="Tech Blogger Logo" className="logo-img" /></a>
60+
</div>
61+
<nav className="navbar">
62+
<ul className="nav-menu">
63+
<li><Link to="/">Home</Link></li>
64+
<li><Link to="/services">Services</Link></li>
65+
<li><Link to="/about">About Us</Link></li>
66+
<li><Link to="/contact">Contact</Link></li>
67+
<li><Link to="/blog">Blog</Link></li>
68+
</ul>
69+
<UserDropdown />
70+
</nav>
71+
</header>
72+
<Routes>
73+
<Route path="/" element={<Home />} />
74+
<Route path="/services" element={<Services />} />
75+
<Route path="/about" element={<About />} />
76+
<Route path="/contact" element={<Contact />} />
77+
<Route path="/blog" element={<Blog />} />
78+
<Route path="/auth" element={<Auth />} />
79+
<Route path="/user" element={<User />} />
80+
<Route path="/admin" element={<Admin />} />
81+
<Route path="/logout" element={<Logout />} />
82+
</Routes>
83+
</main>
84+
);
85+
}
86+
87+
function ScrollToTop() {
88+
React.useEffect(() => {
89+
window.scrollTo({ top: 0, behavior: 'smooth' });
90+
}, []);
91+
return null;
92+
}
93+
function App() {
94+
const [showScrollBtn, setShowScrollBtn] = useState(false);
95+
const [scrollBtnVisible, setScrollBtnVisible] = useState(false);
96+
const fadeDuration = 400; // ms, must match CSS
97+
98+
React.useEffect(() => {
99+
let timeout;
100+
const handleScroll = () => {
101+
if (window.scrollY > 80) {
102+
setShowScrollBtn(true);
103+
setScrollBtnVisible(true);
104+
if (timeout) clearTimeout(timeout);
105+
} else {
106+
setShowScrollBtn(false);
107+
timeout = setTimeout(() => setScrollBtnVisible(false), fadeDuration);
108+
}
109+
};
110+
window.addEventListener('scroll', handleScroll, { passive: true });
111+
// Check on mount in case already scrolled
112+
handleScroll();
113+
return () => {
114+
window.removeEventListener('scroll', handleScroll);
115+
clearTimeout(timeout);
116+
};
117+
}, []);
118+
119+
return (
120+
<Router>
121+
<AnimatedMain/>
122+
<ScrollToTop />
123+
{scrollBtnVisible && (
124+
<button
125+
className={`scroll-to-top-btn ${showScrollBtn ? 'fade-in' : 'fade-out'}`}
126+
onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
127+
aria-label="Scroll to top"
128+
>
129+
&#8593;
130+
</button>
131+
)}
132+
<footer>
133+
<p>&copy; 2025 Tech Blogger</p>
134+
</footer>
135+
</Router>
136+
);
137+
}
138+
139+
export default App;

src/App.test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { render, screen } from '@testing-library/react';
2+
import App from './App';
3+
4+
test('renders learn react link', () => {
5+
render(<App />);
6+
const linkElement = screen.getByText(/learn react/i);
7+
expect(linkElement).toBeInTheDocument();
8+
});

0 commit comments

Comments
 (0)