Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
19 changes: 16 additions & 3 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
<!doctype html>
<html lang="en">
<html lang="en" suppressHydrationWarning>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PeerCall - Secure Privacy-Respecting Video Calls</title>
<script>
// Prevent flash of unstyled content - sync with next-themes
(function() {
try {
const theme = localStorage.getItem('peercall-theme');
if (theme === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
} catch (e) {
// Ignore errors
}
})();
</script>
<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." />
<meta name="author" content="PeerCall" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link href="./src/index.css" rel="stylesheet">
<!-- favicon (use the existing vite.svg as the icon) -->
<link rel="icon" type="image/svg+xml" href="/vite.svg">
<meta property="og:title" content="PeerCall - Secure Privacy-Respecting Video Calls" />
Expand All @@ -20,6 +34,5 @@
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<script src="https://cdn.tailwindcss.com"></script>
</body>
</html>
2,584 changes: 1,469 additions & 1,115 deletions frontend/package-lock.json

Large diffs are not rendered by default.

13 changes: 7 additions & 6 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-toast": "^1.2.15",
"@radix-ui/react-tooltip": "^1.2.8",
"@tanstack/react-query": "^5.90.7",
"@tailwindcss/vite": "^4.1.14",
"@tanstack/react-query": "^5.90.3",
"axios": "^1.13.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
Expand All @@ -29,20 +29,21 @@
"react-dom": "^19.2.0",
"react-hook-form": "^7.65.0",
"react-hotkeys": "^2.0.0",
"react-router-dom": "^7.9.4",
"react-router-dom": "^7.9.5",
"shadcn": "^3.4.1",
"socket.io-client": "^4.8.1",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1"
"tailwind-merge": "^3.4.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.14",
"@tailwindcss/postcss": "^4.1.17",
"@tailwindcss/vite": "^4.1.17",
"@types/node": "^24.7.2",
"@vitejs/plugin-react-swc": "^4.1.0",
"autoprefixer": "^10.4.21",
"postcss": "^8.5.6",
"rollup": "^4.52.5",
"tailwindcss": "^4.1.14",
"vite": "^7.1.11"
"tailwindcss": "^4.1.17",
"vite": "^7.2.2"
}
}
10 changes: 5 additions & 5 deletions frontend/postcss.config.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
plugins: [
require('@tailwindcss/postcss'),
require('autoprefixer')
]
import tailwindcss from "@tailwindcss/postcss";
import autoprefixer from "autoprefixer";

export default {
plugins: [tailwindcss(), autoprefixer()],
};
45 changes: 27 additions & 18 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,40 @@ import JoinRoom from "./pages/JoinRoom.js";
import InRoom from "./pages/InRoom.js";
import CreateRoomLobby from "./pages/CreateRoomLobby.js";
import CreateRoom from "./pages/CreateRoom.js";
import { ThemeProvider } from "next-themes";
import ActiveSessions from "./pages/ActiveSessions.js";
import InRoomWrapper from "./pages/InRoomWrapper.js";
const queryClient = new QueryClient();

