From 1f8a3ff6fff3f64e8912ae6350849732959c4a30 Mon Sep 17 00:00:00 2001 From: vaswzerdali Date: Sat, 6 Dec 2025 01:15:29 +0200 Subject: [PATCH 1/3] feat: add dark mode and extra feature --- src/App.css | 72 ++++++++ src/components/Create.jsx | 20 +++ src/components/Create.module.css | 26 +++ src/components/Footer.module.css | 24 +-- src/components/Header.jsx | 24 ++- src/components/Header.module.css | 164 ++++++++++++++++-- src/components/Home.module.css | 4 +- .../RoomsSlider/RoomCard.module.css | 48 +++-- src/components/RoomsSlider/RoomsSlider.css | 2 +- src/context/DarkModeProvider.jsx | 36 ++++ src/main.jsx | 7 +- src/pages/GoogleLogin.module.css | 67 ++++--- 12 files changed, 420 insertions(+), 74 deletions(-) create mode 100644 src/context/DarkModeProvider.jsx diff --git a/src/App.css b/src/App.css index d840331..8cd6767 100644 --- a/src/App.css +++ b/src/App.css @@ -61,6 +61,78 @@ html, min-height: 0; } +/* ===== DARK MODE VARIABLES ===== */ + +/* Light Mode (Default) */ +:root { + --bg-primary: #ffffff; + --bg-secondary: #f8f9fa; + --bg-tertiary: #e9ecef; + --text-primary1: #2c3e50; + --text-secondary: #6c757d; + --text-tertiary: #adb5bd; + --border-color: #dee2e6; + --shadow: rgba(0, 0, 0, 0.1); + --shadow-lg: rgba(0, 0, 0, 0.15); + --accent-color: #007bff; + --accent-hover: #0056b3; + --success-color: #28a745; + --danger-color: #dc3545; + --warning-color: #ffc107; +} + +/* Dark Mode */ +[data-theme="dark"] { + --bg-primary: #1a1a1a; + --bg-secondary: #242424; + --bg-tertiary: #2d2d2d; + --text-primary1: #ffffff; + --text-secondary: #b0b0b0; + --text-tertiary: #808080; + --border-color: #404040; + --border-color2:#1a1a1a; + --shadow: rgba(0, 0, 0, 0.5); + --shadow-lg: rgba(0, 0, 0, 0.7); + --accent-color: #4da3ff; + --accent-hover: #66b3ff; + --success-color: #4caf50; + --danger-color: #f44336; + --warning-color: #ffb300; +} + +/* Apply to body */ +body { + background-color: var(--bg-primary); + color: var(--text-primary1); + transition: background-color 0.3s ease, color 0.3s ease; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* Common elements */ +input, textarea, select { + background-color: var(--bg-secondary); + color: var(--text-primary); + border: 1px solid var(--border-color); + transition: all 0.3s ease; +} + +button { + transition: all 0.3s ease; +} + +a { + + transition: color 0.3s ease; + text-decoration: none; +} + + + /* Tablet styles (max-width: 1024px) */ @media (max-width: 1024px) { .app-content { diff --git a/src/components/Create.jsx b/src/components/Create.jsx index 6f72118..f512cc8 100644 --- a/src/components/Create.jsx +++ b/src/components/Create.jsx @@ -66,6 +66,16 @@ const CreateRoom = () => { } }; + // --- HANDLE IMAGE REMOVAL --- + const handleRemoveImage = (e) => { + e.stopPropagation(); // Prevent triggering the upload click + setSelectedFile(null); + setImagePreview(null); + if (fileInputRef.current) { + fileInputRef.current.value = ''; // Reset file input + } + }; + const handleFreeJoin = async (roomId) => { try { const res = await api.post(`/api/rooms/${roomId}/join`); @@ -176,7 +186,17 @@ const CreateRoom = () => { onClick={() => fileInputRef.current.click()} > {imagePreview ? ( + <> Room Preview + + ) : (
diff --git a/src/components/Create.module.css b/src/components/Create.module.css index 012bdf7..fbe42d7 100644 --- a/src/components/Create.module.css +++ b/src/components/Create.module.css @@ -72,6 +72,32 @@ box-shadow: 0 4px 12px rgba(255, 161, 22, 0.15); } +.removeImageBtn { + position: absolute; + top: 8px; + right: 8px; + width: 24px; + height: 24px; + border-radius: 50%; + background-color: rgba(0, 0, 0, 0.5); + color: white; + border: none; + font-size: 14px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + z-index: 10; + opacity: 0.7; +} + +.removeImageBtn:hover { + background-color: rgba(0, 0, 0, 0.8); + opacity: 1; + transform: scale(1.05); +} + .placeholder { display: flex; flex-direction: column; diff --git a/src/components/Footer.module.css b/src/components/Footer.module.css index e4f7950..f2348b1 100644 --- a/src/components/Footer.module.css +++ b/src/components/Footer.module.css @@ -9,19 +9,21 @@ padding: 18px 40px 14px; font-family: Inter, sans-serif; width: 100%; - background: #ffffff; + background: var(--bg-primary); z-index: 100; box-sizing: border-box; gap: 6px; + transition: background-color 0.3s ease; } /* Divider Line */ .line { width: 100%; height: 1px; - background-color: #d8d8d8; + background-color: var(--border-color); margin-bottom: 8px; border-radius: 2px; + transition: background-color 0.3s ease; } /* Legal Links Row */ @@ -34,33 +36,35 @@ margin-bottom: 4px; } -/* Single Link */ +/* Single Link - Force all states */ .link { font-size: 14px; - color: #0a1427; + color: var(--text-primary1); text-decoration: none; opacity: 0.85; - transition: 0.2s; + transition: all 0.3s ease; } .link:hover { opacity: 1; - color: #ffa116; /* subtle highlight */ + color: var(--accent) !important; } /* Dots between links */ .dot { - color: #bbbbbb; + color: var(--text-tertiary); font-size: 12px; margin: 0 4px; + transition: color 0.3s ease; } /* Copyright */ .text { margin: 0; font-size: 13px; - color: #020a1a; + color: var(--text-primary1); opacity: 0.75; + transition: color 0.3s ease; } /* Tablet (≤1024px) */ @@ -111,11 +115,11 @@ gap: 6px; } - .link { + .link{ font-size: 11px; } .text { font-size: 11px; } -} +} \ No newline at end of file diff --git a/src/components/Header.jsx b/src/components/Header.jsx index 4079071..b5aa9a6 100644 --- a/src/components/Header.jsx +++ b/src/components/Header.jsx @@ -3,12 +3,15 @@ import { NavLink, useNavigate } from "react-router-dom"; import { getToken } from "../auth/tokenStore"; import { logout } from "../auth/logout"; import styles from "./Header.module.css"; +import { useDarkMode } from "../context/DarkModeProvider"; + export default function Header() { const navigate = useNavigate(); const [loggedIn, setLoggedIn] = useState(!!getToken()); const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const mobileMenuRef = useRef(null); + const { isDarkMode, toggleDarkMode } = useDarkMode(); useEffect(() => { const interval = setInterval(() => { @@ -53,13 +56,24 @@ export default function Header() { rel="noopener noreferrer" className={styles.githubButton} > - GitHub + + + + {/* Dark Mode Toggle Button */} + + {/* Desktop Navigation */}