diff --git a/projects/animated-clock/index.html b/projects/animated-clock/index.html index dc858cb..8ef6ba2 100644 --- a/projects/animated-clock/index.html +++ b/projects/animated-clock/index.html @@ -2,37 +2,61 @@ - - - Animated Clock - + + + Animated Clock + -
-

Animated Clock

-
- - -
- -

Smooth animation with requestAnimationFrame. Select a time zone to view different regional times.

-
- - + + + - \ No newline at end of file +
+

Animated Clock

+
+ + +
+ +

Smooth animation with requestAnimationFrame. Select a time zone to view different regional times.

+
+ + + + diff --git a/projects/animated-clock/main.js b/projects/animated-clock/main.js index 175c95e..2a53a7c 100644 --- a/projects/animated-clock/main.js +++ b/projects/animated-clock/main.js @@ -1,3 +1,6 @@ +// ------------------------------ +// CLOCK FUNCTION +// ------------------------------ const c = document.getElementById('clock'); const ctx = c.getContext('2d'); const timezoneSelect = document.getElementById('timezone-select'); @@ -5,59 +8,74 @@ const timezoneSelect = document.getElementById('timezone-select'); let selectedTimezone = 'local'; timezoneSelect.addEventListener('change', (e) => { - selectedTimezone = e.target.value; + selectedTimezone = e.target.value; }); function getCurrentTime() { - const now = new Date(); - if (selectedTimezone === 'local') { - return now; - } - - try { - const timeInTimezone = new Date(now.toLocaleString("en-US", {timeZone: selectedTimezone})); - const localTime = new Date(now.toLocaleString("en-US")); - const diff = localTime.getTime() - timeInTimezone.getTime(); - return new Date(now.getTime() - diff); - } catch (error) { - return now; - } + const now = new Date(); + if (selectedTimezone === 'local') return now; + + try { + const timeInTimezone = new Date(now.toLocaleString("en-US", { timeZone: selectedTimezone })); + const localTime = new Date(now.toLocaleString("en-US")); + const diff = localTime.getTime() - timeInTimezone.getTime(); + return new Date(now.getTime() - diff); + } catch (error) { + return now; + } } function draw() { - const now = getCurrentTime(); - const w = c.width, h = c.height, r = w / 2; - - ctx.clearRect(0, 0, w, h); - ctx.translate(r, r); - ctx.strokeStyle = '#93c5fd'; + const now = getCurrentTime(); + const w = c.width, h = c.height, r = w / 2; + + ctx.clearRect(0, 0, w, h); + ctx.translate(r, r); + ctx.strokeStyle = '#93c5fd'; + ctx.beginPath(); + ctx.arc(0, 0, r - 6, 0, Math.PI * 2); + ctx.stroke(); + + function hand(angle, len, width) { + ctx.save(); + ctx.rotate(angle); ctx.beginPath(); - ctx.arc(0, 0, r - 6, 0, Math.PI * 2); + ctx.lineWidth = width; + ctx.moveTo(0, 0); + ctx.lineTo(0, -len); ctx.stroke(); - - function hand(angle, len, width) { - ctx.save(); - ctx.rotate(angle); - ctx.beginPath(); - ctx.lineWidth = width; - ctx.moveTo(0, 0); - ctx.lineTo(0, -len); - ctx.stroke(); - ctx.restore(); - } - - const sec = now.getSeconds() + now.getMilliseconds() / 1000; - const min = now.getMinutes() + sec / 60; - const hr = ((now.getHours() % 12) + min / 60); - - hand(hr * Math.PI / 6, r * 0.5, 4); - hand(min * Math.PI / 30, r * 0.75, 3); - hand(sec * Math.PI / 30, r * 0.85, 1); - - ctx.setTransform(1, 0, 0, 1, 0, 0); - requestAnimationFrame(draw); + ctx.restore(); + } + + const sec = now.getSeconds() + now.getMilliseconds() / 1000; + const min = now.getMinutes() + sec / 60; + const hr = ((now.getHours() % 12) + min / 60); + + hand(hr * Math.PI / 6, r * 0.5, 4); + hand(min * Math.PI / 30, r * 0.75, 3); + hand(sec * Math.PI / 30, r * 0.85, 1); + + ctx.setTransform(1, 0, 0, 1, 0, 0); + requestAnimationFrame(draw); } ctx.strokeStyle = '#6ee7b7'; ctx.lineCap = 'round'; draw(); + +const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); diff --git a/projects/animated-clock/styles.css b/projects/animated-clock/styles.css index 4247a9d..51f39d5 100644 --- a/projects/animated-clock/styles.css +++ b/projects/animated-clock/styles.css @@ -1,87 +1,176 @@ body { - font-family: system-ui; - background: #0f0f12; - color: #eef1f8; - margin: 0; - padding: 2rem; - display: grid; - place-items: center + font-family: system-ui; + background: #0f0f12; + color: #eef1f8; + margin: 0; + padding: 2rem; + display: grid; + place-items: center; + transition: background 0.3s, color 0.3s; } main { - max-width: 560px; - width: 100%; - text-align: center; + max-width: 560px; + width: 100%; + text-align: center; } canvas { - background: #17171c; - border: 1px solid #262631; - border-radius: .5rem + background: #17171c; + border: 1px solid #262631; + border-radius: .5rem; } .controls { - margin-bottom: 1.5rem; - display: flex; - align-items: center; - justify-content: center; - gap: 0.75rem; - flex-wrap: wrap; + margin-bottom: 1.5rem; + display: flex; + align-items: center; + justify-content: center; + gap: 0.75rem; + flex-wrap: wrap; } .controls label { - font-weight: 500; - color: #eef1f8; + font-weight: 500; + color: #eef1f8; } .controls select { - background: #17171c; - border: 1px solid #262631; - border-radius: 0.375rem; - color: #eef1f8; - padding: 0.5rem 0.75rem; - font-size: 0.9rem; - min-width: 140px; - cursor: pointer; - transition: border-color 0.2s ease; + background: #17171c; + border: 1px solid #262631; + border-radius: 0.375rem; + color: #eef1f8; + padding: 0.5rem 0.75rem; + font-size: 0.9rem; + min-width: 140px; + cursor: pointer; + transition: border-color 0.2s ease; } .controls select:hover { - border-color: #93c5fd; + border-color: #93c5fd; } .controls select:focus { - outline: none; - border-color: #6ee7b7; - box-shadow: 0 0 0 2px rgba(110, 231, 183, 0.2); + outline: none; + border-color: #6ee7b7; + box-shadow: 0 0 0 2px rgba(110, 231, 183, 0.2); } .notes { - color: #a6adbb; - font-size: .9rem; - margin-top: 1rem; + color: #a6adbb; + font-size: .9rem; + margin-top: 1rem; } @media (max-width: 480px) { - body { - padding: 1rem; - } - - .controls { - flex-direction: column; - gap: 0.5rem; - margin-bottom: 1rem; - } - - .controls select { - min-width: 200px; - width: 100%; - max-width: 280px; - } - - canvas { - width: 100%; - max-width: 240px; - height: auto; - } -} \ No newline at end of file + body { + padding: 1rem; + } + + .controls { + flex-direction: column; + gap: 0.5rem; + margin-bottom: 1rem; + } + + .controls select { + min-width: 200px; + width: 100%; + max-width: 280px; + } + + canvas { + width: 100%; + max-width: 240px; + height: auto; + } +} + +.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; +} + +body.dark-mode .controls label { + color: #0f0f12; +} + +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; +} + +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; +} + +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); +} diff --git a/projects/bmi/index.html b/projects/bmi/index.html index 3124cd2..2589d21 100644 --- a/projects/bmi/index.html +++ b/projects/bmi/index.html @@ -10,6 +10,23 @@ + +
diff --git a/projects/bmi/main.js b/projects/bmi/main.js index cf1d897..0daa5db 100644 --- a/projects/bmi/main.js +++ b/projects/bmi/main.js @@ -704,3 +704,19 @@ document.addEventListener('DOMContentLoaded', () => { new BMICalculator(); }); +const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); diff --git a/projects/bmi/styles.css b/projects/bmi/styles.css index 64f1d55..fb473a6 100644 --- a/projects/bmi/styles.css +++ b/projects/bmi/styles.css @@ -362,6 +362,8 @@ body { text-align: center; } + + .bmi-display { padding: 16px 20px; padding-top: 8px; @@ -736,60 +738,3 @@ body { white-space: normal; padding: 0 5px; } - - .gender-options { - flex-direction: column; - gap: 8px; - } - - .gender-radio-label { - padding: 10px 12px; - font-size: 13px; - } - - .gender-icon { - font-size: 14px; - } - - .gender-text { - font-size: 13px; - } -} - -/* Additional accessibility improvements */ -.gender-radio-label:focus-within { - outline: 2px solid #10b981; - outline-offset: 2px; -} - -/* Improve focus visibility for keyboard navigation */ -.gender-radio:focus + .gender-radio-label { - outline: 2px solid #10b981; - outline-offset: 2px; - background: rgba(16, 185, 129, 0.1); -} - -/* Better contrast for gender icons */ -.gender-icon { - filter: contrast(1.2); -} - -/* Ensure proper spacing on very small screens */ -@media (max-width: 360px) { - .gender-options { - gap: 6px; - } - - .gender-radio-label { - padding: 8px 10px; - font-size: 12px; - } - - .gender-text { - font-size: 12px; - } - - .gender-icon { - font-size: 12px; - } -} \ No newline at end of file diff --git a/projects/currency/index.html b/projects/currency/index.html index ce2e70d..0e73078 100644 --- a/projects/currency/index.html +++ b/projects/currency/index.html @@ -9,6 +9,23 @@ + +

Currency Converter (Offline)

diff --git a/projects/currency/main.js b/projects/currency/main.js index a332c7d..d2ed1ef 100644 --- a/projects/currency/main.js +++ b/projects/currency/main.js @@ -183,3 +183,21 @@ swapBtn.addEventListener('keydown', (e) => { swapCurrencies(); } }); + + +const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); diff --git a/projects/currency/styles.css b/projects/currency/styles.css index ec75515..4350ebe 100644 --- a/projects/currency/styles.css +++ b/projects/currency/styles.css @@ -223,4 +223,92 @@ button#swap { @media (max-width: 520px) { .row.inline { flex-direction: column; align-items: stretch; } .rate-row { flex-direction: column; align-items: stretch; } -} \ No newline at end of file +} + +.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; +} + +body.dark-mode .controls label { + color: #0f0f12; +} + +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; +} + +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; +} + +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); +} diff --git a/projects/expense-tracker/index.html b/projects/expense-tracker/index.html index 949a10b..df2fd99 100644 --- a/projects/expense-tracker/index.html +++ b/projects/expense-tracker/index.html @@ -9,6 +9,23 @@ + +

