Skip to content

Commit 93be1b5

Browse files
authored
Merge pull request #70 from indrasuthar07/theme-toggle
Dark/Light Theme toggle
2 parents 317e46d + 48cefd3 commit 93be1b5

24 files changed

+1919
-1412
lines changed

frontend/index.html

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
11
<!doctype html>
2-
<html lang="en">
2+
<html lang="en" suppressHydrationWarning>
33
<head>
44
<meta charset="UTF-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<title>PeerCall - Secure Privacy-Respecting Video Calls</title>
7+
<script>
8+
// Prevent flash of unstyled content - sync with next-themes
9+
(function() {
10+
try {
11+
const theme = localStorage.getItem('peercall-theme');
12+
if (theme === 'dark') {
13+
document.documentElement.classList.add('dark');
14+
} else {
15+
document.documentElement.classList.remove('dark');
16+
}
17+
} catch (e) {
18+
// Ignore errors
19+
}
20+
})();
21+
</script>
722
<meta name="description" content="Secure, privacy-respecting real-time video calls. PeerCall delivers peer-to-peer WebRTC video communication with strong authentication and session management." />
823
<meta name="author" content="PeerCall" />
924
<link rel="preconnect" href="https://fonts.googleapis.com">
1025
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
1126
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
12-
<link href="./src/index.css" rel="stylesheet">
1327
<!-- favicon (use the existing vite.svg as the icon) -->
1428
<link rel="icon" type="image/svg+xml" href="/vite.svg">
1529
<meta property="og:title" content="PeerCall - Secure Privacy-Respecting Video Calls" />
@@ -20,6 +34,5 @@
2034
<body>
2135
<div id="root"></div>
2236
<script type="module" src="/src/main.tsx"></script>
23-
<script src="https://cdn.tailwindcss.com"></script>
2437
</body>
2538
</html>

frontend/package-lock.json

Lines changed: 1469 additions & 1115 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
"@radix-ui/react-slot": "^1.2.3",
1818
"@radix-ui/react-toast": "^1.2.15",
1919
"@radix-ui/react-tooltip": "^1.2.8",
20+
"@tanstack/react-query": "^5.90.7",
2021
"@tailwindcss/vite": "^4.1.14",
21-
"@tanstack/react-query": "^5.90.3",
2222
"axios": "^1.13.2",
2323
"class-variance-authority": "^0.7.1",
2424
"clsx": "^2.1.1",
@@ -29,20 +29,21 @@
2929
"react-dom": "^19.2.0",
3030
"react-hook-form": "^7.65.0",
3131
"react-hotkeys": "^2.0.0",
32-
"react-router-dom": "^7.9.4",
32+
"react-router-dom": "^7.9.5",
3333
"shadcn": "^3.4.1",
3434
"socket.io-client": "^4.8.1",
3535
"sonner": "^2.0.7",
36-
"tailwind-merge": "^3.3.1"
36+
"tailwind-merge": "^3.4.0"
3737
},
3838
"devDependencies": {
39-
"@tailwindcss/postcss": "^4.1.14",
39+
"@tailwindcss/postcss": "^4.1.17",
40+
"@tailwindcss/vite": "^4.1.17",
4041
"@types/node": "^24.7.2",
4142
"@vitejs/plugin-react-swc": "^4.1.0",
4243
"autoprefixer": "^10.4.21",
4344
"postcss": "^8.5.6",
4445
"rollup": "^4.52.5",
45-
"tailwindcss": "^4.1.14",
46-
"vite": "^7.1.11"
46+
"tailwindcss": "^4.1.17",
47+
"vite": "^7.2.2"
4748
}
4849
}

