Compare commits

..

3 Commits

Author SHA1 Message Date
f17d48030c skip link 2026-01-02 17:52:59 -08:00
b479c59174 Merge branch 'main' into dropdown 2026-01-02 17:19:25 -08:00
0e561c888a dropdown take one needs review 2026-01-02 17:17:35 -08:00
6 changed files with 248 additions and 55 deletions

View File

@ -15,23 +15,23 @@
<meta property="og:description" content="card one's travels | siblinghood of the traveling greeting card" /> <meta property="og:description" content="card one's travels | siblinghood of the traveling greeting card" />
<meta property="og:image" content="/img/logo-light.png" /> <meta property="og:image" content="/img/logo-light.png" />
<meta property="og:image:alt" content="blue and gold icon showing a greeting card with wings" /> <meta property="og:image:alt" content="blue and gold icon showing a greeting card with wings" />
<!-- CSS --> <!-- CSS -->
<link rel="stylesheet" href="/styles/main.css"> <link rel="stylesheet" href="/styles/main.css">
<link rel="stylesheet" href="/styles/cards.css"> <link rel="stylesheet" href="/styles/cards.css">
<link rel="stylesheet" href="/styles/nav.css">
<!-- JS -->
<script src="/scripts/nav.js" defer></script>
</head> </head>
<body> <body>
<header> <header>
<nav> <nav id="top-nav"><!-- auto populated by nav.js --></nav>
<ul>
<li><a href="/">home</a></li>
<li><a href="/card-two">card two</a></li>
</ul>
</nav>
<img id="logo-light" src="/img/logo-light.png" alt="blue and gold icon showing a greeting card with wings" /> <img id="logo-light" src="/img/logo-light.png" alt="blue and gold icon showing a greeting card with wings" />
<img id="logo-dark" src="/img/logo-dark.png" alt="blue and gold icon showing a greeting card with wings" /> <img id="logo-dark" src="/img/logo-dark.png" alt="blue and gold icon showing a greeting card with wings" />
</header> </header>
<main> <main id="main">
<h1>The Travels of <span class="card">Card One</span></h1> <h1>The Travels of <span class="card">Card One</span></h1>
<p><span class="card">Card one</span> has 16 total recipients. Its journey began in late December, 2025.</p> <p><span class="card">Card one</span> has 16 total recipients. Its journey began in late December, 2025.</p>

View File

@ -15,23 +15,23 @@
<meta property="og:description" content="card two's travels | siblinghood of the traveling greeting card" /> <meta property="og:description" content="card two's travels | siblinghood of the traveling greeting card" />
<meta property="og:image" content="/img/logo-light.png" /> <meta property="og:image" content="/img/logo-light.png" />
<meta property="og:image:alt" content="blue and gold icon showing a greeting card with wings" /> <meta property="og:image:alt" content="blue and gold icon showing a greeting card with wings" />
<!-- CSS --> <!-- CSS -->
<link rel="stylesheet" href="/styles/main.css"> <link rel="stylesheet" href="/styles/main.css">
<link rel="stylesheet" href="/styles/cards.css"> <link rel="stylesheet" href="/styles/cards.css">
<link rel="stylesheet" href="/styles/nav.css">
<!-- JS -->
<script src="/scripts/nav.js" defer></script>
</head> </head>
<body> <body>
<header> <header>
<nav> <nav id="top-nav"><!-- auto populated by nav.js --></nav>
<ul>
<li><a href="/">home</a></li>
<li><a href="/card-one">card one</a></li>
</ul>
</nav>
<img id="logo-light" src="/img/logo-light.png" alt="blue and gold icon showing a greeting card with wings" /> <img id="logo-light" src="/img/logo-light.png" alt="blue and gold icon showing a greeting card with wings" />
<img id="logo-dark" src="/img/logo-dark.png" alt="blue and gold icon showing a greeting card with wings" /> <img id="logo-dark" src="/img/logo-dark.png" alt="blue and gold icon showing a greeting card with wings" />
</header> </header>
<main> <main id="main">
<h1>The Travels of <span class="card">Card Two</span></h1> <h1>The Travels of <span class="card">Card Two</span></h1>
<p><span class="card">Card two</span> has 16 total recipients.</p> <p><span class="card">Card two</span> has 16 total recipients.</p>