Expense Tracker

diff --git a/projects/expense-tracker/main.js b/projects/expense-tracker/main.js index 619ce8e..b62d2b4 100644 --- a/projects/expense-tracker/main.js +++ b/projects/expense-tracker/main.js @@ -68,4 +68,21 @@ } exportBtn.addEventListener('click', exportCSV); - render(); \ No newline at end of file + render(); + + const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); diff --git a/projects/expense-tracker/styles.css b/projects/expense-tracker/styles.css index 0ac6953..cd121e0 100644 --- a/projects/expense-tracker/styles.css +++ b/projects/expense-tracker/styles.css @@ -1,2 +1,89 @@ body{font-family:system-ui;background:#0f0f12;color:#eef1f8;margin:0;padding:2rem;display:grid;place-items:center}main{max-width:760px;width:100%}form{display:flex;gap:.5rem;flex-wrap:wrap}input,button{font:inherit}input{padding:.5rem .75rem;border-radius:.5rem;border:1px solid #262631;background:#17171c;color:#eef1f8}button{background:#6ee7b7;color:#0b1020;border:none;padding:.5rem .75rem;border-radius:.5rem;font-weight:600;cursor:pointer}ul{list-style:none;padding:0;margin:1rem 0}.notes{color:#a6adbb;font-size:.9rem} +.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; +} + +body.dark-mode .controls label { + color: #0f0f12; +} + +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; +} + +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; +} + +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); +} diff --git a/projects/image-slider/index.html b/projects/image-slider/index.html index 112342b..d943a17 100644 --- a/projects/image-slider/index.html +++ b/projects/image-slider/index.html @@ -1,30 +1,49 @@ - - - - Image Slider - - + + + + Image Slider + + - -
-

Image Slider

-
- -
- Slide

- + + + + +
+

Image Slider

+
+ +
+ Slide +

-
-
- - + +
+
+

Add autoplay, responsive, accessibility.

+
+ + + - \ No newline at end of file + diff --git a/projects/image-slider/main.js b/projects/image-slider/main.js index 3dd5927..d80f7db 100644 --- a/projects/image-slider/main.js +++ b/projects/image-slider/main.js @@ -13,7 +13,6 @@ const slides = [ }, ]; - let i = 0; const img = document.getElementById("img"); const captionEl = document.getElementById("caption"); @@ -131,4 +130,18 @@ function initSlider() { startAutoplay(); } +// THEME TOGGLE +const themeToggle = document.getElementById('themeToggle'); +const body = document.body; +const currentTheme = localStorage.getItem('theme') || 'light'; +if (currentTheme === 'dark') { + body.classList.add('dark-mode'); +} + +themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); +}); + initSlider(); diff --git a/projects/image-slider/styles.css b/projects/image-slider/styles.css index 6cb75a0..6e3c3d2 100644 --- a/projects/image-slider/styles.css +++ b/projects/image-slider/styles.css @@ -54,6 +54,7 @@ img { .slider:hover .caption { opacity: 1; } + button.nav-btn { background: #6ee7b7; color: #0b1020; @@ -102,16 +103,79 @@ button.nav-btn:hover { .notes { color: #a6adbb; - font-size: 0.9rem; - margin-top: 0.5rem; + font-size: .9rem; +} + +/* THEME TOGGLE BUTTON */ +.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} + +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; } -button:focus-visible { - outline: 2px solid var(--accent-2, #93c5fd); - outline-offset: 2px; +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; } -.indicator:focus-visible { - outline: 2px solid var(--accent-2, #93c5fd); - outline-offset: 2px; +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); } diff --git a/projects/markdown/index.html b/projects/markdown/index.html index 585336b..7eb67f9 100644 --- a/projects/markdown/index.html +++ b/projects/markdown/index.html @@ -9,6 +9,23 @@ + +

