Skip to content

Commit 4f7c3db

Browse files
committed
Add reusable Footer component to dashboard and login
Introduces a new Footer component with styling, displaying trademark info and a GitHub source link. Integrates Footer into both the dashboard layout and login page for consistent branding and navigation. Refactors layout and login CSS for improved structure and responsiveness.
1 parent 9bcf8c8 commit 4f7c3db

File tree

6 files changed

+173
-46
lines changed

6 files changed

+173
-46
lines changed

frontend/src/components/auth/Login.css

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1+
.login-page {
2+
display: flex;
3+
flex-direction: column;
4+
min-height: 100vh;
5+
background: var(--bg-secondary);
6+
}
7+
18
.login-container {
29
display: flex;
310
justify-content: center;
411
align-items: center;
5-
min-height: 100vh;
6-
background: var(--bg-secondary);
12+
flex: 1;
713
padding: var(--spacing-lg);
814
}
915

@@ -128,7 +134,7 @@
128134
.login-box {
129135
padding: var(--spacing-xl) var(--spacing-lg);
130136
}
131-
137+
132138
.login-container {
133139
padding: var(--spacing-md);
134140
}

frontend/src/components/auth/Login.tsx

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
22
import { useNavigate } from 'react-router-dom';
33
import authService from '../../services/auth.service';
44
import { Sun, Moon } from 'lucide-react';
5+
import Footer from '../dashboard/Footer';
56
import './Login.css';
67

78
interface LoginProps {
@@ -47,50 +48,53 @@ const Login: React.FC<LoginProps> = ({ onLogin }) => {
4748
};
4849

4950
return (
50-
<div className="login-container">
51-
<div className="login-box">
52-
<h1>WireGuard WebUI</h1>
53-
<h2>Sign In</h2>
51+
<div className="login-page">
52+
<div className="login-container">
53+
<div className="login-box">
54+
<h1>WireGuard WebUI</h1>
55+
<h2>Sign In</h2>
5456

55-
{error && <div className="error-message">{error}</div>}
57+
{error && <div className="error-message">{error}</div>}
5658

57-
<form onSubmit={handleSubmit}>
58-
<div className="form-group">
59-
<label htmlFor="username">Username or Email</label>
60-
<input
61-
type="text"
62-
id="username"
63-
value={username}
64-
onChange={(e) => setUsername(e.target.value)}
65-
placeholder="Enter username or email"
66-
required
67-
autoFocus
68-
/>
69-
<span className="help-text">You can use your username or email to sign in</span>
70-
</div>
59+
<form onSubmit={handleSubmit}>
60+
<div className="form-group">
61+
<label htmlFor="username">Username or Email</label>
62+
<input
63+
type="text"
64+
id="username"
65+
value={username}
66+
onChange={(e) => setUsername(e.target.value)}
67+
placeholder="Enter username or email"
68+
required
69+
autoFocus
70+
/>
71+
<span className="help-text">You can use your username or email to sign in</span>
72+
</div>
7173

72-
<div className="form-group">
73-
<label htmlFor="password">Password</label>
74-
<input
75-
type="password"
76-
id="password"
77-
value={password}
78-
onChange={(e) => setPassword(e.target.value)}
79-
required
80-
/>
81-
</div>
74+
<div className="form-group">
75+
<label htmlFor="password">Password</label>
76+
<input
77+
type="password"
78+
id="password"
79+
value={password}
80+
onChange={(e) => setPassword(e.target.value)}
81+
required
82+
/>
83+
</div>
8284

83-
<button type="submit" disabled={loading}>
84-
{loading ? 'Signing in...' : 'Sign In'}
85-
</button>
86-
</form>
85+
<button type="submit" disabled={loading}>
86+
{loading ? 'Signing in...' : 'Sign In'}
87+
</button>
88+
</form>
8789

88-
<div className="login-theme-toggle">
89-
<button onClick={toggleDarkMode} className="theme-toggle-btn" aria-label={darkMode ? 'Switch to light mode' : 'Switch to dark mode'}>
90-
{darkMode ? <Sun size={16} /> : <Moon size={16} />}
91-
</button>
90+
<div className="login-theme-toggle">
91+
<button onClick={toggleDarkMode} className="theme-toggle-btn" aria-label={darkMode ? 'Switch to light mode' : 'Switch to dark mode'}>
92+
{darkMode ? <Sun size={16} /> : <Moon size={16} />}
93+
</button>
94+
</div>
9295
</div>
9396
</div>
97+
<Footer />
9498
</div>
9599
);
96100
};
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
.footer {
2+
background: var(--bg-primary);
3+
border-top: 1px solid var(--border);
4+
padding: var(--spacing-md) var(--spacing-lg);
5+
margin-top: auto;
6+
}
7+
8+
.footer-content {
9+
display: flex;
10+
align-items: center;
11+
justify-content: space-between;
12+
gap: var(--spacing-lg);
13+
max-width: 100%;
14+
flex-wrap: wrap;
15+
}
16+
17+
.footer-section {
18+
display: flex;
19+
align-items: center;
20+
gap: var(--spacing-sm);
21+
}
22+
23+
.footer-text {
24+
font-size: 12px;
25+
color: var(--text-muted);
26+
margin: 0;
27+
line-height: 1.4;
28+
}
29+
30+
.footer-link {
31+
display: inline-flex;
32+
align-items: center;
33+
gap: 6px;
34+
font-size: 12px;
35+
color: var(--text-secondary);
36+
text-decoration: none;
37+
padding: 4px 8px;
38+
border-radius: var(--radius-sm);
39+
transition: all 0.2s;
40+
}
41+
42+
.footer-link:hover {
43+
color: var(--primary);
44+
background: rgba(136, 23, 26, 0.05);
45+
}
46+
47+
[data-theme="dark"] .footer-link:hover {
48+
background: rgba(136, 23, 26, 0.15);
49+
}
50+
51+
/* Responsive */
52+
@media (min-width: 768px) {
53+
.footer-content {
54+
flex-wrap: nowrap;
55+
}
56+
}
57+
58+
@media (max-width: 768px) {
59+
.footer-content {
60+
flex-direction: column;
61+
align-items: flex-start;
62+
}
63+
64+
.footer-section {
65+
width: 100%;
66+
justify-content: center;
67+
text-align: center;
68+
}
69+
70+
.footer-text {
71+
font-size: 11px;
72+
}
73+
74+
.footer-link {
75+
font-size: 11px;
76+
}
77+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from 'react';
2+
import { Github } from 'lucide-react';
3+
import './Footer.css';
4+
5+
const Footer: React.FC = () => {
6+
return (
7+
<footer className="footer">
8+
<div className="footer-content">
9+
<div className="footer-section">
10+
<p className="footer-text">
11+
"WireGuard" and the "WireGuard" logo are registered trademarks of Jason A. Donenfeld.
12+
</p>
13+
</div>
14+
<div className="footer-section">
15+
<a
16+
href="https://github.com/Arthur2500/wireguard-multiclient-webui"
17+
target="_blank"
18+
rel="noopener noreferrer"
19+
className="footer-link"
20+
aria-label="View source code on GitHub"
21+
>
22+
<Github size={16} /> Source Code
23+
</a>
24+
</div>
25+
</div>
26+
</footer>
27+
);
28+
};
29+
30+
export default Footer;

frontend/src/components/dashboard/Layout.css

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,18 @@
196196
color: var(--text-primary);
197197
}
198198

