From 4803d0dce78c8a10be46bc139112c6fd009d0e62 Mon Sep 17 00:00:00 2001 From: anshiky73-svg Date: Fri, 23 Jan 2026 17:30:48 +0530 Subject: [PATCH] feat: add dark/light mode toggle button --- expensetracker.css | 61 ++++++++++++++++++++++++++++- index.html | 55 +++++++++++++++++++++++++- theme.js | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 209 insertions(+), 3 deletions(-) create mode 100644 theme.js diff --git a/expensetracker.css b/expensetracker.css index 9672b531..3a6a3946 100644 --- a/expensetracker.css +++ b/expensetracker.css @@ -30,6 +30,39 @@ --shadow-card: 0 8px 16px rgba(0, 0, 0, 0.3); } +/* Light Mode Theme */ +[data-theme="light"] { + /* Color Palette */ + --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); + --success-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); + --warning-gradient: linear-gradient(135deg, #fa709a 0%, #fee140 100%); + --dark-gradient: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%); + + /* Background Colors */ + --bg-primary: #ffffff; + --bg-secondary: #f5f5f5; + --bg-tertiary: #efefef; + --bg-glass: rgba(0, 0, 0, 0.05); + + /* Text Colors */ + --text-primary: #1a1a1a; + --text-secondary: #666666; + --text-accent: #667eea; + + /* Accent Colors */ + --accent-primary: #667eea; + --accent-secondary: #764ba2; + --success: #00c853; + --error: #d32f2f; + --warning: #ffa000; + + /* Shadows */ + --shadow-glass: 0 8px 32px 0 rgba(0, 0, 0, 0.1); + --shadow-hover: 0 15px 35px rgba(0, 0, 0, 0.15); + --shadow-card: 0 8px 16px rgba(0, 0, 0, 0.1); +} + * { margin: 0; padding: 0; @@ -134,6 +167,32 @@ body { gap: 0.75rem; } +.theme-toggle-btn { + background: rgba(255, 255, 255, 0.1); + border: 1px solid rgba(100, 255, 218, 0.3); + color: var(--accent-primary); + width: 40px; + height: 40px; + border-radius: 50%; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.2rem; + transition: all 0.3s ease; + margin-right: 1rem; +} + +.theme-toggle-btn:hover { + background: rgba(100, 255, 218, 0.2); + border-color: var(--accent-primary); + transform: scale(1.1); +} + +.theme-toggle-btn.light-mode { + color: #ffd700; +} + .profile-img { width: 40px; height: 40px; @@ -1539,4 +1598,4 @@ body { #scrollToTopBtn svg { display: block; -} +} \ No newline at end of file diff --git a/index.html b/index.html index 7d8831ce..d121167a 100644 --- a/index.html +++ b/index.html @@ -60,6 +60,39 @@ --shadow-card: 0 8px 16px rgba(0, 0, 0, 0.3); } + /* Light Mode Theme */ + [data-theme="light"] { + /* Color Palette */ + --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); + --success-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); + --warning-gradient: linear-gradient(135deg, #fa709a 0%, #fee140 100%); + --dark-gradient: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%); + + /* Background Colors */ + --bg-primary: #ffffff; + --bg-secondary: #f5f5f5; + --bg-tertiary: #efefef; + --bg-glass: rgba(0, 0, 0, 0.05); + + /* Text Colors */ + --text-primary: #1a1a1a; + --text-secondary: #666666; + --text-accent: #667eea; + + /* Accent Colors */ + --accent-primary: #667eea; + --accent-secondary: #764ba2; + --success: #00c853; + --error: #d32f2f; + --warning: #ffa000; + + /* Shadows */ + --shadow-glass: 0 8px 32px 0 rgba(0, 0, 0, 0.1); + --shadow-hover: 0 15px 35px rgba(0, 0, 0, 0.15); + --shadow-card: 0 8px 16px rgba(0, 0, 0, 0.1); + } + * { margin: 0; padding: 0; @@ -93,6 +126,14 @@ color: var(--text-primary); line-height: 1.6; overflow-x: hidden; + transition: background-color 0.3s ease, color 0.3s ease; + } + + [data-theme="light"] body { + background-image: + radial-gradient(circle at 20% 80%, rgba(102, 126, 234, 0.1) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba(240, 147, 251, 0.1) 0%, transparent 50%), + radial-gradient(circle at 40% 40%, rgba(102, 126, 234, 0.05) 0%, transparent 50%); } /* Header Styles */ @@ -104,6 +145,12 @@ backdrop-filter: blur(20px); background: rgba(15, 15, 35, 0.8); border-bottom: 1px solid rgba(255, 255, 255, 0.1); + transition: background 0.3s ease, border-color 0.3s ease; + } + + [data-theme="light"] .header { + background: rgba(255, 255, 255, 0.9); + border-bottom: 1px solid rgba(0, 0, 0, 0.1); } .navbar { @@ -198,7 +245,7 @@ padding-top: 100px; min-height: 100vh; } - + .hero-section { text-align: center; padding: 3rem 2rem; @@ -1644,6 +1691,9 @@ +
User John Doe @@ -1903,6 +1953,7 @@

Company

+ @@ -1976,4 +2027,4 @@

Install ExpenseFlow

}); - + \ No newline at end of file diff --git a/theme.js b/theme.js new file mode 100644 index 00000000..342dd2ab --- /dev/null +++ b/theme.js @@ -0,0 +1,96 @@ +// Theme Toggle Functionality +class ThemeManager { + constructor() { + this.STORAGE_KEY = 'expenseflow-theme'; + this.LIGHT_THEME = 'light'; + this.DARK_THEME = 'dark'; + this.init(); + } + + init() { + // Check if DOM is already loaded (likely since script is at end of body) + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', () => { + this.restoreTheme(); + this.setupThemeToggle(); + }); + } else { + // DOM is already loaded, initialize immediately + this.restoreTheme(); + this.setupThemeToggle(); + } + } + + getStoredTheme() { + return localStorage.getItem(this.STORAGE_KEY); + } + + setStoredTheme(theme) { + localStorage.setItem(this.STORAGE_KEY, theme); + } + + getPreferredTheme() { + const stored = this.getStoredTheme(); + if (stored) { + return stored; + } + + // Check system preference + if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) { + return this.LIGHT_THEME; + } + + return this.DARK_THEME; + } + + applyTheme(theme) { + const html = document.documentElement; + + if (theme === this.LIGHT_THEME) { + html.setAttribute('data-theme', this.LIGHT_THEME); + } else { + html.setAttribute('data-theme', this.DARK_THEME); + } + + this.setStoredTheme(theme); + this.updateToggleButton(theme); + } + + restoreTheme() { + const theme = this.getPreferredTheme(); + this.applyTheme(theme); + } + + toggleTheme() { + const currentTheme = document.documentElement.getAttribute('data-theme') || this.DARK_THEME; + const newTheme = currentTheme === this.LIGHT_THEME ? this.DARK_THEME : this.LIGHT_THEME; + this.applyTheme(newTheme); + } + + updateToggleButton(theme) { + const button = document.getElementById('theme-toggle-btn'); + if (button) { + if (theme === this.LIGHT_THEME) { + button.classList.add('light-mode'); + button.classList.remove('dark-mode'); + button.title = 'Switch to Dark Mode'; + button.innerHTML = ''; + } else { + button.classList.add('dark-mode'); + button.classList.remove('light-mode'); + button.title = 'Switch to Light Mode'; + button.innerHTML = ''; + } + } + } + + setupThemeToggle() { + const button = document.getElementById('theme-toggle-btn'); + if (button) { + button.addEventListener('click', () => this.toggleTheme()); + } + } +} + +// Initialize theme manager +const themeManager = new ThemeManager();