Skip to content

Commit 36be7a4

Browse files
committed
Add nice article navigation and auto aria-current=page
1 parent b3f5833 commit 36be7a4

File tree

9 files changed

+117
-75
lines changed

9 files changed

+117
-75
lines changed

assets/css/app.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ a:not([class]):not(.prose *) {
2828
color: var(--link--color);
2929
font-weight: var(--link--font-weight);
3030
text-decoration: var(--link--decoration);
31+
font-style: var(--link--font-style);
3132
}
3233
a:hover:not([class]):not(.prose *) {
3334
text-decoration: var(--link--decoration--hover);
@@ -44,6 +45,8 @@ a:hover:not([class]):not(.prose *) {
4445
}
4546
[data-links~='current-page-bold'] a[aria-current="page"] {
4647
--link--font-weight: bold;
48+
/* --link--font-style: italic; */
49+
/* border-left: 2px solid currentColor; */
4750
}
4851
[data-links~='block'] {
4952
--link--display: block;

assets/js/app.js

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import "phoenix_html";
88
import { Socket } from "phoenix";
99
import { LiveSocket } from "phoenix_live_view";
1010
import topbar from "../vendor/topbar";
11+
import "./customElements/navigable-article";
12+
import "./customElements/enhanced-navigation";
1113

1214
window.IMPORT = {
1315
DOMTesting: () => import("@testing-library/dom")
@@ -82,34 +84,3 @@ window.customElements.define('loading-stopwatch', class extends HTMLElement {
8284
}
8385
});
8486

85-
customElements.define('navigable-article', class extends HTMLElement {
86-
constructor() {
87-
super();
88-
89-
const document = this.ownerDocument;
90-
91-
function El(base, props, ...children) {
92-
const el = typeof base === 'string' ? document.createElement(base) : base.cloneNode(false);
93-
Object.assign(el, props);
94-
el.append(...children);
95-
return el;
96-
}
97-
98-
const aside = this.querySelector('aside');
99-
aside.hidden = false;
100-
101-
const navItemsSlot = this.querySelector('slot[name=nav-items]');
102-
const navItemsTemplates = navItemsSlot.querySelector('template').content;
103-
const linkTemplate = navItemsTemplates.querySelector('a');
104-
const ulTemplate = navItemsTemplates.querySelector('ul');
105-
const liTemplate = navItemsTemplates.querySelector('li');
106-
107-
const article = this.querySelector('article');
108-
const headings = article.querySelectorAll('h2');
109-
const items = Array.from(headings, (headingEl) => {
110-
return El(liTemplate, {}, El(linkTemplate, { href: '#' + headingEl.id }, headingEl.innerText));
111-
});
112-
113-
navItemsSlot.append(El(ulTemplate, {}, ...items));
114-
}
115-
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
customElements.define('enhanced-navigation', class extends HTMLElement {
2+
constructor() {
3+
super();
4+
5+
const document = this.ownerDocument;
6+
const features = this.dataset;
7+
8+
function El(base, props, ...children) {
9+
const el = typeof base === 'string' ? document.createElement(base) : base.cloneNode(false);
10+
Object.assign(el, props);
11+
el.append(...children);
12+
return el;
13+
}
14+
15+
if ('addArticleNavigation' in features) {
16+
const aside = this.querySelector('aside');
17+
aside.hidden = false;
18+
19+
const navItemsSlot = this.querySelector('slot[name=nav-items]');
20+
const navItemsTemplates = navItemsSlot.querySelector('template').content;
21+
const linkTemplate = navItemsTemplates.querySelector('a');
22+
const ulTemplate = navItemsTemplates.querySelector('ul');
23+
const liTemplate = navItemsTemplates.querySelector('li');
24+
25+
const article = this.querySelector('article');
26+
const headings = article.querySelectorAll('h2');
27+
const items = Array.from(headings, (headingEl) => {
28+
return El(liTemplate, {}, El(linkTemplate, { href: '#' + headingEl.id }, headingEl.innerText));
29+
});
30+
31+
navItemsSlot.append(El(ulTemplate, {}, ...items));
32+
}
33+
34+
if ('addAriaCurrentPage' in features) {
35+
const currentPath = document.location.pathname;
36+
for (const link of this.querySelectorAll(`a[href="${currentPath}"`)) {
37+
link.ariaCurrent = "page";
38+
}
39+
}
40+
}
41+
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
customElements.define('navigable-article', class extends HTMLElement {
2+
constructor() {
3+
super();
4+
5+
const document = this.ownerDocument;
6+
7+
function El(base, props, ...children) {
8+
const el = typeof base === 'string' ? document.createElement(base) : base.cloneNode(false);
9+
Object.assign(el, props);
10+
el.append(...children);
11+
return el;
12+
}
13+
14+
const aside = this.querySelector('aside');
15+
aside.hidden = false;
16+
17+
const navItemsSlot = this.querySelector('slot[name=nav-items]');
18+
const navItemsTemplates = navItemsSlot.querySelector('template').content;
19+
const linkTemplate = navItemsTemplates.querySelector('a');
20+
const ulTemplate = navItemsTemplates.querySelector('ul');
21+
const liTemplate = navItemsTemplates.querySelector('li');
22+
23+
const article = this.querySelector('article');
24+
const headings = article.querySelectorAll('h2');
25+
const items = Array.from(headings, (headingEl) => {
26+
return El(liTemplate, {}, El(linkTemplate, { href: '#' + headingEl.id }, headingEl.innerText));
27+
});
28+
29+
navItemsSlot.append(El(ulTemplate, {}, ...items));
30+
}
31+
});

lib/components_guide_web/controllers/accessibility_first_controller.ex

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,6 @@ defmodule ComponentsGuideWeb.AccessibilityFirstView do
5858
use ComponentsGuideWeb.Snippets
5959
use Phoenix.HTML
6060

61-
def render_sidebar(_assigns) do
62-
render("content_nav.html")
63-
end
64-
65-
def sidebar(assigns = %{article: "content"}) do
66-
~H"""
67-
<%= render_slot(@inner_block, render("content_nav.html")) %>
68-
"""
69-
end
70-
71-
def sidebar(assigns), do: ~H""
72-
7361
# def collected_image(conn, image_name) do
7462
# %{static_path: path_to_image, width: width, height: height} = render(image_name)
7563
# url = Routes.static_path(conn, "/" <> path_to_image)

lib/components_guide_web/templates/accessibility_first/_nav.html.eex

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
<nav class="pt-6 pb-4">
2-
<ul y-y x-x=md class="flex-wrap gap-4 text-xl font-bold" data-links="p-3">
1+
<nav>
2+
<p class="px-2 pb-6 mb-6 text-5xl text-violet-200 border-b-4 border-current"><%= "Accessibility-First" %></p>
3+
<ul class="text-xl" data-links="block p-2 current-page-bold">
34
<li><%= link("Why?", to: '/accessibility-first') %>
45
<li><%= link("Navigation", to: '/accessibility-first/navigation') %>
56
<li><%= link("Landmarks", to: '/accessibility-first/landmarks') %>

lib/components_guide_web/templates/accessibility_first/_top.html.eex

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,18 @@
33
<span class="mr-1 text-5xl">🔊🥇</span>
44
<span><%= "Accessibility-First" %></span>
55
</h1>
6-
<%= render ComponentsGuideWeb.AccessibilityFirstView, "_nav.html" %>
6+
<nav class="pt-6 pb-4">
7+
<ul y-y x-x="md" class="flex-wrap gap-4 text-xl font-bold" data-links="p-3">
8+
<li><%= link("Why?", to: '/accessibility-first') %>
9+
<li><%= link("Navigation", to: '/accessibility-first/navigation') %>
10+
<li><%= link("Landmarks", to: '/accessibility-first/landmarks') %>
11+
<li><%= link("Content", to: '/accessibility-first/content') %>
12+
<li><%= link("Forms", to: '/accessibility-first/forms') %>
13+
<li><%= link("All Roles", to: '/accessibility-first/roles') %>
14+
<li><%= link("Accessible Name", to: '/accessibility-first/accessible-name') %>
15+
<li><%= link("Testing with Playwright", to: '/accessibility-first/playwright') %>
16+
<li><%= link("Properties", to: '/accessibility-first/properties-cheatsheet') %>
17+
<li><%= link("Widgets", to: '/accessibility-first/widgets-cheatsheet') %>
18+
</ul>
19+
</nav>
720
</div>

lib/components_guide_web/templates/accessibility_first/content_nav.html.md

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
1-
<%= render view_module(@conn), "_header.html" %>
2-
3-
<div class="text-base lg:text-lg flex items-stretch bg-gray-900">
4-
<.sidebar let={nav} article={@article}>
5-
<nav class="text-white w-48 lg:w-64 bg-gray-800">
6-
<div class="sticky top-0">
7-
<%= nav %>
8-
</div>
9-
</nav>
10-
</.sidebar>
11-
12-
<div class="mx-auto flex-shrink">
13-
<div class="max-w-xl lg:max-w-4xl px-6 pt-8 pb-16 text-white">
14-
<article class="prose md:prose-xl prose-invert max-w-4xl mx-auto py-16">
15-
<%= render(view_module(@conn), @article <> ".html", conn: @conn) %>
16-
</article>
1+
<enhanced-navigation class="flex flex-col" data-add-aria-current-page data-add-article-navigation>
2+
<div class="mx-auto grid-flow-col md:grid md:grid-cols-[20rem_minmax(0,var(--max-width))] xl:grid-cols-[20rem_minmax(0,var(--max-width))_18rem] gap-8" style="--max-width: 46em">
3+
<div class="md:sticky top-0 md:h-screen pl-4 pt-16 text-white">
4+
<%= render view_module(@conn), "_nav.html", conn: @conn %>
175
</div>
6+
<article class="text-white bg-gray-900 px-4 md:px-0">
7+
<div class="prose md:prose-xl prose-invert max-w-4xl mx-auto py-16">
8+
<%= render(view_module(@conn), @article <> ".html", conn: @conn) %>
9+
</div>
10+
</article>
11+
<aside class="sticky top-0 h-screen hidden xl:block" hidden>
12+
<nav class="pt-16 text-gray-200">
13+
<div class="pl-5 pb-2 font-bold uppercase text-white">On this page</div>
14+
<slot name="nav-items">
15+
<template>
16+
<ul class="list-none">
17+
<li class="border-l-4 border-gray-800 hover:border-blue-400"></li>
18+
</ul>
19+
<a href="#" class="inline-flex py-1 pl-4 hover:text-blue-400"></a>
20+
</template>
21+
</slot>
22+
</nav>
23+
</aside>
1824
</div>
19-
</div>
25+
</enhanced-navigation>

0 commit comments

Comments
 (0)