199-
.main-content {
199+
.main-wrapper {
200200
flex: 1;
201201
margin-left: 250px;
202+
display: flex;
203+
flex-direction: column;
202204
background: var(--bg-secondary);
203205
min-height: 100vh;
204-
max-width: 100vw;
206+
}
207+
208+
.main-content {
209+
flex: 1;
210+
background: var(--bg-secondary);
205211
}
206212

207213
/* Responsive */
@@ -232,7 +238,7 @@
232238
z-index: 999;
233239
}
234240

235-
.main-content {
241+
.main-wrapper {
236242
margin-left: 0;
237243
padding-top: 60px;
238244
}

frontend/src/components/dashboard/Layout.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Link, useLocation, useNavigate } from 'react-router-dom';
33
import { User } from '../../types';
44
import authService from '../../services/auth.service';
55
import { Shield, LayoutDashboard, FolderOpen, Users, BarChart3, LogOut, Sun, Moon, Menu, X, Monitor } from 'lucide-react';
6+
import Footer from './Footer';
67
import './Layout.css';
78

89
interface LayoutProps {
@@ -112,9 +113,12 @@ const Layout: React.FC<LayoutProps> = ({ children, user, onLogout }) => {
112113
</div>
113114
</nav>
114115

115-
<main className="main-content">
116-
{children}
117-
</main>
116+
<div className="main-wrapper">
117+
<main className="main-content">
118+
{children}
119+
</main>
120+
<Footer />
121+
</div>
118122
</div>
119123
);
120124
};

0 commit comments

Comments
 (0)