const App = () => (
<ErrorBoundary>
<QueryClientProvider client={queryClient}>
<TooltipProvider>
<Toaster />
<Sonner />
<BrowserRouter>
<Routes>
<Route path="/" element={<Index />} />
<Route path="/signup" element={<SignUp />} />
<Route path="/signin" element={<SignIn />} />
<Route path="/room-actions" element={<RoomActions />} />
<Route path="/oauth-success" element={<OAuthSuccess />} />
<Route path="/create-room" element={<CreateRoom />} /> {/* ✅ */}
<Route path="/join-room" element={<JoinRoom />} /> {/* ✅ */}
<Route path="/room/:roomName" element={<InRoomWrapper />} />
<Route path="/lobby/:roomId" element={<CreateRoomLobby />} />
<Route path="/sessions" element={<ActiveSessions />} />
</Routes>
</BrowserRouter>
</TooltipProvider>
<ThemeProvider
attribute="class"
defaultTheme="light"
enableSystem={false}
storageKey="peercall-theme"
disableTransitionOnChange={false}
>
<TooltipProvider>
<Toaster />
<Sonner />
<BrowserRouter>
<Routes>
<Route path="/" element={<Index />} />
<Route path="/signup" element={<SignUp />} />
<Route path="/signin" element={<SignIn />} />
<Route path="/room-actions" element={<RoomActions />} />
<Route path="/oauth-success" element={<OAuthSuccess />} />
<Route path="/create-room" element={<CreateRoom />} /> {/* ✅ */}
<Route path="/join-room" element={<JoinRoom />} /> {/* ✅ */}
<Route path="/room/:roomName" element={<InRoomWrapper />} />
<Route path="/lobby/:roomId" element={<CreateRoomLobby />} />
<Route path="/sessions" element={<ActiveSessions />} />
</Routes>
</BrowserRouter>
</TooltipProvider>
</ThemeProvider>
</QueryClientProvider>
</ErrorBoundary>
);
Expand Down
26 changes: 13 additions & 13 deletions frontend/src/components/ChatOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,49 +60,49 @@ const ChatOverlay: React.FC<ChatOverlayProps> = ({
<>
{!open && (
<button
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"
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"
onClick={() => setOpen(true)}
aria-label="Open chat"
>
💬
{unreadCount > 0 && (
<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">
<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">
{unreadCount > 9 ? "9+" : unreadCount}
</span>
)}
</button>
)}
{open && (
<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">
<div className="flex items-center justify-between p-4 border-b">
<span className="font-semibold">In-Call Chat - {roomId}</span>
<button onClick={() => setOpen(false)} className="text-gray-500 hover:text-red-600">
<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">
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-800">
<span className="font-semibold text-gray-900 dark:text-gray-100">In-Call Chat - {roomId}</span>
<button onClick={() => setOpen(false)} className="text-gray-500 dark:text-gray-400 hover:text-red-600 dark:hover:text-red-500">
×
</button>
</div>
<div className="flex-1 overflow-y-auto p-4 space-y-2 h-72 bg-gray-50">
<div className="flex-1 overflow-y-auto p-4 space-y-2 h-72 bg-gray-50 dark:bg-gray-950">
{messages.map((msg, idx) => (
<div key={idx} className="flex flex-col">
<div className="flex items-center gap-2">
<span className="text-xs text-green-700 font-bold">{msg.user}</span>
<span className="text-xs text-gray-500">
<span className="text-xs text-green-700 dark:text-green-400 font-bold">{msg.user}</span>
<span className="text-xs text-gray-500 dark:text-gray-400">
{msg.time ? new Date(msg.time).toLocaleTimeString() : ""}
</span>
</div>
<span className="bg-green-100 text-gray-900 rounded px-2 py-1 text-sm w-fit max-w-[85%]">{msg.text}</span>
<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>
</div>
))}
<div ref={chatEndRef} />
</div>
<form className="flex items-center gap-2 p-3 border-t" onSubmit={sendMessage}>
<form className="flex items-center gap-2 p-3 border-t border-gray-200 dark:border-gray-800" onSubmit={sendMessage}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Type a message..."
className="flex-1 rounded border px-2 py-1 text-sm focus:outline-none focus:ring focus:ring-green-400"
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"
/>
<button type="submit" className="bg-green-600 hover:bg-green-700 text-white px-4 py-1 rounded">
<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">
Send
</button>
</form>
Expand Down
18 changes: 9 additions & 9 deletions frontend/src/components/Features.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ const features = [

const Features = () => {
return (
<section id="features" className="py-24 bg-gray-50">
<section id="features" className="py-24 bg-gray-50 dark:bg-gray-950 transition-colors">
<div className="container mx-auto px-6">
<div className="text-center mb-16 animate-fade-in-up">
<h2 className="text-4xl md:text-5xl font-bold mb-4">
<h2 className="text-4xl md:text-5xl font-bold mb-4 text-gray-900 dark:text-gray-100">
Powerful{" "}
<span className="text-green-600">
<span className="text-green-600 dark:text-green-500">
Features
</span>
</h2>
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
<p className="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
Everything you need for secure, private video communication
</p>
</div>
Expand All @@ -54,16 +54,16 @@ const Features = () => {
{features.map((feature, index) => (
<Card
key={index}
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"
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"
style={{ animationDelay: `${index * 0.1}s` }}
>
<div className="mb-4 inline-block p-3 bg-green-100 rounded-lg group-hover:scale-110 transition-transform">
<feature.icon className="w-8 h-8 text-green-600" />
<div className="mb-4 inline-block p-3 bg-green-100 dark:bg-green-900/30 rounded-lg group-hover:scale-110 transition-transform">
<feature.icon className="w-8 h-8 text-green-600 dark:text-green-500" />
</div>
<h3 className="text-xl font-semibold mb-3 text-gray-900">
<h3 className="text-xl font-semibold mb-3 text-gray-900 dark:text-gray-100">
{feature.title}
</h3>
<p className="text-gray-600 leading-relaxed">
<p className="text-gray-600 dark:text-gray-400 leading-relaxed">
{feature.description}
</p>
</Card>
Expand Down
28 changes: 14 additions & 14 deletions frontend/src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ const Footer = () => {
const currentYear = new Date().getFullYear();

return (
<footer id="join" className="bg-gray-50 border-t border-gray-200">
<footer id="join" className="bg-gray-50 dark:bg-gray-950 border-t border-gray-200 dark:border-gray-800 transition-colors">
<div className="container mx-auto px-6 py-12">
<div className="grid grid-cols-1 md:grid-cols-3 gap-12 mb-8">
{/* Brand */}
<div className="space-y-4">
<h3 className="text-2xl font-bold text-green-600">
<h3 className="text-2xl font-bold text-green-600 dark:text-green-500">
PeerCall
</h3>
<p className="text-gray-600">
<p className="text-gray-600 dark:text-gray-400">
Secure, privacy-respecting real-time video calls built with modern web technologies.
</p>
<div className="flex gap-4">
Expand All @@ -21,7 +21,7 @@ const Footer = () => {
target="_blank"
rel="noopener noreferrer"
aria-label="Twitter"
className="text-gray-600 hover:text-green-600 transition-colors"
className="text-gray-600 dark:text-gray-400 hover:text-green-600 dark:hover:text-green-500 transition-colors"
>
<Twitter size={20} />
</a>
Expand All @@ -30,7 +30,7 @@ const Footer = () => {
target="_blank"
rel="noopener noreferrer"
aria-label="GitHub"
className="text-gray-600 hover:text-green-600 transition-colors"
className="text-gray-600 dark:text-gray-400 hover:text-green-600 dark:hover:text-green-500 transition-colors"
>
<Github size={20} />
</a>
Expand All @@ -39,7 +39,7 @@ const Footer = () => {
target="_blank"
rel="noopener noreferrer"
aria-label="LinkedIn"
className="text-gray-600 hover:text-green-600 transition-colors"
className="text-gray-600 dark:text-gray-400 hover:text-green-600 dark:hover:text-green-500 transition-colors"
>
<Linkedin size={20} />
</a>
Expand All @@ -48,14 +48,14 @@ const Footer = () => {

{/* Quick Links */}
<div>
<h4 className="font-semibold mb-4 text-green-600">Resources</h4>
<h4 className="font-semibold mb-4 text-green-600 dark:text-green-500">Resources</h4>
<ul className="space-y-3">
<li>
<a
href="https://github.com/OPCODE-Open-Spring-Fest/PeerCall"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 text-gray-600 hover:text-green-600 transition-colors"
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-green-600 dark:hover:text-green-500 transition-colors"
>
<Github size={16} />
GitHub Repository
Expand All @@ -66,7 +66,7 @@ const Footer = () => {
href="https://github.com/OPCODE-Open-Spring-Fest/PeerCall/blob/main/.github/Contributor_Guide/Contributing.md"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 text-gray-600 hover:text-green-600 transition-colors"
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-green-600 dark:hover:text-green-500 transition-colors"
>
<Heart size={16} />
Contribution Guide
Expand All @@ -77,7 +77,7 @@ const Footer = () => {
href="https://github.com/OPCODE-Open-Spring-Fest/PeerCall/tree/main/.github/Contributor_Guide"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 text-gray-600 hover:text-green-600 transition-colors"
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-green-600 dark:hover:text-green-500 transition-colors"
>
<FileText size={16} />
MIT License
Expand All @@ -88,21 +88,21 @@ const Footer = () => {

{/* CTA */}
<div>
<h4 className="font-semibold mb-4 text-green-600">Get Started</h4>
<p className="text-gray-600 mb-4">
<h4 className="font-semibold mb-4 text-green-600 dark:text-green-500">Get Started</h4>
<p className="text-gray-600 dark:text-gray-400 mb-4">
Ready to experience secure video calling?
</p>
<a
href="#"
className="inline-block bg-green-600 text-white px-4 py-2 rounded-lg font-medium hover:opacity-90 transition-opacity shadow-lg"
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"
>
Create Account
</a>
</div>
</div>

{/* Bottom Bar */}
<div className="pt-8 border-t border-gray-200 text-center text-sm text-gray-500">
<div className="pt-8 border-t border-gray-200 dark:border-gray-800 text-center text-sm text-gray-500 dark:text-gray-400">
<p>
© {currentYear} PeerCall.
</p>
Expand Down
Loading
Loading