Markdown Editor

@@ -16,22 +33,7 @@

Markdown Editor

- +

Add full parser, export as HTML, and themes.

diff --git a/projects/markdown/main.js b/projects/markdown/main.js index 4fd8dab..19a14d4 100644 --- a/projects/markdown/main.js +++ b/projects/markdown/main.js @@ -1,21 +1,15 @@ const input = document.getElementById('input'); const preview = document.getElementById('preview'); -const themeToggle = document.getElementById('themeToggle'); const exportHtml = document.getElementById('exportHtml'); +const themeToggle = document.getElementById('themeToggle'); const body = document.body; -// Theme management (matching home page system) +// Apply saved theme const currentTheme = localStorage.getItem('theme') || 'light'; if (currentTheme === 'dark') { body.classList.add('dark-mode'); } -function toggleTheme() { - body.classList.toggle('dark-mode'); - const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; - localStorage.setItem('theme', theme); -} - // Markdown parsing function naive(md) { return md @@ -36,26 +30,16 @@ function exportAsHtml() { - - - Exported Markdown - + + +Exported Markdown + - ${preview.innerHTML} +${preview.innerHTML} `; @@ -72,9 +56,13 @@ function exportAsHtml() { // Event listeners input.addEventListener('input', render); -themeToggle.addEventListener('click', toggleTheme); exportHtml.addEventListener('click', exportAsHtml); -// Initialize -applyTheme(currentTheme); +themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); +}); + +// Initial render render(); diff --git a/projects/markdown/styles.css b/projects/markdown/styles.css index a761f84..a4bf7fe 100644 --- a/projects/markdown/styles.css +++ b/projects/markdown/styles.css @@ -11,28 +11,6 @@ --input-bg: #0e0e13; } -body:not(.dark-mode) { - --bg: #f8f9fa; - --card: #ffffff; - --text: #1a1a1a; - --muted: #6b7280; - --bg-gradient-start: #f0f4f8; - --bg-gradient-end: #e2e8f0; - --border: #e5e7eb; - --input-bg: #ffffff; -} - -body.dark-mode { - --bg: #0f0f12; - --card: #17171c; - --text: #eef1f8; - --muted: #a6adbb; - --bg-gradient-start: #0b0b0e; - --bg-gradient-end: #121217; - --border: #262631; - --input-bg: #0e0e13; -} - * { box-sizing: border-box; } @@ -105,9 +83,69 @@ main { transform: translateY(0); } + +textarea { + width: 100%; + background: var(--input-bg); + color: var(--text); + border: 1px solid var(--border); + border-radius: .5rem; + padding: .75rem; + font-family: inherit; + font-size: 1rem; + line-height: 1.5; + resize: vertical; + transition: background 0.3s ease, border-color 0.3s ease; +} + +textarea:focus { + outline: none; + border-color: var(--accent); + box-shadow: 0 0 0 2px rgba(110, 231, 183, 0.2); +} + +.preview { + background: var(--input-bg); + border: 1px solid var(--border); + border-radius: .5rem; + padding: .75rem; + min-height: 200px; + transition: background 0.3s ease, border-color 0.3s ease; + line-height: 1.6; +} + +.preview h2 { + color: var(--text); + margin: 0 0 0.5rem 0; +} + +.preview h3 { + color: var(--text); + margin: 0 0 0.5rem 0; +} + +.preview strong { + font-weight: bold; +} + +.preview em { + font-style: italic; +} + +.preview li { + margin: 0.25rem 0; +} + +.notes { + color: var(--muted); + font-size: .9rem; + text-align: center; + margin: 0; +} + .theme-toggle { background: var(--card); - border: 2px solid var(--border); + border: 2px solid var(--border, #262631); border-radius: 50%; width: 50px; height: 50px; @@ -154,62 +192,41 @@ body:not(.dark-mode) .theme-toggle .moon-icon { opacity: 0; transform: rotate(-90deg); } - -textarea { - width: 100%; - background: var(--input-bg); - color: var(--text); - border: 1px solid var(--border); - border-radius: .5rem; - padding: .75rem; - font-family: inherit; - font-size: 1rem; - line-height: 1.5; - resize: vertical; - transition: background 0.3s ease, border-color 0.3s ease; -} - -textarea:focus { - outline: none; - border-color: var(--accent); - box-shadow: 0 0 0 2px rgba(110, 231, 183, 0.2); +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; } -.preview { - background: var(--input-bg); - border: 1px solid var(--border); - border-radius: .5rem; - padding: .75rem; - min-height: 200px; - transition: background 0.3s ease, border-color 0.3s ease; - line-height: 1.6; +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; } -.preview h2 { - color: var(--text); - margin: 0 0 0.5rem 0; +body.dark-mode .controls label { + color: #0f0f12; } -.preview h3 { - color: var(--text); - margin: 0 0 0.5rem 0; +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; } -.preview strong { - font-weight: bold; +body.dark-mode .notes { + color: #4b5563; } -.preview em { - font-style: italic; +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; } -.preview li { - margin: 0.25rem 0; +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); } - -.notes { - color: var(--muted); - font-size: .9rem; - text-align: center; - margin: 0; -} \ No newline at end of file diff --git a/projects/maze/index.html b/projects/maze/index.html index 75b35c2..891d665 100644 --- a/projects/maze/index.html +++ b/projects/maze/index.html @@ -9,6 +9,22 @@ +