frontend/postcss.config.cjs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
module.exports = {
2-
plugins: [
3-
require('@tailwindcss/postcss'),
4-
require('autoprefixer')
5-
]
1+
import tailwindcss from "@tailwindcss/postcss";
2+
import autoprefixer from "autoprefixer";
3+
4+
export default {
5+
plugins: [tailwindcss(), autoprefixer()],
66
};

frontend/src/App.tsx

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,40 @@ import JoinRoom from "./pages/JoinRoom.js";
1414
import InRoom from "./pages/InRoom.js";
1515
import CreateRoomLobby from "./pages/CreateRoomLobby.js";
1616
import CreateRoom from "./pages/CreateRoom.js";
17+
import { ThemeProvider } from "next-themes";
1718
import ActiveSessions from "./pages/ActiveSessions.js";
1819
import InRoomWrapper from "./pages/InRoomWrapper.js";
1920
const queryClient = new QueryClient();
2021

2122
const App = () => (
2223
<ErrorBoundary>
2324
<QueryClientProvider client={queryClient}>
24-
<TooltipProvider>
25-
<Toaster />
26-
<Sonner />
27-
<BrowserRouter>
28-
<Routes>
29-
<Route path="/" element={<Index />} />
30-
<Route path="/signup" element={<SignUp />} />
31-
<Route path="/signin" element={<SignIn />} />
32-
<Route path="/room-actions" element={<RoomActions />} />
33-
<Route path="/oauth-success" element={<OAuthSuccess />} />
34-
<Route path="/create-room" element={<CreateRoom />} /> {/* ✅ */}
35-
<Route path="/join-room" element={<JoinRoom />} /> {/* ✅ */}
36-
<Route path="/room/:roomName" element={<InRoomWrapper />} />
37-
<Route path="/lobby/:roomId" element={<CreateRoomLobby />} />
38-
<Route path="/sessions" element={<ActiveSessions />} />
39-
</Routes>
40-
</BrowserRouter>
41-
</TooltipProvider>
25+
<ThemeProvider
26+
attribute="class"
27+
defaultTheme="light"
28+
enableSystem={false}
29+
storageKey="peercall-theme"
30+
disableTransitionOnChange={false}
31+
>
32+
<TooltipProvider>
33+
<Toaster />
34+
<Sonner />
35+
<BrowserRouter>
36+
<Routes>
37+
<Route path="/" element={<Index />} />
38+
<Route path="/signup" element={<SignUp />} />
39+
<Route path="/signin" element={<SignIn />} />
40+
<Route path="/room-actions" element={<RoomActions />} />
41+
<Route path="/oauth-success" element={<OAuthSuccess />} />
42+
<Route path="/create-room" element={<CreateRoom />} /> {/* ✅ */}
43+
<Route path="/join-room" element={<JoinRoom />} /> {/* ✅ */}
44+
<Route path="/room/:roomName" element={<InRoomWrapper />} />
45+
<Route path="/lobby/:roomId" element={<CreateRoomLobby />} />
46+
<Route path="/sessions" element={<ActiveSessions />} />
47+
</Routes>
48+
</BrowserRouter>
49+
</TooltipProvider>
50+
</ThemeProvider>
4251
</QueryClientProvider>
4352
</ErrorBoundary>
4453
);

frontend/src/components/ChatOverlay.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,49 +60,49 @@ const ChatOverlay: React.FC<ChatOverlayProps> = ({
6060
<>
6161
{!open && (
6262
<button
63-
className="fixed bottom-6 right-6 bg-green-600 text-white rounded-full w-14 h-14 flex items-center justify-center shadow-lg hover:bg-green-700 transition-all z-50"
63+
className="fixed bottom-6 right-6 bg-green-600 dark:bg-green-500 text-white rounded-full w-14 h-14 flex items-center justify-center shadow-lg hover:bg-green-700 dark:hover:bg-green-600 transition-all z-50"
6464
onClick={() => setOpen(true)}
6565
aria-label="Open chat"
6666
>
6767
💬
6868
{unreadCount > 0 && (
69-
<span className="absolute -top-2 -right-2 bg-red-500 text-white text-xs rounded-full w-6 h-6 flex items-center justify-center">
69+
<span className="absolute -top-2 -right-2 bg-red-500 dark:bg-red-600 text-white text-xs rounded-full w-6 h-6 flex items-center justify-center">
7070
{unreadCount > 9 ? "9+" : unreadCount}
7171
</span>
7272
)}
7373
</button>
7474
)}
7575
{open && (
76-
<div className="fixed bottom-6 right-6 w-80 max-w-[90vw] bg-white shadow-2xl rounded-xl flex flex-col z-50 animate-fade-in-up">
77-
<div className="flex items-center justify-between p-4 border-b">
78-
<span className="font-semibold">In-Call Chat - {roomId}</span>
79-
<button onClick={() => setOpen(false)} className="text-gray-500 hover:text-red-600">
76+
<div className="fixed bottom-6 right-6 w-80 max-w-[90vw] bg-white dark:bg-gray-900 shadow-2xl rounded-xl flex flex-col z-50 animate-fade-in-up border border-gray-200 dark:border-gray-800">
77+
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-800">
78+
<span className="font-semibold text-gray-900 dark:text-gray-100">In-Call Chat - {roomId}</span>
79+
<button onClick={() => setOpen(false)} className="text-gray-500 dark:text-gray-400 hover:text-red-600 dark:hover:text-red-500">
8080
×
8181
</button>
8282
</div>
83-
<div className="flex-1 overflow-y-auto p-4 space-y-2 h-72 bg-gray-50">
83+
<div className="flex-1 overflow-y-auto p-4 space-y-2 h-72 bg-gray-50 dark:bg-gray-950">
8484
{messages.map((msg, idx) => (
8585
<div key={idx} className="flex flex-col">
8686
<div className="flex items-center gap-2">
87-
<span className="text-xs text-green-700 font-bold">{msg.user}</span>
88-
<span className="text-xs text-gray-500">
87+
<span className="text-xs text-green-700 dark:text-green-400 font-bold">{msg.user}</span>
88+
<span className="text-xs text-gray-500 dark:text-gray-400">
8989
{msg.time ? new Date(msg.time).toLocaleTimeString() : ""}
9090
</span>
9191
</div>
92-
<span className="bg-green-100 text-gray-900 rounded px-2 py-1 text-sm w-fit max-w-[85%]">{msg.text}</span>
92+
<span className="bg-green-100 dark:bg-green-900/30 text-gray-900 dark:text-gray-100 rounded px-2 py-1 text-sm w-fit max-w-[85%]">{msg.text}</span>
9393
</div>
9494
))}
9595
<div ref={chatEndRef} />
9696
</div>
97-
<form className="flex items-center gap-2 p-3 border-t" onSubmit={sendMessage}>
97+
<form className="flex items-center gap-2 p-3 border-t border-gray-200 dark:border-gray-800" onSubmit={sendMessage}>
9898
<input
9999
type="text"
100100
value={input}
101101
onChange={(e) => setInput(e.target.value)}
102102
placeholder="Type a message..."
103-
className="flex-1 rounded border px-2 py-1 text-sm focus:outline-none focus:ring focus:ring-green-400"
103+
className="flex-1 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 px-2 py-1 text-sm focus:outline-none focus:ring focus:ring-green-400 dark:focus:ring-green-500"
104104
/>
105-
<button type="submit" className="bg-green-600 hover:bg-green-700 text-white px-4 py-1 rounded">
105+
<button type="submit" className="bg-green-600 dark:bg-green-500 hover:bg-green-700 dark:hover:bg-green-600 text-white px-4 py-1 rounded">
106106
Send
107107
</button>
108108
</form>

frontend/src/components/Features.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,16 @@ const features = [
3636

3737
const Features = () => {
3838
return (
39-
<section id="features" className="py-24 bg-gray-50">
39+
<section id="features" className="py-24 bg-gray-50 dark:bg-gray-950 transition-colors">
4040
<div className="container mx-auto px-6">
4141
<div className="text-center mb-16 animate-fade-in-up">
42-
<h2 className="text-4xl md:text-5xl font-bold mb-4">
42+
<h2 className="text-4xl md:text-5xl font-bold mb-4 text-gray-900 dark:text-gray-100">
4343
Powerful{" "}
44-
<span className="text-green-600">
44+
<span className="text-green-600 dark:text-green-500">
4545
Features
4646
</span>
4747
</h2>
48-
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
48+
<p className="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
4949
Everything you need for secure, private video communication
5050
</p>
5151
</div>
@@ -54,16 +54,16 @@ const Features = () => {
5454
{features.map((feature, index) => (
5555
<Card
5656
key={index}
57-
className="p-8 bg-white border border-gray-200 rounded-lg hover:shadow-lg transition-all duration-300 hover:-translate-y-2 group animate-fade-in-up"
57+
className="p-8 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-lg hover:shadow-lg transition-all duration-300 hover:-translate-y-2 group animate-fade-in-up"
5858
style={{ animationDelay: `${index * 0.1}s` }}
5959
>
60-
<div className="mb-4 inline-block p-3 bg-green-100 rounded-lg group-hover:scale-110 transition-transform">
61-
<feature.icon className="w-8 h-8 text-green-600" />
60+
<div className="mb-4 inline-block p-3 bg-green-100 dark:bg-green-900/30 rounded-lg group-hover:scale-110 transition-transform">
61+
<feature.icon className="w-8 h-8 text-green-600 dark:text-green-500" />
6262
</div>
63-
<h3 className="text-xl font-semibold mb-3 text-gray-900">
63+
<h3 className="text-xl font-semibold mb-3 text-gray-900 dark:text-gray-100">
6464
{feature.title}
6565
</h3>
66-
<p className="text-gray-600 leading-relaxed">
66+
<p className="text-gray-600 dark:text-gray-400 leading-relaxed">
6767
{feature.description}
6868
</p>
6969
</Card>

frontend/src/components/Footer.tsx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ const Footer = () => {
44
const currentYear = new Date().getFullYear();
55

66
return (
7-
<footer id="join" className="bg-gray-50 border-t border-gray-200">
7+
<footer id="join" className="bg-gray-50 dark:bg-gray-950 border-t border-gray-200 dark:border-gray-800 transition-colors">
88
<div className="container mx-auto px-6 py-12">
99
<div className="grid grid-cols-1 md:grid-cols-3 gap-12 mb-8">
1010
{/* Brand */}
1111
<div className="space-y-4">
12-
<h3 className="text-2xl font-bold text-green-600">
12+
<h3 className="text-2xl font-bold text-green-600 dark:text-green-500">
1313
PeerCall
1414
</h3>
15-
<p className="text-gray-600">
15+
<p className="text-gray-600 dark:text-gray-400">
1616
Secure, privacy-respecting real-time video calls built with modern web technologies.
1717
</p>
1818
<div className="flex gap-4">
@@ -21,7 +21,7 @@ const Footer = () => {
2121
target="_blank"
2222
rel="noopener noreferrer"
2323
aria-label="Twitter"
24-
className="text-gray-600 hover:text-green-600 transition-colors"
24+
className="text-gray-600 dark:text-gray-400 hover:text-green-600 dark:hover:text-green-500 transition-colors"
2525
>
2626
<Twitter size={20} />
2727
</a>
@@ -30,7 +30,7 @@ const Footer = () => {
3030
target="_blank"
3131
rel="noopener noreferrer"
3232
aria-label="GitHub"
33-
className="text-gray-600 hover:text-green-600 transition-colors"
33+
className="text-gray-600 dark:text-gray-400 hover:text-green-600 dark:hover:text-green-500 transition-colors"
3434
>
3535
<Github size={20} />
3636
</a>
@@ -39,7 +39,7 @@ const Footer = () => {
3939
target="_blank"
4040
rel="noopener noreferrer"
4141
aria-label="LinkedIn"
42-
className="text-gray-600 hover:text-green-600 transition-colors"
42+
className="text-gray-600 dark:text-gray-400 hover:text-green-600 dark:hover:text-green-500 transition-colors"
4343
>
4444
<Linkedin size={20} />
4545
</a>
@@ -48,14 +48,14 @@ const Footer = () => {
4848

4949
{/* Quick Links */}
5050
<div>
51-
<h4 className="font-semibold mb-4 text-green-600">Resources</h4>
51+
<h4 className="font-semibold mb-4 text-green-600 dark:text-green-500">Resources</h4>
5252
<ul className="space-y-3">
5353
<li>
5454
<a
5555
href="https://github.com/OPCODE-Open-Spring-Fest/PeerCall"
5656
target="_blank"
5757
rel="noopener noreferrer"
58-
className="flex items-center gap-2 text-gray-600 hover:text-green-600 transition-colors"
58+
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-green-600 dark:hover:text-green-500 transition-colors"
5959
>
6060
<Github size={16} />
6161
GitHub Repository
@@ -66,7 +66,7 @@ const Footer = () => {
6666
href="https://github.com/OPCODE-Open-Spring-Fest/PeerCall/blob/main/.github/Contributor_Guide/Contributing.md"
6767
target="_blank"
6868
rel="noopener noreferrer"
69-
className="flex items-center gap-2 text-gray-600 hover:text-green-600 transition-colors"
69+
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-green-600 dark:hover:text-green-500 transition-colors"
7070
>
7171
<Heart size={16} />
7272
Contribution Guide
@@ -77,7 +77,7 @@ const Footer = () => {
7777
href="https://github.com/OPCODE-Open-Spring-Fest/PeerCall/tree/main/.github/Contributor_Guide"
7878
target="_blank"
7979
rel="noopener noreferrer"
80-
className="flex items-center gap-2 text-gray-600 hover:text-green-600 transition-colors"
80+
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-green-600 dark:hover:text-green-500 transition-colors"
8181
>
8282
<FileText size={16} />
8383
MIT License
@@ -88,21 +88,21 @@ const Footer = () => {
8888

8989
{/* CTA */}
9090
<div>
91-
<h4 className="font-semibold mb-4 text-green-600">Get Started</h4>
92-
<p className="text-gray-600 mb-4">
91+
<h4 className="font-semibold mb-4 text-green-600 dark:text-green-500">Get Started</h4>
92+
<p className="text-gray-600 dark:text-gray-400 mb-4">
9393
Ready to experience secure video calling?
9494
</p>
9595
<a
9696
href="#"
97-
className="inline-block bg-green-600 text-white px-4 py-2 rounded-lg font-medium hover:opacity-90 transition-opacity shadow-lg"
97+
className="inline-block bg-green-600 dark:bg-green-500 text-white px-4 py-2 rounded-lg font-medium hover:opacity-90 transition-opacity shadow-lg"
9898
>
9999
Create Account
100100
</a>
101101
</div>
102102
</div>
103103

104104
{/* Bottom Bar */}
105-
<div className="pt-8 border-t border-gray-200 text-center text-sm text-gray-500">
105+
<div className="pt-8 border-t border-gray-200 dark:border-gray-800 text-center text-sm text-gray-500 dark:text-gray-400">
106106
<p>
107107
© {currentYear} PeerCall.
108108
</p>

0 commit comments

Comments
 (0)