View File

@ -15,23 +15,23 @@
<meta property="og:description" content="Siblinghood of the Traveling Greeting Card" /> <meta property="og:description" content="Siblinghood of the Traveling Greeting Card" />
<meta property="og:image" content="/img/logo-light.png" /> <meta property="og:image" content="/img/logo-light.png" />
<meta property="og:image:alt" content="blue and gold icon showing a greeting card with wings" /> <meta property="og:image:alt" content="blue and gold icon showing a greeting card with wings" />
<!-- CSS --> <!-- CSS -->
<link rel="stylesheet" href="/styles/main.css"> <link rel="stylesheet" href="/styles/main.css">
<link rel="stylesheet" href="/styles/nav.css">
<!-- JS -->
<script src="/scripts/nav.js" defer></script>
</head> </head>
<body> <body>
<header> <header>
<nav> <nav id="top-nav"><!-- auto populated by nav.js --></nav>
<ul>
<li><a href="/card-one">card one</a></li>
<li><a href="/card-two">card two</a></li>
</ul>
</nav>
<img id="logo-light" src="/img/logo-light.png" alt="blue and gold icon showing a greeting card with wings" /> <img id="logo-light" src="/img/logo-light.png" alt="blue and gold icon showing a greeting card with wings" />
<img id="logo-dark" src="/img/logo-dark.png" alt="blue and gold icon showing a greeting card with wings" /> <img id="logo-dark" src="/img/logo-dark.png" alt="blue and gold icon showing a greeting card with wings" />
</header> </header>
<main> <main id="main">
<h1>Siblinghood of the Traveling Greeting Card</h1> <h1>Siblinghood of the Traveling Greeting Card</h1>
<p id="author">a community-building project by <a target="_blank" href="https://leecat.art">lee</a>.</p> <p id="author">a community-building project by <a target="_blank" href="https://leecat.art">lee</a>.</p>

131
scripts/nav.js Normal file
View File

@ -0,0 +1,131 @@
/* 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 constructSkipLink = function() {
const a = constructMenuLink("skip", "#main");
a.id = "skip";
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.type = "button";
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(constructSkipLink());
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();
});

View File

@ -26,6 +26,7 @@ body {
main { main {
width: 65%; width: 65%;
margin: 0 auto 2rem; margin: 0 auto 2rem;
scroll-margin-top: 1.5rem;
} }
@media (max-width: 650px) { @media (max-width: 650px) {
@ -123,40 +124,9 @@ time {
font-weight: 700; font-weight: 700;
} }
nav ul { button {
display: flex; cursor: pointer;
gap: 1rem; background-color: var(--color-bg);
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);
} }
header img { header img {

92
styles/nav.css Normal file
View File

@ -0,0 +1,92 @@
nav {
display: flex;
position: relative;
gap: 1rem;
justify-content: center;
margin: 1rem auto;
}
nav a,
nav button {
font-size: 1.4rem;
border: .1rem solid;
border-radius: .15rem;
padding: .15rem .3rem;
color: var(--color-accent);
text-decoration: none;
line-height: 2rem;
outline-offset: .1rem;
}
@media (max-width: 650px) {
nav a,
nav button {
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: .1rem solid var(--color-accent);
}
#skip {
left: -999px;
position: absolute;
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
z-index: -99;
background-color: var(--color-bg);
}
#skip:focus-visible {
left: 1rem;
width: auto;
height: auto;
overflow: auto;
z-index: 999;
}
#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: 10rem;
}
#dropdown {
position: relative;
display: inline-block;
min-width: 3rem;
}
nav ul.show {
display: block;
}
nav ul li {
margin: .5rem;
}
nav ul a {
display: inline-block;
background-color: var(--color-bg);
}