diff --git a/web-app/css/styles.css b/web-app/css/styles.css index e745d70..67c547c 100644 --- a/web-app/css/styles.css +++ b/web-app/css/styles.css @@ -1827,6 +1827,10 @@ body { color: #999fee; } +.game-icon-blackjack { + color: #8b5cf6; +} + .game-icon-dice { color: #e04f4f; } @@ -3015,6 +3019,120 @@ body { } } +/* ========================================================================== + CARD AND MODAL LAYOUT STANDARDIZATION + ========================================================================== */ + +.projects-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + gap: 1.2rem; + margin-top: 2rem; + align-items: stretch; +} + +.project-card { + min-height: 240px; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: stretch; + padding: 1.75rem 1.5rem 1.5rem; + border-radius: 28px; + background: var(--surface-color); + border: 1px solid var(--accent-border); + box-shadow: 0 18px 40px rgba(0, 0, 0, 0.08); + transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; +} + +.project-card h3 { + margin-bottom: 0.8rem; + font-size: 1.15rem; + line-height: 1.35; + color: var(--text-color); +} + +.project-card p { + margin-bottom: 1rem; + color: var(--text-secondary); + font-size: 0.95rem; + line-height: 1.65; + flex: 1 1 auto; +} + +.project-card .btn-play { + margin-top: auto; + align-self: flex-start; +} + +.card-icon { + width: 72px; + height: 72px; + display: grid; + place-items: center; + border-radius: 22px; + background: var(--accent-soft); + color: var(--accent-color); + margin-bottom: 1.2rem; + font-size: 2rem; + flex-shrink: 0; +} + +.modal-content { + width: min(100%, 900px); + max-width: 900px; + min-width: 320px; + max-height: 92vh; + overflow-y: auto; + overflow-x: hidden; + padding: 2rem; + border-radius: 20px; + box-shadow: var(--shadow-modal); + background: var(--surface-color); + border: 1px solid var(--border-color); +} + +#modalBody { + width: 100%; + display: flex; + flex-direction: column; + gap: 1rem; + align-items: stretch; +} + +#modalBody > * { + width: 100%; + max-width: 100%; +} + +.modal-close { + z-index: 2100; +} + +@media (max-width: 768px) { + .modal-content { + width: min(100%, 92vw); + padding: 1.5rem; + max-height: 90vh; + } + + .project-card { + min-height: auto; + padding: 1.5rem 1.25rem; + } +} + +@media (max-width: 576px) { + .projects-grid { + grid-template-columns: 1fr; + gap: 1rem; + } + + .project-card { + padding: 1.25rem; + } +} + /* ========================================================================== ARCADE REDESIGN OVERRIDES ========================================================================== */ @@ -4333,6 +4451,8 @@ html[data-theme="dark"] body { .btn-play { transform: none !important; } +} + /* Fix card content alignment */ .project-card { text-align: left; @@ -4359,4 +4479,136 @@ html[data-theme="dark"] body { padding: 1rem; } } -} \ No newline at end of file + +/* ========================================================================== + FINAL CARD + MODAL CONSISTENCY OVERRIDES + This section is intentionally appended at the end to override earlier + duplicate card/modal definitions and enforce consistent spacing, sizing, + and responsive behavior across all project pages. + ========================================================================== */ + +.projects-grid { + display: grid !important; + grid-template-columns: repeat(auto-fit, minmax(260px, 360px)) !important; + justify-content: center !important; + gap: 1.2rem !important; + margin: 0 auto 2rem !important; + align-items: stretch !important; +} + +.projects-grid > .project-card { + justify-self: center !important; + width: 100% !important; + max-width: 360px !important; +} + +.project-card { + min-height: 240px !important; + display: flex; + flex-direction: column !important; + justify-content: flex-start !important; + align-items: flex-start !important; + padding: 1.75rem 1.5rem 1.5rem !important; + border-radius: 28px !important; + background: var(--surface-color) !important; + border: 1px solid var(--accent-border) !important; + box-shadow: 0 18px 40px rgba(0, 0, 0, 0.08) !important; + transition: transform 0.2s ease !important; + margin: 0 auto !important; + font-size: 0.95rem !important; + line-height: 1.6 !important; +} + +.project-card .btn-play { + margin-top: 1rem !important; + align-self: flex-start !important; +} + +.card-icon { + width: 72px !important; + height: 72px !important; + display: grid !important; + place-items: center !important; + border-radius: 22px !important; + background: var(--accent-soft) !important; + color: var(--accent-color) !important; + margin: 0 auto 1.2rem !important; + font-size: 2rem !important; +} + +.modal { + display: none !important; + position: fixed !important; + top: 0 !important; + left: 0 !important; + width: 100% !important; + height: 100% !important; + background: var(--overlay-color) !important; + backdrop-filter: blur(6px) !important; + -webkit-backdrop-filter: blur(6px) !important; + z-index: 2000 !important; + animation: fadeIn 0.3s ease !important; +} + +.modal.active { + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +.modal-content { + width: min(100%, 900px) !important; + max-width: 900px !important; + min-width: 320px !important; + max-height: 92vh !important; + overflow-y: auto !important; + overflow-x: hidden !important; + padding: 2rem !important; + border-radius: 20px !important; + box-shadow: var(--shadow-modal) !important; + background: var(--surface-color) !important; + border: 1px solid var(--border-color) !important; + margin: auto !important; +} + +#modalBody { + width: 100% !important; + display: flex !important; + flex-direction: column !important; + gap: 1rem !important; + align-items: stretch !important; +} + +#modalBody > * { + width: 100% !important; + max-width: 100% !important; +} + +.modal-close { + z-index: 2100 !important; +} + +@media (max-width: 768px) { + .modal-content { + width: min(100%, 92vw) !important; + padding: 1.5rem !important; + max-height: 90vh !important; + } + + .project-card { + min-height: auto !important; + padding: 1.5rem 1.25rem !important; + } +} + +@media (max-width: 576px) { + .projects-grid { + grid-template-columns: 1fr !important; + gap: 1rem !important; + } + + .project-card { + padding: 1.25rem !important; + min-height: auto !important; + } +} diff --git a/web-app/index.html b/web-app/index.html index 2399b25..5c12c92 100644 --- a/web-app/index.html +++ b/web-app/index.html @@ -1172,163 +1172,210 @@

thrive

-
-
BlackJack21
- -

BlackJack21

-

Beat the dealer!

- -
Rock Paper Scissors
- -

Rock Paper Scissors

-

Battle against the computer!

- -
Dice Rolling
- -

Dice Rolling

-

Roll the dice with 3D animation!

- -
Coin Flip
- -

Coin Flip

-

Heads or tails with spinning animation!

- -
Number Guessing
- -

Number Guessing

-

Guess the secret number!

- -
Hangman
- -

Hangman

-

Classic word-guessing game!

- -
Word Scramble
- -

Word Scramble

-

Unscramble words before attempts run out!

- -
FLAMES Game
- -

FLAMES Game

-

Discover your relationship status!

- -
Dots & Boxes AI
- -

Dots & Boxes AI

-

Challenge friends or AI in this strategy game!

- -
Password Forge
- -

Password Forge

-

Survive evolving firewall password rules!

- -
Math Quiz
- -

Math Quiz

-

MCQ quiz with lives and difficulty levels!

- -
Snake Game
- -

Snake Game

-

Classic snake game!

- -
Emoji Memory Game
- -

Emoji Memory Game

-

Test your memory with matching emojis!

- -
Whack-a-Mole
- -

Whack-a-Mole

-

Hit the moles before they disappear!

- -
Flappy Game
- -

Flappy Game

-

Dodge the incoming balls and survive!

- -
2048 Game
- -

2048 Game

-

Combine tiles and reach 2048!

- -
Fibonacci Series
- -

Fibonacci Series

-

Generate Fibonacci sequences!

- -
AP/GP/AGP/HP Recognizer
- -

AP/GP/AGP/HP Recognizer

-

Identify progression types from any sequence.

- -
Pascal's Triangle
- -

Pascal's Triangle

-

Beautiful hexagon visualization!

- -
Armstrong Numbers
- -

Armstrong Numbers

-

Check special number properties!

- -
Calculator
- -

Calculator

-

Your mathematical companion!

- -
Collatz Conjecture
- -

Collatz Conjecture

-

Explore the 3n+1 problem!

- -
Prime Analyzer
- -

Prime Analyzer

-

All-in-one prime number toolkit!

- -
Projectile Motion
- -

Projectile Motion

-

Calculate TOF, Hmax, and Range with physics!

- -
Coordinate to Polar
- -

Coordinate to Polar

-

Transform Cartesian (x, y) into polar (r, theta).

- -
Derivative Calculator
- -

Derivative Calculator

-

Compute 1st/nth polynomial derivatives and evaluate them.

- -
Morse Code
- -

Morse Code

-

Translate with lights & sound!

- -
Tower of Hanoi
- -

Tower of Hanoi

-

Solve the classic puzzle!

- -
Number Converter
- -

Number Converter

-

Convert Dec, Bin, Oct, and Hex!

- -
Typing Speed Tester
- -

Typing Speed Tester

-

Test your typing skills!

+
+
+ 2048 Game +
+

2048 Game

+

Combine tiles and reach 2048!

+
+
+ AP/GP/AGP/HP Recognizer +
+

AP/GP/AGP/HP Recognizer

+

Identify progression types from any sequence.

+
+
+ Armstrong Numbers +
+

Armstrong Numbers

+

Check special number properties!

+
+
+ BlackJack21 +
+

BlackJack21

+

Beat the dealer!

+
+
+ Calculator +
+

Calculator

+

Your mathematical companion!

+
+
+ Coin Flip +
+

Coin Flip

+

Heads or tails with spinning animation!

+
+
+ Collatz Conjecture +
+

Collatz Conjecture

+

Explore the 3n+1 problem!

+
+
+ Color Palette Suggestor +
+

Color Palette Suggestor

+

Generate palettes + CSS snippets for any website type and mood!

+
+
+ Coordinate to Polar +
+

Coordinate to Polar

+

Transform Cartesian (x, y) into polar (r, theta).

+
+
+ Derivative Calculator +
+

Derivative Calculator

+

Compute 1st/nth polynomial derivatives and evaluate them.

+
+
+ Dice Rolling +
+

Dice Rolling

+

Roll the dice with 3D animation!

+
+
+ Dots & Boxes AI +
+

Dots & Boxes AI

+

Challenge friends or AI in this strategy game!

+
+
+ Emoji Memory Game +
+

Emoji Memory Game

+

Test your memory with matching emojis!

+
+
+ Fibonacci Series +
+

Fibonacci Series

+

Generate Fibonacci sequences!

+
+
+ FLAMES Game +
+

FLAMES Game

+

Discover your relationship status!

+
+
+ Flappy Game +
+

Flappy Game

+

Dodge the incoming balls and survive!

+
+
+ Hangman +
+

Hangman

+

Classic word-guessing game!

+
+
+ Math Quiz +
+

Math Quiz

+

MCQ quiz with lives and difficulty levels!

+
+
+ Morse Code +
+

Morse Code

+

Translate with lights & sound!

+
+
+ Number Converter +
+

Number Converter

+

Convert Dec, Bin, Oct, and Hex!

+
+
+ Number Guessing +
+

Number Guessing

+

Guess the secret number!

+
+
+ Pascal's Triangle +
+

Pascal's Triangle

+

Beautiful hexagon visualization!

+
+
+ Password Forge +
+

Password Forge

+

Survive evolving firewall password rules!

+
+
+ Prime Analyzer +
+

Prime Analyzer

+

All-in-one prime number toolkit!

+
+
+ Projectile Motion +
+

Projectile Motion

+

Calculate TOF, Hmax, and Range with physics!

+
+
+ Rock Paper Scissors +
+

Rock Paper Scissors

+

Battle against the computer!

+
+
+ Simon Says +
+

Simon Says

+

Repeat the pattern and test your memory skills!

+
+
+ Snake Game +
+

Snake Game

+

Classic snake game!

+
+
+ Tower of Hanoi +
+

Tower of Hanoi

+

Solve the classic puzzle!

+
+
+ Typing Speed Tester +
+

Typing Speed Tester

+

Test your typing skills!

+
+
+ Whack-a-Mole +
+

Whack-a-Mole

+

Hit the moles before they disappear!

+
+
+ Word Scramble +
+

Word Scramble

+

Unscramble words before attempts run out!

+
+
-
Color Palette Suggestor
+ +
+
-

Color Palette Suggestor

-

Generate palettes + CSS snippets for any website type and mood!

+
-
@@ -1593,38 +1640,18 @@

Stay Updated

const navSearchInput = document.getElementById("searchInput"); const heroSearchInput = document.getElementById("heroSearchInput"); - // Select all project cards - const projectCards = document.querySelectorAll(".project-card"); - - function filterCards(searchValue) { - projectCards.forEach(card => { - const title = card.querySelector("h3").textContent.toLowerCase(); - const description = card.querySelector("p").textContent.toLowerCase(); - - if ( - title.includes(searchValue) || - description.includes(searchValue) - ) { - card.style.display = "block"; - } else { - card.style.display = "none"; - } - }); - } - - // Sync both search inputs and filter cards + // Sync both search inputs and let main.js handle the filtering cleanly if (navSearchInput) { navSearchInput.addEventListener("input", () => { - const val = navSearchInput.value.toLowerCase(); if (heroSearchInput) heroSearchInput.value = navSearchInput.value; - filterCards(val); }); } if (heroSearchInput) { heroSearchInput.addEventListener("input", () => { - const val = heroSearchInput.value.toLowerCase(); - if (navSearchInput) navSearchInput.value = heroSearchInput.value; - filterCards(val); + if (navSearchInput) { + navSearchInput.value = heroSearchInput.value; + navSearchInput.dispatchEvent(new Event("input")); + } }); } diff --git a/web-app/js/main.js b/web-app/js/main.js index 0347a87..40c2072 100644 --- a/web-app/js/main.js +++ b/web-app/js/main.js @@ -761,7 +761,7 @@ if (stickyFilterBar && heroSection) { if (searchLoader) searchLoader.style.display = query ? 'block' : 'none'; debouncedSearch(query); performSearch(); - if (query && projectsSection) { + if (query && projectsSection && document.activeElement === searchInput) { projectsSection.scrollIntoView({ behavior: prefersReducedMotion() ? 'auto' : 'smooth', block: 'start' @@ -822,18 +822,19 @@ if (stickyFilterBar && heroSection) { var modalBody = document.getElementById('modalBody'); if (!modalContent || !modalBody) return; - // Reset scroll position to top to avoid viewport clippings during calculations modalContent.scrollTop = 0; modalBody.scrollTop = 0; - // Hide scrollbars on the container - modalContent.style.overflow = 'hidden'; + modalContent.style.overflow = 'auto'; - // Reset inline styles to capture natural dimensions modalBody.style.transform = ''; modalBody.style.transformOrigin = ''; - modalBody.style.width = ''; + modalBody.style.width = '100%'; modalBody.style.height = ''; + modalBody.style.display = 'flex'; + modalBody.style.flexDirection = 'column'; + modalBody.style.alignItems = 'stretch'; + modalBody.style.gap = '1rem'; var targetEl = Array.from(modalBody.children).find(function (el) { return el.tagName.toLowerCase() !== 'style'; @@ -842,40 +843,8 @@ if (stickyFilterBar && heroSection) { targetEl.style.transform = ''; targetEl.style.transformOrigin = ''; - - var computedStyle = window.getComputedStyle(modalContent); - var paddingTop = parseFloat(computedStyle.paddingTop) || 32; - var paddingBottom = parseFloat(computedStyle.paddingBottom) || 32; - var paddingLeft = parseFloat(computedStyle.paddingLeft) || 32; - var paddingRight = parseFloat(computedStyle.paddingRight) || 32; - - var availableHeight = modalContent.clientHeight - paddingTop - paddingBottom; - var availableWidth = modalContent.clientWidth - paddingLeft - paddingRight; - - var contentHeight = targetEl.scrollHeight; - var contentWidth = targetEl.scrollWidth; - - if (contentHeight <= 0 || contentWidth <= 0) return; - - var zoom = 1; - var heightZoom = availableHeight / contentHeight; - var widthZoom = availableWidth / contentWidth; - - zoom = Math.min(heightZoom, widthZoom); - if (zoom > 1) { - zoom = 1; - } - - // Apply scale transform and origins - targetEl.style.transform = 'scale(' + zoom + ')'; - targetEl.style.transformOrigin = 'top center'; - - // Constrain wrapper block size to prevent scroll triggering - modalBody.style.height = (contentHeight * zoom) + 'px'; - modalBody.style.width = '100%'; - modalBody.style.display = 'flex'; - modalBody.style.flexDirection = 'column'; - modalBody.style.alignItems = 'center'; + targetEl.style.width = '100%'; + targetEl.style.maxWidth = '100%'; } function initModalScaling() { @@ -997,6 +966,9 @@ if (stickyFilterBar && heroSection) { modalBody.style.transformOrigin = ''; modalBody.style.width = ''; modalBody.style.height = ''; + modalBody.style.display = ''; + modalBody.style.alignItems = ''; + modalBody.style.gap = ''; } if (lastFocusedElement && typeof lastFocusedElement.focus === 'function') { lastFocusedElement.focus({ preventScroll: true });