Maze

Contribute: generator, solver, keyboard navigation.

diff --git a/projects/maze/main.js b/projects/maze/main.js index 8a1f5ad..ba32f26 100644 --- a/projects/maze/main.js +++ b/projects/maze/main.js @@ -2,3 +2,19 @@ const c = document.getElementById('maze'); const ctx = c.getContext('2d'); // TODO: implement maze generation and basic player movement ctx.fillStyle = '#17171c'; ctx.fillRect(0, 0, c.width, c.height); ctx.fillStyle = '#6ee7b7'; ctx.fillRect(8, 8, 24, 24); +const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); diff --git a/projects/maze/styles.css b/projects/maze/styles.css index a3ef54d..b52f95f 100644 --- a/projects/maze/styles.css +++ b/projects/maze/styles.css @@ -22,4 +22,92 @@ canvas { .notes { color: #a6adbb; font-size: .9rem -} \ No newline at end of file +} + +.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; +} + +body.dark-mode .controls label { + color: #0f0f12; +} + +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; +} + +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; +} + +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); +} diff --git a/projects/memory-match/index.html b/projects/memory-match/index.html index d32da39..4c57367 100644 --- a/projects/memory-match/index.html +++ b/projects/memory-match/index.html @@ -9,6 +9,23 @@ + +

