From a2a327ad6bbad8ad24bbe0f79932cd3b144bbe16 Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Sat, 12 Apr 2025 10:23:09 -0500 Subject: [PATCH] static navbar done --- css/colors.css | 18 ++++ css/container.css | 21 +++++ css/grid.css | 18 ---- css/hero.css | 13 +++ css/navbar.css | 211 +++++++++++++++++++++++++++++++++++++--------- js/navbar.js | 32 +++++-- tests/navbar.html | 29 +++---- 7 files changed, 258 insertions(+), 84 deletions(-) create mode 100644 css/colors.css create mode 100644 css/container.css create mode 100644 css/hero.css diff --git a/css/colors.css b/css/colors.css new file mode 100644 index 0000000..d49d6b5 --- /dev/null +++ b/css/colors.css @@ -0,0 +1,18 @@ +:root { + /* Colors - Base */ + --color-black-transparent-1: rgba(0, 0, 0, 0.065); + --color-black-transparent-2: rgba(0, 0, 0, 0.125); + --color-black-transparent-3: rgba(0, 0, 0, 0.2); + --color-blue: #08c; + --color-blue-dark: #0077b3; + --color-gray-dark: #777; + --color-gray-darker: #555; + --color-gray-darkest: #333; + --color-gray-light: #d4d4d4; + --color-gray-lighter: #e5e5e5; + --color-gray-lightest: #f2f2f2; + --color-gray-medium: #999999; + --color-white: #ffffff; + --color-white-off: #fafafa; + --color-white-transparent: rgba(255, 255, 255, 0.5); +} diff --git a/css/container.css b/css/container.css new file mode 100644 index 0000000..2996adc --- /dev/null +++ b/css/container.css @@ -0,0 +1,21 @@ +/* + Container + ======================================== +*/ + +.container { + width: 100%; + padding: 0 calc(var(--grid-gutter) / 2); + margin: 0 auto; +} + +@media (min-width: 576px) { .container { max-width: 540px; } } +@media (min-width: 768px) { .container { max-width: 720px; } } +@media (min-width: 992px) { .container { max-width: 960px; } } +@media (min-width: 1200px) { .container { max-width: 1170px; } } + +.container-fluid { + width: 100%; + padding: 0 calc(var(--grid-gutter) / 2); + margin: 0 auto; +} diff --git a/css/grid.css b/css/grid.css index 347ba14..578a8fb 100644 --- a/css/grid.css +++ b/css/grid.css @@ -7,24 +7,6 @@ --grid-gutter: 24px; } -/* Container */ -.container { - width: 100%; - padding: 0 calc(var(--grid-gutter) / 2); - margin: 0 auto; -} - -@media (min-width: 576px) { .container { max-width: 540px; } } -@media (min-width: 768px) { .container { max-width: 720px; } } -@media (min-width: 992px) { .container { max-width: 960px; } } -@media (min-width: 1200px) { .container { max-width: 1140px; } } - -.container-fluid { - width: 100%; - padding: 0 calc(var(--grid-gutter) / 2); - margin: 0 auto; -} - /* Row */ .row { display: flex; diff --git a/css/hero.css b/css/hero.css new file mode 100644 index 0000000..05c96a0 --- /dev/null +++ b/css/hero.css @@ -0,0 +1,13 @@ +/* + Hero + ======================================== +*/ + +.hero { + padding: 3.75rem; + margin-bottom: 2rem; + font-size: 1.25rem; + color: inherit; + background-color: #eeeeee; + border-radius: 4px; +} diff --git a/css/navbar.css b/css/navbar.css index c8fe45e..fcac1f3 100644 --- a/css/navbar.css +++ b/css/navbar.css @@ -1,63 +1,192 @@ /* Variables */ :root { + /* Dimensions */ --navbar-height: 40px; - --navbar-bg: #fafafa; - --navbar-bg-highlight: #f2f2f2; - --navbar-bg-active-top: #f2f2f2; - --navbar-bg-active-highlight: #e6e6e6; - --navbar-border: #d4d4d4; - --navbar-link: #777; - --navbar-link-hover: #333; - --navbar-link-active: #555; - --navbar-active: #08c; + + /* Colors - Component Specific */ + --navbar-active: var(--color-blue); --navbar-active-bg: transparent; - --navbar-brand-color: var(--navbar-link); + --navbar-bg: var(--color-white-off); + --navbar-bg-highlight: var(--color-gray-lightest); + --navbar-border: var(--color-gray-light); + --navbar-brand-color: var(--color-gray-dark); + --navbar-dropdown-bg: var(--color-white); + --navbar-dropdown-divider: var(--color-gray-lighter); + --navbar-dropdown-header: var(--color-gray-medium); + --navbar-dropdown-link: var(--color-gray-darkest); + --navbar-hover-bg-end: var(--color-blue-dark); + --navbar-hover-bg-start: var(--color-blue); + --navbar-hover-text: var(--color-white); + --navbar-item-active-bg: var(--color-gray-lighter); + --navbar-link: var(--color-gray-dark); + --navbar-link-active: var(--color-gray-darker); + --navbar-link-hover: var(--color-gray-darkest); + --navbar-shadow: var(--color-black-transparent-1); + --navbar-shadow-inset: var(--color-black-transparent-2); + --navbar-text-shadow: var(--color-white); } /* Navbar Base */ .navbar { - display: flex; - align-items: center; - justify-content: space-between; - min-height: var(--navbar-height); - margin-bottom: 1.25rem; - padding: 0 1.25rem; background-color: var(--navbar-bg); - background-image: linear-gradient(to bottom, white, var(--navbar-bg-highlight)); + background-image: linear-gradient(to bottom, var(--color-white), var(--navbar-bg-highlight)); border: 1px solid var(--navbar-border); border-radius: 4px; - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); -} - -.navbar .nav-group { + box-shadow: 0 1px 4px var(--navbar-shadow); display: flex; - align-items: center; -} - -.navbar .nav-menu { - display: flex; - align-items: center; - - li { - display: inline-flex; - margin-right: 1rem; - } - - li.active { - background-image: linear-gradient(to bottom, var(--navbar-bg-active-top), var(--navbar-bg-active-highlight)); - color: var(--navbar-link-active); - } + justify-content: space-between; + margin: 1.25rem 0; + min-height: var(--navbar-height); + padding: 0 1.25rem; } .navbar .brand { - display: block; - font-size: 20px; - font-weight: 200; + align-items: center; color: var(--navbar-brand-color); + display: flex; + font-size: 20px; + height: 100%; margin-right: 1.25rem; - text-shadow: 0 1px 0 white; + text-shadow: 0 1px 0 var(--navbar-text-shadow); &:hover, &:focus { text-decoration: none; } } + +.navbar .nav-group { + align-items: center; + display: flex; + min-height: 100%; +} + +.navbar .nav-menu { + align-items: center; + display: flex; + height: 100%; + + li { + align-items: center; + display: inline-flex; + height: 100%; + margin-right: 0.5rem; + padding: 0 0.5rem; + + a { + color: var(--navbar-link); + text-shadow: 0 1px 0 var(--navbar-text-shadow); + white-space: nowrap; + } + + &:hover a { + color: var(--navbar-link-hover); + } + } + + li.active { + background-color: var(--navbar-item-active-bg); + box-shadow: inset 0 3px 8px var(--navbar-shadow-inset); + + a { + color: var(--navbar-link-active); + } + } + + /* Dropdown */ + li.dropdown { + position: relative; + + &:has(i.caret) { + align-items: center; + display: inline-flex; + } + + i.caret { + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid currentColor; + bottom: 3px; + display: inline-block; + height: 0; + position: relative; + width: 0; + } + } + + li.dropdown .dropdown-menu { + background-color: var(--navbar-dropdown-bg); + border: 1px solid var(--color-black-transparent-3); + border-radius: 4px; + box-shadow: 0 5px 10px var(--color-black-transparent-3); + display: none; + font-size: 0.88rem; + left: 0; + list-style: none; + min-width: 160px; + padding: 0.5rem 0; + position: absolute; + top: 100%; + + li { + margin-right: 0; + padding: 0.3rem 1rem; + width: 100%; + + /* Link items in the dropdown */ + &:has(> a:first-child):hover { + background-image: linear-gradient(to bottom, var(--navbar-hover-bg-start), var(--navbar-hover-bg-end)); + + a { + color: var(--navbar-hover-text); + text-shadow: none; + } + } + + a { + color: var(--navbar-dropdown-link); + display: inline-block; + width: 100%; + } + + &:last-child { + margin-bottom: 0; + } + + &.divider { + background-color: var(--navbar-dropdown-divider); + display: block; + height: 1px; + margin: 0.5rem 0; + overflow: hidden; + padding: 0; + } + + &.nav-header { + color: var(--navbar-dropdown-header); + display: block; + font-size: 0.7rem; + font-weight: bold; + text-shadow: 0 1px 0 var(--color-white-transparent); + text-transform: uppercase; + } + } + + &.caret::before { + background-color: var(--navbar-dropdown-bg); + border-color: var(--color-black-transparent-3) var(--navbar-dropdown-bg) var(--navbar-dropdown-bg) var(--color-black-transparent-3); + border-style: solid; + border-width: 1px; + content: ''; + height: 10px; + left: 9px; + position: absolute; + top: -5px; + transform: rotate(45deg); + width: 10px; + } + } + + li.dropdown.open .dropdown-menu { + display: block; + } +} diff --git a/js/navbar.js b/js/navbar.js index 2f562d4..f933a52 100644 --- a/js/navbar.js +++ b/js/navbar.js @@ -2,14 +2,28 @@ Navbar JavaScript ======================================== */ -document.addEventListener('DOMContentLoaded', function() { - // Mobile menu toggle - const btnNavbar = document.querySelector('.btn-navbar'); - const navCollapse = document.querySelector('.nav-collapse'); - if (btnNavbar && navCollapse) { - btnNavbar.addEventListener('click', function() { - navCollapse.classList.toggle('active'); - }); - } +document.addEventListener('DOMContentLoaded', () => { + document.querySelectorAll('.dropdown').forEach(dropdown => { + const toggle = dropdown.querySelector('.dropdown-toggle'); + const mode = dropdown.getAttribute('data-dropdown') || 'click'; + + if (mode === 'hover') { + dropdown.addEventListener('mouseenter', () => dropdown.classList.add('open')); + dropdown.addEventListener('mouseleave', () => dropdown.classList.remove('open')); + } else { + toggle.addEventListener('click', e => { + e.preventDefault(); + dropdown.classList.toggle('open'); + }); + } + }); + + document.addEventListener('click', e => { + if (!e.target.closest('.dropdown-toggle')) { + document.querySelectorAll('.dropdown:not([data-dropdown="hover"])').forEach(dropdown => { + if (!dropdown.contains(e.target)) dropdown.classList.remove('open'); + }); + } + }); }); diff --git a/tests/navbar.html b/tests/navbar.html index f7c2c9c..d0801c7 100644 --- a/tests/navbar.html +++ b/tests/navbar.html @@ -4,22 +4,14 @@ Navbar + + + - +
-
+

Standard Navbar Demo

This demonstrates the default navbar style with rounded corners and a bottom margin.

The standard navbar scrolls with the page content.

+
- +