From 0e561c888a0487e1d8d2315063c92f6f74343917 Mon Sep 17 00:00:00 2001 From: Lee Cattarin Date: Fri, 2 Jan 2026 17:17:35 -0800 Subject: [PATCH] dropdown take one needs review --- card-one/index.html | 12 ++--- card-two/index.html | 12 ++--- index.html | 12 ++--- scripts/nav.js | 122 ++++++++++++++++++++++++++++++++++++++++++++ styles/main.css | 37 ++------------ styles/nav.css | 73 ++++++++++++++++++++++++++ 6 files changed, 216 insertions(+), 52 deletions(-) create mode 100644 scripts/nav.js create mode 100644 styles/nav.css diff --git a/card-one/index.html b/card-one/index.html index 75302dc..94cc6ff 100644 --- a/card-one/index.html +++ b/card-one/index.html @@ -15,18 +15,18 @@ + + + + +
- + blue and gold icon showing a greeting card with wings blue and gold icon showing a greeting card with wings diff --git a/card-two/index.html b/card-two/index.html index 6ba6414..5b476e1 100644 --- a/card-two/index.html +++ b/card-two/index.html @@ -15,18 +15,18 @@ + + + + +
- + blue and gold icon showing a greeting card with wings blue and gold icon showing a greeting card with wings diff --git a/index.html b/index.html index f99fcef..ba11ab4 100644 --- a/index.html +++ b/index.html @@ -15,17 +15,17 @@ + + + + +
- + blue and gold icon showing a greeting card with wings blue and gold icon showing a greeting card with wings diff --git a/scripts/nav.js b/scripts/nav.js new file mode 100644 index 0000000..16996ca --- /dev/null +++ b/scripts/nav.js @@ -0,0 +1,122 @@ +/* Nav construction */ +const cards = [ + { + title: "card one", + href: "/card-one/" + }, + { + title: "card two", + href: "/card-two/" + } +] + +const constructMenuLink = function(title, href) { + const path = window.location.pathname; + + const a = document.createElement("a"); + a.href = href; + a.title = title; + a.innerHTML = title; + if (path === href) a.id = "current-page"; + + return a; +} + +const constructDropdown = function() { + const div = document.createElement("div"); + div.id = "dropdown"; + + const button = document.createElement("button"); + button.innerHTML = "cards ⮷"; + button.id="drop-button"; + button.ariaLabel = "card submenu"; + button.ariaExpanded = "false"; + button.setAttribute("aria-controls", "drop-content"); + div.append(button); + + const ul = document.createElement("ul"); + ul.id = "drop-content"; + ul.ariaHidden = "true"; + + for (const card of cards) { + const li = document.createElement("li"); + li.append(constructMenuLink(card.title, card.href)); + ul.append(li); + } + + div.append(ul); + return div; +} + +const constructNav = function() { + const nav = document.getElementById("top-nav"); + nav.append(constructMenuLink("home", "/")); + nav.append(constructDropdown()); +} + +constructNav(); + +/* Dropdown handling */ + +const dropdown = document.getElementById("dropdown"); +const dropdownButton = document.getElementById("drop-button"); +const dropdownContent = document.getElementById("drop-content"); + +const dropdownItems = dropdownContent.querySelectorAll("a"); +const firstDropdownItem = dropdownItems[0]; +const lastDropdownItem = dropdownItems[dropdownItems.length - 1]; + +const openDropdown = function() { + dropdownContent.classList.add("show"); + dropdownContent.setAttribute("aria-hidden", "false"); + dropdownButton.setAttribute("aria-expanded", "true"); +} + +const closeDropdown = function() { + if (dropdownButton.ariaExpanded === "true") { + dropdownContent.classList.remove("show"); + dropdownContent.setAttribute("aria-hidden", "true"); + dropdownButton.setAttribute("aria-expanded", "false"); + + /* focus the button again */ + dropdownButton.focus(); + } +} + +dropdownButton.addEventListener("click", (event) => { + if (dropdownButton.ariaExpanded === "false") openDropdown(); + else closeDropdown(); +}); + +dropdownButton.addEventListener("keydown", (event) => { + if (event.key === "Enter" || event.key === " ") { // Space or Enter key + event.preventDefault(); // Prevent the default action to stop scrolling when pressing Space + if (dropdownButton.ariaExpanded === "false") { + openDropdown(); + } else { + closeDropdown(); + } + } +}); + +firstDropdownItem.addEventListener("keydown", (event) => { + if (event.key === "Tab" && event.shiftKey) { + event.preventDefault(); + closeDropdown(); + } +}); + +lastDropdownItem.addEventListener("keydown", (event) => { + if (event.key === "Tab" && !event.shiftKey) { + event.preventDefault(); + closeDropdown(); + } +}); + +document.addEventListener("keydown", (event) => { + if (event.key === "Escape") closeDropdown(); +}); + +window.addEventListener("click", (event) => { + if (!event.target.matches("#drop-button")) closeDropdown(); +}); diff --git a/styles/main.css b/styles/main.css index 706691b..e055a53 100644 --- a/styles/main.css +++ b/styles/main.css @@ -123,40 +123,9 @@ time { font-weight: 700; } -nav ul { - display: flex; - gap: 1rem; - list-style: none; - justify-content: center; - margin: 1rem auto; -} - -nav a { - font-size: 1.4rem; - border: 1px solid; - border-radius: .15rem; - padding: .15rem .3rem; - color: var(--color-accent); - text-decoration: none; -} - -@media (max-width: 650px) { - nav a { - font-size: 1.1rem; - } -} - -@media (any-hover: hover) { - nav a:hover { - color: var(--color-bg); - background-color: var(--color-accent); - } -} - -nav a:focus-visible { - outline: none; - color: var(--color-bg); - background-color: var(--color-accent); +button { + cursor: pointer; + background-color: var(--color-bg); } header img { diff --git a/styles/nav.css b/styles/nav.css new file mode 100644 index 0000000..5a416b7 --- /dev/null +++ b/styles/nav.css @@ -0,0 +1,73 @@ +nav { + display: flex; + gap: 1rem; + justify-content: center; + margin: 1rem auto; +} + +nav a, +nav button { + font-size: 1.4rem; + border: 1px solid; + border-radius: .15rem; + padding: .15rem .3rem; + color: var(--color-accent); + text-decoration: none; + line-height: 2rem; +} + +@media (max-width: 650px) { + nav a { + font-size: 1.1rem; + } +} + +@media (any-hover: hover) { + nav a:hover, + nav button:hover { + color: var(--color-bg); + background-color: var(--color-accent); + border-color: var(--color-accent); + } +} + +nav a:focus-visible, +nav button:focus-visible { + outline: none; + color: var(--color-bg); + background-color: var(--color-accent); + border-color: var(--color-accent); +} + +#current-page { + border-right-width: .5rem; + border-left-width: .5rem; +} + +nav ul { + list-style: none; + display: none; + position: absolute; + z-index: 1; + margin: 0 0 0 1rem; + min-width: 8rem; +} + +#dropdown { + position: relative; + display: inline-block; + min-width: 3rem; +} + +nav ul.show { + display: block; +} + +nav ul li { + margin: .25rem; +} + +nav ul a { + display: inline-block; + background-color: var(--color-bg); +}