Memory Match

diff --git a/projects/memory-match/main.js b/projects/memory-match/main.js index 1242018..827cfb9 100644 --- a/projects/memory-match/main.js +++ b/projects/memory-match/main.js @@ -5,6 +5,24 @@ const grid = document.getElementById('grid'); const timeEl = document.querySelector('.time'); const bestEl = document.querySelector('.best'); +const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); + + const emojis = ['🍎', '🍌', '🍇', '🍓', '🍒', '🍍', '🍊', '🍉']; let deck = shuffle([...emojis, ...emojis]).map((v, i) => ({ id: i, v, flipped: false, matched: false })); let first = null, second = null, lock = false; @@ -107,3 +125,5 @@ function loadBestTime() { loadBestTime(); render(); + + diff --git a/projects/memory-match/styles.css b/projects/memory-match/styles.css index 235fc66..28d81b1 100644 --- a/projects/memory-match/styles.css +++ b/projects/memory-match/styles.css @@ -46,4 +46,92 @@ button.card.flipped { margin-bottom: 1rem; font-size: 1.1rem; color: #a6adbb; -} \ No newline at end of file +} + +.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; +} + +body.dark-mode .controls label { + color: #0f0f12; +} + +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; +} + +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; +} + +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); +} diff --git a/projects/number-guessing-game/index.html b/projects/number-guessing-game/index.html index 3dcd566..ba8aaee 100644 --- a/projects/number-guessing-game/index.html +++ b/projects/number-guessing-game/index.html @@ -8,6 +8,23 @@ + +

Number Guessing Game

I'm thinking of a number between 1 and 100. Can you guess it?

diff --git a/projects/number-guessing-game/main.js b/projects/number-guessing-game/main.js index 21865d6..c0342f8 100644 --- a/projects/number-guessing-game/main.js +++ b/projects/number-guessing-game/main.js @@ -89,4 +89,22 @@ function initNumberGuessingGame() { setFeedback('', ''); } -window.addEventListener('DOMContentLoaded', initNumberGuessingGame); \ No newline at end of file +window.addEventListener('DOMContentLoaded', initNumberGuessingGame); + + +const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); diff --git a/projects/number-guessing-game/styles.css b/projects/number-guessing-game/styles.css index c45c7ef..138e7a7 100644 --- a/projects/number-guessing-game/styles.css +++ b/projects/number-guessing-game/styles.css @@ -65,4 +65,92 @@ button:disabled { background: #1f1f27; border-color: #2a2a33; color: var(--muted background: linear-gradient(135deg, var(--accent), var(--accent-2)); border-color: #1e3a8a; } -#restart-btn:hover { filter: brightness(1.05); } \ No newline at end of file +#restart-btn:hover { filter: brightness(1.05); } + +.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; +} + +body.dark-mode .controls label { + color: #0f0f12; +} + +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; +} + +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; +} + +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); +} diff --git a/projects/pomodoro/index.html b/projects/pomodoro/index.html index 2564e18..c14b625 100644 --- a/projects/pomodoro/index.html +++ b/projects/pomodoro/index.html @@ -9,6 +9,23 @@ + +

Pomodoro Timer

25:00
diff --git a/projects/pomodoro/main.js b/projects/pomodoro/main.js index 32f338a..365100e 100644 --- a/projects/pomodoro/main.js +++ b/projects/pomodoro/main.js @@ -32,81 +32,3 @@ document.getElementById('reset').addEventListener('click', () => { render(); -// ---------------- TASK PANEL CODE ---------------- -const taskForm = document.getElementById('task-form'); -const taskList = document.getElementById('task-list'); - -let tasks = JSON.parse(localStorage.getItem('tasks')) || []; - -function saveTasks() { - localStorage.setItem('tasks', JSON.stringify(tasks)); -} - -function updateTaskDropdown() { - currentTaskSelect.innerHTML = ''; - tasks.forEach((task, index) => { - const opt = document.createElement('option'); - opt.value = index; - opt.textContent = task.name; - currentTaskSelect.appendChild(opt); - }); -} - -function renderTasks() { - taskList.innerHTML = ''; - tasks.forEach((task, index) => { - const li = document.createElement('li'); - li.innerHTML = ` - ${task.name}${task.desc ? ' - ' + task.desc : ''} ${task.pomodoros ? '(' + task.pomodoros + ' 🍅)' : ''} - - - - - `; - taskList.appendChild(li); - }); - updateTaskDropdown(); -} - -// Add task -taskForm.addEventListener('submit', e => { - e.preventDefault(); - const name = document.getElementById('task-name').value.trim(); - const desc = document.getElementById('task-desc').value.trim(); - if (!name) return; - tasks.push({name, desc, pomodoros: 0}); - saveTasks(); - renderTasks(); - taskForm.reset(); -}); - -// Edit task -window.editTask = function(index) { - const newName = prompt('Edit task name', tasks[index].name); - if (newName !== null) tasks[index].name = newName.trim() || tasks[index].name; - const newDesc = prompt('Edit description', tasks[index].desc); - if (newDesc !== null) tasks[index].desc = newDesc.trim(); - saveTasks(); - renderTasks(); -} - -// Delete task -window.deleteTask = function(index) { - if (confirm('Delete this task?')) { - tasks.splice(index,1); - saveTasks(); - renderTasks(); - } -} - -// Increment Pomodoro count for selected task -function incrementPomodoroForCurrentTask() { - const taskIndex = currentTaskSelect.value; - if (taskIndex !== "") { - tasks[taskIndex].pomodoros = (tasks[taskIndex].pomodoros || 0) + 1; - saveTasks(); - renderTasks(); - } -} - -renderTasks(); diff --git a/projects/pomodoro/styles.css b/projects/pomodoro/styles.css index 2cda0b7..829125c 100644 --- a/projects/pomodoro/styles.css +++ b/projects/pomodoro/styles.css @@ -32,48 +32,6 @@ button { color: #a6adbb; font-size: .9rem } -.task-panel { - margin-top: 2rem; - background: #1c1f2a; - padding: 1rem; - border-radius: 0.5rem; -} -.task-panel h2 { - margin: 0 0 0.5rem 0; -} -#task-form input { - padding: 0.5rem; - margin-right: 0.5rem; - border-radius: 0.25rem; - border: none; -} -#task-form button { - padding: 0.5rem 0.75rem; -} - -#task-list { - list-style: none; - padding: 0; - margin-top: 1rem; -} - -#task-list li { - display: flex; - justify-content: space-between; - margin-bottom: 0.5rem; - padding: 0.25rem 0.5rem; - background: #2a2f3f; - border-radius: 0.25rem; -} - -.task-buttons button { - margin-left: 0.25rem; - background: #6ee7b7; - border-radius: 0.25rem; - border: none; - cursor: pointer; - padding: 0.25rem 0.5rem; -} diff --git a/projects/qr-code-generator-scanner/index.html b/projects/qr-code-generator-scanner/index.html index da91799..26d4760 100644 --- a/projects/qr-code-generator-scanner/index.html +++ b/projects/qr-code-generator-scanner/index.html @@ -7,6 +7,23 @@ + +

QR Code Generator & Scanner

diff --git a/projects/qr-code-generator-scanner/main.js b/projects/qr-code-generator-scanner/main.js index 5e1eae6..5aabcd6 100644 --- a/projects/qr-code-generator-scanner/main.js +++ b/projects/qr-code-generator-scanner/main.js @@ -11,4 +11,21 @@ function initQRCodeGeneratorScanner() { // TODO: Download QR code } -window.addEventListener('DOMContentLoaded', initQRCodeGeneratorScanner); \ No newline at end of file +window.addEventListener('DOMContentLoaded', initQRCodeGeneratorScanner); + +const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); diff --git a/projects/qr-code-generator-scanner/styles.css b/projects/qr-code-generator-scanner/styles.css index 8cd3811..8cae5d1 100644 --- a/projects/qr-code-generator-scanner/styles.css +++ b/projects/qr-code-generator-scanner/styles.css @@ -1 +1,87 @@ -/* TODO: Style QR container, input, QR code display, download button, scan input, result display */ \ No newline at end of file +/* TODO: Style QR container, input, QR code display, download button, scan input, result display */.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; +} + +body.dark-mode .controls label { + color: #0f0f12; +} + +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; +} + +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; +} + +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); +} diff --git a/projects/rock-paper-scissors/index.html b/projects/rock-paper-scissors/index.html index b13b199..b786efa 100644 --- a/projects/rock-paper-scissors/index.html +++ b/projects/rock-paper-scissors/index.html @@ -7,6 +7,23 @@ + +

Rock-Paper-Scissors Game

diff --git a/projects/rock-paper-scissors/main.js b/projects/rock-paper-scissors/main.js index b99abf1..8c3c720 100644 --- a/projects/rock-paper-scissors/main.js +++ b/projects/rock-paper-scissors/main.js @@ -73,3 +73,21 @@ function initRockPaperScissors() { } window.addEventListener("DOMContentLoaded", initRockPaperScissors); + +const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); + diff --git a/projects/rock-paper-scissors/styles.css b/projects/rock-paper-scissors/styles.css index 1cf5b55..16a839f 100644 --- a/projects/rock-paper-scissors/styles.css +++ b/projects/rock-paper-scissors/styles.css @@ -107,3 +107,92 @@ h1 { gap: 0.5em; } } + +.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; +} + +body.dark-mode .controls label { + color: #0f0f12; +} + +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; +} + +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; +} + +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); +} + diff --git a/projects/text-encryption-decryption/index.html b/projects/text-encryption-decryption/index.html index 0bcf532..62ac956 100644 --- a/projects/text-encryption-decryption/index.html +++ b/projects/text-encryption-decryption/index.html @@ -7,6 +7,23 @@ + +

Text Encryption / Decryption Tool

diff --git a/projects/text-encryption-decryption/main.js b/projects/text-encryption-decryption/main.js index dbe0663..dbabca0 100644 --- a/projects/text-encryption-decryption/main.js +++ b/projects/text-encryption-decryption/main.js @@ -149,4 +149,21 @@ function initTextEncryptionDecryption() { updateCharCount(); } -window.addEventListener('DOMContentLoaded', initTextEncryptionDecryption); \ No newline at end of file +window.addEventListener('DOMContentLoaded', initTextEncryptionDecryption); + +const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); diff --git a/projects/text-encryption-decryption/styles.css b/projects/text-encryption-decryption/styles.css index 7743230..4828e1b 100644 --- a/projects/text-encryption-decryption/styles.css +++ b/projects/text-encryption-decryption/styles.css @@ -141,4 +141,92 @@ select, input[type="number"] { h1 { font-size: 1.4rem; } #tool-container { padding: 14px; } textarea { min-height: 100px; } -} \ No newline at end of file +} + +.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; +} + +body.dark-mode .controls label { + color: #0f0f12; +} + +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; +} + +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; +} + +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); +} diff --git a/projects/theme-switcher/index.html b/projects/theme-switcher/index.html index 7ffe68f..ee6d5f4 100644 --- a/projects/theme-switcher/index.html +++ b/projects/theme-switcher/index.html @@ -9,6 +9,23 @@ + +

Theme Switcher

diff --git a/projects/theme-switcher/main.js b/projects/theme-switcher/main.js index aa71c55..a628c9e 100644 --- a/projects/theme-switcher/main.js +++ b/projects/theme-switcher/main.js @@ -1,2 +1,18 @@ const input = document.getElementById('color'); document.getElementById('apply').addEventListener('click', () => { document.documentElement.style.setProperty('--accent', input.value); }); // TODOs: generate palettes (HSL); save themes (localStorage); share URL hash +const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); diff --git a/projects/theme-switcher/styles.css b/projects/theme-switcher/styles.css index d9059cd..3e3da3e 100644 --- a/projects/theme-switcher/styles.css +++ b/projects/theme-switcher/styles.css @@ -35,4 +35,92 @@ button { .notes { color: #a6adbb; font-size: .9rem -} \ No newline at end of file +} + +.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; +} + +body.dark-mode .controls label { + color: #0f0f12; +} + +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; +} + +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; +} + +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); +} diff --git a/projects/todo/index.html b/projects/todo/index.html index 7547331..6a37878 100644 --- a/projects/todo/index.html +++ b/projects/todo/index.html @@ -9,6 +9,23 @@ + +

Todo List

diff --git a/projects/todo/main.js b/projects/todo/main.js index a2b5a8c..6c445e9 100644 --- a/projects/todo/main.js +++ b/projects/todo/main.js @@ -48,3 +48,19 @@ function render() { render(); // TODOs: save to localStorage; add filter (all/active/done); sort; theme switcher +const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); diff --git a/projects/todo/styles.css b/projects/todo/styles.css index 50aea8d..3cbcc86 100644 --- a/projects/todo/styles.css +++ b/projects/todo/styles.css @@ -250,4 +250,92 @@ li.done label span { label { gap: 0.5rem; } -} \ No newline at end of file +} + +.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; +} + +body.dark-mode .controls label { + color: #0f0f12; +} + +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; +} + +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; +} + +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); +} diff --git a/projects/weather/index.html b/projects/weather/index.html index 257c757..2806557 100644 --- a/projects/weather/index.html +++ b/projects/weather/index.html @@ -9,6 +9,23 @@ + +

Weather

diff --git a/projects/weather/main.js b/projects/weather/main.js index a84627d..36113f4 100644 --- a/projects/weather/main.js +++ b/projects/weather/main.js @@ -182,4 +182,21 @@ unitBtn.addEventListener('click', () => { displayWeather(cache[cacheKey].data, currentCity); } } -}); \ No newline at end of file +}); + +const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); diff --git a/projects/weather/styles.css b/projects/weather/styles.css index 5f618de..f9d945b 100644 --- a/projects/weather/styles.css +++ b/projects/weather/styles.css @@ -8,6 +8,94 @@ body { place-items: center; min-height: 100vh; } +.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; +} + +body.dark-mode .controls label { + color: #0f0f12; +} + +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; +} + +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; +} + +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); +} + main { max-width: 560px; diff --git a/projects/whack-a-mole/index.html b/projects/whack-a-mole/index.html index 1659132..1b9d7c8 100644 --- a/projects/whack-a-mole/index.html +++ b/projects/whack-a-mole/index.html @@ -7,6 +7,23 @@ + +

Whack-a-Mole

diff --git a/projects/whack-a-mole/main.js b/projects/whack-a-mole/main.js index dd0c3c7..f947be1 100644 --- a/projects/whack-a-mole/main.js +++ b/projects/whack-a-mole/main.js @@ -289,3 +289,21 @@ document.addEventListener('keydown', (e) => { }); render(); + +const themeToggle = document.getElementById('themeToggle'); + const body = document.body; + + + const currentTheme = localStorage.getItem('theme') || 'light'; + if (currentTheme === 'dark') { + body.classList.add('dark-mode'); + } + + themeToggle.addEventListener('click', () => { + body.classList.toggle('dark-mode'); + + + const theme = body.classList.contains('dark-mode') ? 'dark' : 'light'; + localStorage.setItem('theme', theme); + }); + diff --git a/projects/whack-a-mole/styles.css b/projects/whack-a-mole/styles.css index f74fef7..34d21fb 100644 --- a/projects/whack-a-mole/styles.css +++ b/projects/whack-a-mole/styles.css @@ -8,6 +8,97 @@ body { place-items: center; } + +.theme-toggle { + background: var(--card); + border: 2px solid var(--border, #262631); + border-radius: 50%; + width: 50px; + height: 50px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.theme-toggle:hover { + transform: rotate(15deg) scale(1.1); + border-color: var(--accent); + box-shadow: 0 6px 16px rgba(110, 231, 183, 0.2); +} + +.theme-toggle svg { + position: absolute; + transition: all 0.3s ease; +} + +.theme-toggle .sun-icon { + opacity: 0; + transform: rotate(90deg); +} + +.theme-toggle .moon-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .sun-icon { + opacity: 1; + transform: rotate(0deg); +} + +body:not(.dark-mode) .theme-toggle .moon-icon { + opacity: 0; + transform: rotate(-90deg); +} +/* ------------------------------------ + DARK MODE THEME +------------------------------------ */ +body.dark-mode { + background: #eef1f8; + color: #0f0f12; +} + +body.dark-mode canvas { + background: #ffffff; + border-color: #cbd5e1; +} + +body.dark-mode .controls label { + color: #0f0f12; +} + +body.dark-mode .controls select { + background: #ffffff; + border: 1px solid #cbd5e1; + color: #0f0f12; +} + +body.dark-mode .notes { + color: #4b5563; +} + +/* Toggle button colors for dark mode */ +body.dark-mode .theme-toggle { + background: #e2e8f0; + border-color: #a1a1aa; + color: #0f0f12; +} + +body.dark-mode .theme-toggle:hover { + border-color: #2563eb; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.2); +} + + + main { max-width: 560px; width: 100%;