From 3b1f8d6eb8fa3ee04bbc9908b2ac567b025e93c0 Mon Sep 17 00:00:00 2001 From: Fernando Tona Date: Sat, 18 Oct 2025 19:35:58 +0100 Subject: [PATCH 1/9] Spacing working as I want between elements. --- src/css/style.css | 100 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/css/style.css b/src/css/style.css index 14d8d8d..77999e9 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -222,6 +222,106 @@ a { 4. MEDIA QUERIES (RESPONSIVE) =================================== */ +/* Mobile optimizations (up to 576px) */ +@media (max-width: 576px) { + .language-selector-wrapper { + top: 15px; + right: 15px; + } + + .custom-select { + width: 100px; + } + + .custom-select-trigger { + padding: 6px 28px 6px 10px; + font-size: 12px; + background-position: right 8px center; + background-size: 8px; + } + + .custom-option { + padding: 6px 10px; + font-size: 12px; + } + + /* Align container properly */ + .container { + padding-left: 15px !important; + padding-right: 15px !important; + } + + /* Make image width dynamic with 15px margin on both sides */ + .col-12.col-sm-10 { + padding-left: 0 !important; + padding-right: 0 !important; + margin-left: 0 !important; + margin-right: 0 !important; + max-width: 100% !important; + margin-bottom: 0 !important; + } + + .col-12.col-sm-10 img { + max-width: calc(100vw - 30px) !important; + width: calc(100vw - 30px) !important; + margin-left: auto !important; + margin-right: auto !important; + display: block !important; + margin-bottom: 0 !important; + } + + /* Reduce heading size */ + .display-5 { + font-size: 2rem !important; + margin-top: 0 !important; + margin-bottom: 0.5rem !important; + } + + /* Reduce lead text size */ + .lead { + font-size: 1rem !important; + margin-bottom: 0.5rem !important; + } + + /* Reduce button padding */ + .btn-lg { + padding: 0.5rem 1rem !important; + font-size: 1rem !important; + } + + /* Adjust spacing - KILL THE GAP */ + .row.g-5 { + row-gap: 1.5rem !important; + gap: 1.5rem !important; + } + + .py-5 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + + /* Target the text column directly */ + .col-lg-6 { + padding-top: 0 !important; + margin-top: 0 !important; + } + + /* Tighten ALL headings and paragraphs */ + h1, .h1, .display-5 { + margin-top: 0 !important; + margin-bottom: 0.75rem !important; + padding-top: 0 !important; + } + + p, .lead { + margin-bottom: 0.75rem !important; + } + + .d-grid { + margin-top: 1.25rem !important; + } +} + /* Desktop and up (992px and above) */ @media (min-width: 992px) { .btn-linkedin, From 36fb6af6d9be54d67f86850e802a56bc4b5df408 Mon Sep 17 00:00:00 2001 From: Fernando Tona Date: Sat, 18 Oct 2025 19:42:46 +0100 Subject: [PATCH 2/9] better. Without white spacing around. --- src/css/style.css | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/css/style.css b/src/css/style.css index 77999e9..4320d2f 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -59,6 +59,7 @@ a { min-height: 100vh; display: flex; align-items: center; + overflow-x: hidden; } /* Language Selector */ @@ -224,6 +225,12 @@ a { /* Mobile optimizations (up to 576px) */ @media (max-width: 576px) { + /* Prevent horizontal scroll */ + body { + overflow-x: hidden !important; + max-width: 100vw !important; + } + .language-selector-wrapper { top: 15px; right: 15px; @@ -249,6 +256,14 @@ a { .container { padding-left: 15px !important; padding-right: 15px !important; + max-width: 100% !important; + overflow-x: hidden !important; + } + + /* Fix Bootstrap row negative margins */ + .row { + margin-left: 0 !important; + margin-right: 0 !important; } /* Make image width dynamic with 15px margin on both sides */ @@ -296,7 +311,7 @@ a { } .py-5 { - padding-top: 1.5rem !important; + padding-top: 4rem !important; padding-bottom: 1.5rem !important; } From 61b8d85e3667ded9a7b9b0430b48e1a04a18168f Mon Sep 17 00:00:00 2001 From: Fernando Tona Date: Sat, 18 Oct 2025 20:13:48 +0100 Subject: [PATCH 3/9] Seems to be perfect in mobile --- src/css/style.css | 9 ++++++++- src/index.html | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/css/style.css b/src/css/style.css index 4320d2f..7eeee90 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -231,6 +231,11 @@ a { max-width: 100vw !important; } + /* Remove flexbox centering on mobile for consistent positioning */ + #main { + align-items: flex-start !important; + } + .language-selector-wrapper { top: 15px; right: 15px; @@ -274,6 +279,7 @@ a { margin-right: 0 !important; max-width: 100% !important; margin-bottom: 0 !important; + margin-top: 100px !important; } .col-12.col-sm-10 img { @@ -283,6 +289,7 @@ a { margin-right: auto !important; display: block !important; margin-bottom: 0 !important; + margin-top: 0 !important; } /* Reduce heading size */ @@ -311,7 +318,7 @@ a { } .py-5 { - padding-top: 4rem !important; + padding-top: 0.5rem !important; padding-bottom: 1.5rem !important; } diff --git a/src/index.html b/src/index.html index e0dc549..f0f8e45 100644 --- a/src/index.html +++ b/src/index.html @@ -39,7 +39,7 @@
-
+
@@ -54,7 +54,7 @@
-
+
Date: Sat, 18 Oct 2025 20:28:49 +0100 Subject: [PATCH 4/9] Better. --- src/css/style.css | 120 ++++++++++++++++++++-------------------------- src/index.html | 11 ++--- 2 files changed, 57 insertions(+), 74 deletions(-) diff --git a/src/css/style.css b/src/css/style.css index 7eeee90..eb172a5 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -62,6 +62,11 @@ a { overflow-x: hidden; } +/* Container padding - default for all sizes */ +.container { + padding: 3rem 1.5rem; +} + /* Language Selector */ .language-selector-wrapper { position: absolute; @@ -158,6 +163,25 @@ a { filter: brightness(0) invert(1); } +/* Profile image */ +.profile-image { + display: block; + margin: 0 auto; + max-width: 350px; + width: 100%; + border-radius: 2%; +} + +/* Main title */ +.main-title { + color: var(--clr-navy); +} + +/* Lead text */ +.lead { + color: var(--clr-white); +} + /* LinkedIn button */ .btn-linkedin { display: flex; @@ -225,17 +249,17 @@ a { /* Mobile optimizations (up to 576px) */ @media (max-width: 576px) { - /* Prevent horizontal scroll */ + /* Prevent horizontal scroll and align content to top */ body { - overflow-x: hidden !important; - max-width: 100vw !important; + overflow-x: hidden; + max-width: 100vw; } - /* Remove flexbox centering on mobile for consistent positioning */ #main { - align-items: flex-start !important; + align-items: flex-start; } + /* Language selector positioning */ .language-selector-wrapper { top: 15px; right: 15px; @@ -257,90 +281,50 @@ a { font-size: 12px; } - /* Align container properly */ + /* Container and spacing */ .container { - padding-left: 15px !important; - padding-right: 15px !important; - max-width: 100% !important; - overflow-x: hidden !important; + padding: 0.5rem 15px 1.5rem 15px; } - /* Fix Bootstrap row negative margins */ .row { - margin-left: 0 !important; - margin-right: 0 !important; + margin-left: 0; + margin-right: 0; + row-gap: 1.5rem; } - /* Make image width dynamic with 15px margin on both sides */ + /* Image column - ensure clearance from language selector */ .col-12.col-sm-10 { - padding-left: 0 !important; - padding-right: 0 !important; - margin-left: 0 !important; - margin-right: 0 !important; - max-width: 100% !important; - margin-bottom: 0 !important; - margin-top: 100px !important; + margin-top: 100px; + max-width: 100%; + padding: 0; } - .col-12.col-sm-10 img { - max-width: calc(100vw - 30px) !important; - width: calc(100vw - 30px) !important; - margin-left: auto !important; - margin-right: auto !important; - display: block !important; - margin-bottom: 0 !important; - margin-top: 0 !important; + .profile-image { + width: calc(100vw - 30px); /* 15px margin on each side */ + max-width: calc(100vw - 30px); + margin-left: auto; + margin-right: auto; } - /* Reduce heading size */ + /* Typography scaling */ .display-5 { - font-size: 2rem !important; - margin-top: 0 !important; - margin-bottom: 0.5rem !important; + font-size: 2rem; + margin-bottom: 0.5rem; } - /* Reduce lead text size */ .lead { - font-size: 1rem !important; - margin-bottom: 0.5rem !important; + font-size: 1rem; + margin-bottom: 0.5rem; } - /* Reduce button padding */ + /* Buttons */ .btn-lg { - padding: 0.5rem 1rem !important; - font-size: 1rem !important; - } - - /* Adjust spacing - KILL THE GAP */ - .row.g-5 { - row-gap: 1.5rem !important; - gap: 1.5rem !important; - } - - .py-5 { - padding-top: 0.5rem !important; - padding-bottom: 1.5rem !important; - } - - /* Target the text column directly */ - .col-lg-6 { - padding-top: 0 !important; - margin-top: 0 !important; - } - - /* Tighten ALL headings and paragraphs */ - h1, .h1, .display-5 { - margin-top: 0 !important; - margin-bottom: 0.75rem !important; - padding-top: 0 !important; - } - - p, .lead { - margin-bottom: 0.75rem !important; + padding: 0.5rem 1rem; + font-size: 1rem; } .d-grid { - margin-top: 1.25rem !important; + margin-top: 1.25rem; } } diff --git a/src/index.html b/src/index.html index f0f8e45..94778a0 100644 --- a/src/index.html +++ b/src/index.html @@ -39,7 +39,7 @@
-
+
@@ -58,21 +58,20 @@
Fernando Tona picture
-

+

Fernando Tona

-

+

Software Developer | .NET/C# | Azure

-

+

Problem-Solver with a Musician's Discipline

From 02df89f58e7d1dc1d9c8f9be2f3e7631049a8ef2 Mon Sep 17 00:00:00 2001 From: Fernando Tona Date: Sat, 18 Oct 2025 20:38:27 +0100 Subject: [PATCH 5/9] looks perfect on mobile. --- src/css/style.css | 16 ++++++++++------ src/index.html | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/css/style.css b/src/css/style.css index eb172a5..218cd07 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -283,20 +283,19 @@ a { /* Container and spacing */ .container { - padding: 0.5rem 15px 1.5rem 15px; + padding: 60px 15px 1.5rem 15px; } .row { - margin-left: 0; - margin-right: 0; - row-gap: 1.5rem; + margin: 0; + row-gap: 15px; } - /* Image column - ensure clearance from language selector */ + /* Image column */ .col-12.col-sm-10 { - margin-top: 100px; max-width: 100%; padding: 0; + margin: 0; } .profile-image { @@ -330,6 +329,11 @@ a { /* Desktop and up (992px and above) */ @media (min-width: 992px) { + /* Add spacing between columns on desktop */ + .row { + row-gap: 3rem; + } + .btn-linkedin, .btn-github-outline { width: auto; diff --git a/src/index.html b/src/index.html index 94778a0..2f822c2 100644 --- a/src/index.html +++ b/src/index.html @@ -54,7 +54,7 @@
-
+
Date: Sat, 18 Oct 2025 20:40:27 +0100 Subject: [PATCH 6/9] formatting --- src/index.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/index.html b/src/index.html index 2f822c2..73cc409 100644 --- a/src/index.html +++ b/src/index.html @@ -65,9 +65,7 @@ />
-

- Fernando Tona -

+

Fernando Tona

Software Developer | .NET/C# | Azure

From 6c25cf3e4c2caf4997f15f9b6aba834899af321e Mon Sep 17 00:00:00 2001 From: Fernando Tona Date: Sat, 18 Oct 2025 21:18:07 +0100 Subject: [PATCH 7/9] Overall code cleanup --- src/css/style.css | 368 ----------------------------------- src/css/styles.css | 271 ++++++++++++++++++++++++++ src/index.html | 42 ++-- src/js/custom-select.js | 20 +- src/js/custom-select.test.js | 40 ++-- 5 files changed, 321 insertions(+), 420 deletions(-) delete mode 100644 src/css/style.css create mode 100644 src/css/styles.css diff --git a/src/css/style.css b/src/css/style.css deleted file mode 100644 index 218cd07..0000000 --- a/src/css/style.css +++ /dev/null @@ -1,368 +0,0 @@ -/* =================================== - CSS STRUCTURE: - 1. Global Styles - 2. Layout Components - 3. UI Components - 4. Media Queries (Responsive) - =================================== */ - -/* =================================== - 1. GLOBAL STYLES - =================================== */ - -/* Reset and base styles */ -a { - text-decoration: none; -} - -/* Color Variables */ -:root { - --clr-navy: #070f2b; - --clr-gradient-mid: #3572ef; - --clr-gradient-end: #3abef9; - --clr-linkedin: #2856c7; - --clr-white: #ffffff; -} - -/* =================================== - 2. LAYOUT COMPONENTS - =================================== */ - -/* Background and animations */ -.gradient-bg { - background: linear-gradient( - 300deg, - var(--clr-navy), - var(--clr-gradient-mid), - var(--clr-gradient-end) - ); - background-size: 180% 180%; - animation: gradient-animation 10s ease infinite; -} - -@keyframes gradient-animation { - 0% { - background-position: 0% 50%; - } - - 50% { - background-position: 100% 50%; - } - - 100% { - background-position: 0% 50%; - } -} - -/* Main section layout */ -#main { - min-height: 100vh; - display: flex; - align-items: center; - overflow-x: hidden; -} - -/* Container padding - default for all sizes */ -.container { - padding: 3rem 1.5rem; -} - -/* Language Selector */ -.language-selector-wrapper { - position: absolute; - top: 10px; - right: 10px; - z-index: 1000; -} - -/* Custom Select Styles */ -.custom-select { - position: relative; - width: 110px; -} - -.custom-select-trigger { - padding: 8px 32px 8px 12px; - font-size: 13px; - font-weight: 600; - color: white; - background-color: rgba(255, 255, 255, 0.15); - backdrop-filter: blur(10px); - border: 2px solid rgba(255, 255, 255, 0.3); - border-radius: 12px; - cursor: pointer; - transition: all 0.3s ease; - background-image: url("../assets/images/arrow-down.svg"); - background-repeat: no-repeat; - background-position: right 10px center; - background-size: 10px; - user-select: none; -} - -.custom-select-trigger:hover { - background-color: rgba(255, 255, 255, 0.25); - border-color: rgba(255, 255, 255, 0.5); - transform: translateY(-2px); -} - -.custom-select.open .custom-select-trigger { - background-color: rgba(255, 255, 255, 0.3); - border-color: white; - box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.2); -} - -.custom-options { - position: absolute; - top: calc(100% + 5px); - left: 0; - right: 0; - background-color: rgba(255, 255, 255, 0.15); - backdrop-filter: blur(10px); - border: 2px solid rgba(255, 255, 255, 0.3); - border-radius: 12px; - overflow: hidden; - opacity: 0; - visibility: hidden; - transform: translateY(-10px); - transition: all 0.3s ease; -} - -.custom-select.open .custom-options { - opacity: 1; - visibility: visible; - transform: translateY(0); -} - -.custom-option { - padding: 8px 12px; - font-size: 13px; - font-weight: 600; - color: white; - cursor: pointer; - transition: all 0.2s ease; - user-select: none; -} - -.custom-option:hover { - background-color: rgba(255, 255, 255, 0.2); -} - -.custom-option.selected { - background-color: rgba(255, 255, 255, 0.25); -} - -/* =================================== - 3. UI COMPONENTS - =================================== */ - -/* Button icons */ -.btn-icon { - width: 18px; - height: 18px; - margin-right: 6px; - filter: brightness(0) invert(1); -} - -/* Profile image */ -.profile-image { - display: block; - margin: 0 auto; - max-width: 350px; - width: 100%; - border-radius: 2%; -} - -/* Main title */ -.main-title { - color: var(--clr-navy); -} - -/* Lead text */ -.lead { - color: var(--clr-white); -} - -/* LinkedIn button */ -.btn-linkedin { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - background-color: var(--clr-linkedin); - color: var(--clr-white); - border: 2px solid var(--clr-linkedin); -} - -.btn-linkedin:hover { - background-color: var(--clr-navy); - color: var(--clr-white); -} - -.btn-linkedin:focus, -.btn-linkedin:active { - background-color: var(--clr-white); - color: var(--clr-navy); - box-shadow: 0 0 0 0.2rem rgba(0, 119, 181, 0.25); -} - -.btn-linkedin:focus .btn-icon, -.btn-linkedin:active .btn-icon { - filter: brightness(0) invert(0); -} - -/* GitHub button */ -.btn-github-outline { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - background-color: transparent; - color: var(--clr-white); - border: 2px solid var(--clr-white); -} - -.btn-github-outline:hover { - background-color: var(--clr-white); - color: var(--clr-navy); - border-color: var(--clr-white); -} - -.btn-github-outline:focus, -.btn-github-outline:active { - background-color: var(--clr-navy); - color: var(--clr-white); - border-color: var(--clr-navy); -} - -.btn-github-outline:hover .btn-icon { - filter: brightness(0) invert(0); -} - -.btn-github-outline:focus .btn-icon, -.btn-github-outline:active .btn-icon { - filter: brightness(0) invert(1); -} - -/* =================================== - 4. MEDIA QUERIES (RESPONSIVE) - =================================== */ - -/* Mobile optimizations (up to 576px) */ -@media (max-width: 576px) { - /* Prevent horizontal scroll and align content to top */ - body { - overflow-x: hidden; - max-width: 100vw; - } - - #main { - align-items: flex-start; - } - - /* Language selector positioning */ - .language-selector-wrapper { - top: 15px; - right: 15px; - } - - .custom-select { - width: 100px; - } - - .custom-select-trigger { - padding: 6px 28px 6px 10px; - font-size: 12px; - background-position: right 8px center; - background-size: 8px; - } - - .custom-option { - padding: 6px 10px; - font-size: 12px; - } - - /* Container and spacing */ - .container { - padding: 60px 15px 1.5rem 15px; - } - - .row { - margin: 0; - row-gap: 15px; - } - - /* Image column */ - .col-12.col-sm-10 { - max-width: 100%; - padding: 0; - margin: 0; - } - - .profile-image { - width: calc(100vw - 30px); /* 15px margin on each side */ - max-width: calc(100vw - 30px); - margin-left: auto; - margin-right: auto; - } - - /* Typography scaling */ - .display-5 { - font-size: 2rem; - margin-bottom: 0.5rem; - } - - .lead { - font-size: 1rem; - margin-bottom: 0.5rem; - } - - /* Buttons */ - .btn-lg { - padding: 0.5rem 1rem; - font-size: 1rem; - } - - .d-grid { - margin-top: 1.25rem; - } -} - -/* Desktop and up (992px and above) */ -@media (min-width: 992px) { - /* Add spacing between columns on desktop */ - .row { - row-gap: 3rem; - } - - .btn-linkedin, - .btn-github-outline { - width: auto; - min-width: 140px; - } - - .btn-icon { - width: 20px; - height: 20px; - margin-right: 8px; - } - .language-selector-wrapper { - top: 20px; - right: 20px; - } - - .custom-select { - width: 150px; - } - - .custom-select-trigger { - padding: 10px 40px 10px 16px; - font-size: 15px; - background-position: right 12px center; - background-size: 12px; - } - - .custom-option { - padding: 10px 16px; - font-size: 15px; - } -} diff --git a/src/css/styles.css b/src/css/styles.css new file mode 100644 index 0000000..74da1bf --- /dev/null +++ b/src/css/styles.css @@ -0,0 +1,271 @@ +/* ================================================================= + VARIABLES - Design tokens and responsive values + ================================================================= */ + +:root { + /* Colors */ + --clr-navy: #070f2b; + --clr-gradient-mid: #3572ef; + --clr-gradient-end: #3abef9; + --clr-linkedin: #2856c7; + --clr-white: #ffffff; + + /* Responsive values - Mobile first */ + --lang-selector-top: 15px; + --lang-selector-right: 15px; + --lang-selector-width: 100px; + --lang-selector-padding: 6px 28px 6px 10px; + --lang-selector-font-size: 12px; + --lang-option-padding: 6px 10px; + --lang-arrow-size: 8px; + --lang-arrow-position: right 8px center; + --btn-icon-size: 18px; + --btn-icon-margin: 6px; + --container-padding: 60px 15px 1.5rem 15px; +} + +/* Desktop overrides */ +@media (min-width: 992px) { + :root { + --lang-selector-top: 20px; + --lang-selector-right: 20px; + --lang-selector-width: 150px; + --lang-selector-padding: 10px 40px 10px 16px; + --lang-selector-font-size: 15px; + --lang-option-padding: 10px 16px; + --lang-arrow-size: 12px; + --lang-arrow-position: right 12px center; + --btn-icon-size: 20px; + --btn-icon-margin: 8px; + --container-padding: 3rem 1.5rem; + } +} + +/* ================================================================= + BASE - Global styles + ================================================================= */ + +a { + text-decoration: none; +} + +body { + overflow-x: hidden; + max-width: 100vw; +} + +/* ================================================================= + HERO SECTION - Main landing area + ================================================================= */ + +.hero { + background: linear-gradient(300deg, var(--clr-navy), var(--clr-gradient-mid), var(--clr-gradient-end)); + background-size: 180% 180%; + animation: gradient-animation 10s ease infinite; + min-height: 100vh; + display: flex; + align-items: flex-start; + overflow-x: hidden; +} + +@keyframes gradient-animation { + 0%, 100% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } +} + +@media (min-width: 992px) { + .hero { + align-items: center; + } +} + +.hero__container { + padding: var(--container-padding); +} + +.hero__profile-image { + display: block; + margin: 0 auto; + width: 100%; + max-width: 350px; + border-radius: 2%; +} + +@media (max-width: 576px) { + .hero__profile-image { + width: calc(100vw - 30px); + max-width: calc(100vw - 30px); + } +} + +.hero__title { + color: var(--clr-navy); +} + +.hero__text { + color: var(--clr-white); +} + +/* ================================================================= + LANGUAGE SELECTOR - Dropdown component + ================================================================= */ + +.lang-selector { + position: absolute; + top: var(--lang-selector-top); + right: var(--lang-selector-right); + z-index: 1000; + width: var(--lang-selector-width); +} + +.lang-selector__trigger { + width: 100%; + padding: var(--lang-selector-padding); + font-size: var(--lang-selector-font-size); + font-weight: 600; + color: white; + background-color: rgba(255, 255, 255, 0.15); + background-image: url("../assets/images/arrow-down.svg"); + background-repeat: no-repeat; + background-position: var(--lang-arrow-position); + background-size: var(--lang-arrow-size); + backdrop-filter: blur(10px); + border: 2px solid rgba(255, 255, 255, 0.3); + border-radius: 12px; + cursor: pointer; + user-select: none; + transition: all 0.3s ease; +} + +.lang-selector__trigger:hover { + background-color: rgba(255, 255, 255, 0.25); + border-color: rgba(255, 255, 255, 0.5); + transform: translateY(-2px); +} + +.lang-selector--open .lang-selector__trigger { + background-color: rgba(255, 255, 255, 0.3); + border-color: white; + box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.2); +} + +.lang-selector__dropdown { + position: absolute; + top: calc(100% + 5px); + left: 0; + right: 0; + background-color: rgba(255, 255, 255, 0.15); + backdrop-filter: blur(10px); + border: 2px solid rgba(255, 255, 255, 0.3); + border-radius: 12px; + overflow: hidden; + opacity: 0; + visibility: hidden; + transform: translateY(-10px); + transition: all 0.3s ease; +} + +.lang-selector--open .lang-selector__dropdown { + opacity: 1; + visibility: visible; + transform: translateY(0); +} + +.lang-selector__option { + padding: var(--lang-option-padding); + font-size: var(--lang-selector-font-size); + font-weight: 600; + color: white; + cursor: pointer; + user-select: none; + transition: all 0.2s ease; +} + +.lang-selector__option:hover { + background-color: rgba(255, 255, 255, 0.2); +} + +.lang-selector__option--selected { + background-color: rgba(255, 255, 255, 0.25); +} + +/* ================================================================= + BUTTONS - LinkedIn and GitHub + ================================================================= */ + +.btn__icon { + width: var(--btn-icon-size); + height: var(--btn-icon-size); + margin-right: var(--btn-icon-margin); + filter: brightness(0) invert(1); +} + +/* LinkedIn button */ +.btn--linkedin { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + background-color: var(--clr-linkedin); + color: var(--clr-white); + border: 2px solid var(--clr-linkedin); +} + +.btn--linkedin:hover { + background-color: var(--clr-navy); + color: var(--clr-white); +} + +.btn--linkedin:focus, +.btn--linkedin:active { + background-color: var(--clr-white); + color: var(--clr-navy); + box-shadow: 0 0 0 0.2rem rgba(0, 119, 181, 0.25); +} + +.btn--linkedin:focus .btn__icon, +.btn--linkedin:active .btn__icon { + filter: brightness(0) invert(0); +} + +/* GitHub button */ +.btn--github { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + background-color: transparent; + color: var(--clr-white); + border: 2px solid var(--clr-white); +} + +.btn--github:hover { + background-color: var(--clr-white); + color: var(--clr-navy); + border-color: var(--clr-white); +} + +.btn--github:focus, +.btn--github:active { + background-color: var(--clr-navy); + color: var(--clr-white); + border-color: var(--clr-navy); +} + +.btn--github:hover .btn__icon { + filter: brightness(0) invert(0); +} + +.btn--github:focus .btn__icon, +.btn--github:active .btn__icon { + filter: brightness(0) invert(1); +} + +/* Desktop button sizing */ +@media (min-width: 992px) { + .btn--linkedin, + .btn--github { + width: auto; + min-width: 140px; + } +} diff --git a/src/index.html b/src/index.html index 73cc409..a0903c4 100644 --- a/src/index.html +++ b/src/index.html @@ -34,23 +34,21 @@ integrity="sha384-LN+7fdVzj6u52u30Kp6M/trliBMCMKTyK833zpbD+pXdCLuTusPj697FH4R/5mcr" crossorigin="anonymous" /> - + -
-
-
-
-
- English -
-
-
English
-
Español
-
Français
-
Português
-
+
+
+
+
+ English +
+
+
English
+
Español
+
Français
+
Português
@@ -58,18 +56,18 @@
Fernando Tona picture
-

Fernando Tona

-

+

Fernando Tona

+

Software Developer | .NET/C# | Azure

-

+

Problem-Solver with a Musician's Discipline

@@ -78,11 +76,11 @@

Fernando Tona

target="_blank" rel="noopener noreferrer" > - @@ -92,11 +90,11 @@

Fernando Tona

target="_blank" rel="noopener noreferrer" > - diff --git a/src/js/custom-select.js b/src/js/custom-select.js index 4efab1f..ac90d86 100644 --- a/src/js/custom-select.js +++ b/src/js/custom-select.js @@ -1,5 +1,5 @@ document.addEventListener("DOMContentLoaded", () => { - const customSelect = document.querySelector(".custom-select"); + const langSelector = document.querySelector(".lang-selector"); const trigger = document.getElementById("languageTrigger"); const options = document.getElementById("languageOptions"); const selectedLanguageSpan = document.getElementById("selectedLanguage"); @@ -13,25 +13,25 @@ document.addEventListener("DOMContentLoaded", () => { trigger.addEventListener("click", (e) => { e.stopPropagation(); - customSelect.classList.toggle("open"); + langSelector.classList.toggle("lang-selector--open"); }); document.addEventListener("click", () => { - customSelect.classList.remove("open"); + langSelector.classList.remove("lang-selector--open"); }); options.addEventListener("click", async (e) => { - if (e.target.classList.contains("custom-option")) { + if (e.target.classList.contains("lang-selector__option")) { const selectedValue = e.target.getAttribute("data-value"); - document.querySelectorAll(".custom-option").forEach((opt) => { - opt.classList.remove("selected"); + document.querySelectorAll(".lang-selector__option").forEach((opt) => { + opt.classList.remove("lang-selector__option--selected"); }); - e.target.classList.add("selected"); + e.target.classList.add("lang-selector__option--selected"); selectedLanguageSpan.textContent = languageNames[selectedValue]; - customSelect.classList.remove("open"); + langSelector.classList.remove("lang-selector--open"); await setLanguage(selectedValue); } @@ -40,6 +40,6 @@ document.addEventListener("DOMContentLoaded", () => { const currentLang = getCurrentLanguage(); selectedLanguageSpan.textContent = languageNames[currentLang]; document - .querySelector(`.custom-option[data-value="${currentLang}"]`) - ?.classList.add("selected"); + .querySelector(`.lang-selector__option[data-value="${currentLang}"]`) + ?.classList.add("lang-selector__option--selected"); }); diff --git a/src/js/custom-select.test.js b/src/js/custom-select.test.js index 6e63be3..4735de5 100644 --- a/src/js/custom-select.test.js +++ b/src/js/custom-select.test.js @@ -6,24 +6,24 @@ global.setLanguage = jest.fn().mockResolvedValue(undefined); global.getCurrentLanguage = jest.fn().mockReturnValue("en"); describe("Custom Select Component", () => { - let customSelect, trigger, selectedLanguageSpan; + let langSelector, trigger, selectedLanguageSpan; beforeEach(() => { document.body.innerHTML = ` -
-
+
+
English
-
-
English
-
Español
-
Français
-
Português
+
+
English
+
Español
+
Français
+
Português
`; - customSelect = document.querySelector(".custom-select"); + langSelector = document.querySelector(".lang-selector"); trigger = document.getElementById("languageTrigger"); selectedLanguageSpan = document.getElementById("selectedLanguage"); @@ -41,31 +41,31 @@ describe("Custom Select Component", () => { expect(getCurrentLanguage).toHaveBeenCalled(); expect(selectedLanguageSpan.textContent).toBe("English"); - const selectedOption = document.querySelector(".custom-option.selected"); + const selectedOption = document.querySelector(".lang-selector__option--selected"); expect(selectedOption.getAttribute("data-value")).toBe("en"); }); test("should toggle dropdown when trigger is clicked", () => { - expect(customSelect.classList.contains("open")).toBe(false); + expect(langSelector.classList.contains("lang-selector--open")).toBe(false); trigger.click(); - expect(customSelect.classList.contains("open")).toBe(true); + expect(langSelector.classList.contains("lang-selector--open")).toBe(true); trigger.click(); - expect(customSelect.classList.contains("open")).toBe(false); + expect(langSelector.classList.contains("lang-selector--open")).toBe(false); }); test("should close dropdown when clicking outside", () => { trigger.click(); - expect(customSelect.classList.contains("open")).toBe(true); + expect(langSelector.classList.contains("lang-selector--open")).toBe(true); document.body.click(); - expect(customSelect.classList.contains("open")).toBe(false); + expect(langSelector.classList.contains("lang-selector--open")).toBe(false); }); test("should change language and update UI when option is selected", async () => { - const spanishOption = document.querySelector('.custom-option[data-value="es"]'); - const englishOption = document.querySelector('.custom-option[data-value="en"]'); + const spanishOption = document.querySelector('.lang-selector__option[data-value="es"]'); + const englishOption = document.querySelector('.lang-selector__option[data-value="en"]'); trigger.click(); await spanishOption.click(); @@ -73,8 +73,8 @@ describe("Custom Select Component", () => { expect(setLanguage).toHaveBeenCalledWith("es"); expect(selectedLanguageSpan.textContent).toBe("Español"); - expect(spanishOption.classList.contains("selected")).toBe(true); - expect(englishOption.classList.contains("selected")).toBe(false); - expect(customSelect.classList.contains("open")).toBe(false); + expect(spanishOption.classList.contains("lang-selector__option--selected")).toBe(true); + expect(englishOption.classList.contains("lang-selector__option--selected")).toBe(false); + expect(langSelector.classList.contains("lang-selector--open")).toBe(false); }); }); From 5fa33f62e751eea979842674eb2768e1633d427d Mon Sep 17 00:00:00 2001 From: Fernando Tona Date: Sat, 18 Oct 2025 21:20:43 +0100 Subject: [PATCH 8/9] prettier format --- src/css/styles.css | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/css/styles.css b/src/css/styles.css index 74da1bf..f00db4b 100644 --- a/src/css/styles.css +++ b/src/css/styles.css @@ -9,7 +9,7 @@ --clr-gradient-end: #3abef9; --clr-linkedin: #2856c7; --clr-white: #ffffff; - + /* Responsive values - Mobile first */ --lang-selector-top: 15px; --lang-selector-right: 15px; @@ -59,7 +59,12 @@ body { ================================================================= */ .hero { - background: linear-gradient(300deg, var(--clr-navy), var(--clr-gradient-mid), var(--clr-gradient-end)); + background: linear-gradient( + 300deg, + var(--clr-navy), + var(--clr-gradient-mid), + var(--clr-gradient-end) + ); background-size: 180% 180%; animation: gradient-animation 10s ease infinite; min-height: 100vh; @@ -69,8 +74,13 @@ body { } @keyframes gradient-animation { - 0%, 100% { background-position: 0% 50%; } - 50% { background-position: 100% 50%; } + 0%, + 100% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } } @media (min-width: 992px) { From 136da1c95c3708c97bd1d6572956db49ec039910 Mon Sep 17 00:00:00 2001 From: Fernando Tona Date: Sat, 18 Oct 2025 21:42:50 +0100 Subject: [PATCH 9/9] clean up --- src/css/styles.css | 50 +++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/css/styles.css b/src/css/styles.css index f00db4b..9ad2fc0 100644 --- a/src/css/styles.css +++ b/src/css/styles.css @@ -1,16 +1,15 @@ -/* ================================================================= - VARIABLES - Design tokens and responsive values - ================================================================= */ +/* ============================================================ + VARIABLES - CSS custom properties for responsive design + ============================================================ */ :root { - /* Colors */ --clr-navy: #070f2b; --clr-gradient-mid: #3572ef; --clr-gradient-end: #3abef9; --clr-linkedin: #2856c7; --clr-white: #ffffff; - /* Responsive values - Mobile first */ + /* Mobile-first responsive values */ --lang-selector-top: 15px; --lang-selector-right: 15px; --lang-selector-width: 100px; @@ -41,9 +40,9 @@ } } -/* ================================================================= - BASE - Global styles - ================================================================= */ +/* ============================================================ + BASE + ============================================================ */ a { text-decoration: none; @@ -54,9 +53,9 @@ body { max-width: 100vw; } -/* ================================================================= - HERO SECTION - Main landing area - ================================================================= */ +/* ============================================================ + HERO SECTION + ============================================================ */ .hero { background: linear-gradient( @@ -95,7 +94,7 @@ body { .hero__profile-image { display: block; - margin: 0 auto; + margin: 0 auto 1.5rem auto; width: 100%; max-width: 350px; border-radius: 2%; @@ -114,11 +113,24 @@ body { .hero__text { color: var(--clr-white); + white-space: nowrap; /* Keep text on single line */ } -/* ================================================================= - LANGUAGE SELECTOR - Dropdown component - ================================================================= */ +@media (max-width: 576px) { + .hero__text { + font-size: 0.95rem; + } +} + +@media (max-width: 400px) { + .hero__text { + font-size: 0.85rem; + } +} + +/* ============================================================ + LANGUAGE SELECTOR (BEM naming: lang-selector) + ============================================================ */ .lang-selector { position: absolute; @@ -199,9 +211,9 @@ body { background-color: rgba(255, 255, 255, 0.25); } -/* ================================================================= - BUTTONS - LinkedIn and GitHub - ================================================================= */ +/* ============================================================ + BUTTONS (BEM naming: btn--linkedin, btn--github) + ============================================================ */ .btn__icon { width: var(--btn-icon-size); @@ -210,7 +222,6 @@ body { filter: brightness(0) invert(1); } -/* LinkedIn button */ .btn--linkedin { display: flex; align-items: center; @@ -238,7 +249,6 @@ body { filter: brightness(0) invert(0); } -/* GitHub button */ .btn--github { display: flex; align-items: center;