Skip to content

Commit

Permalink
tree-menu component
Browse files Browse the repository at this point in the history
  • Loading branch information
oscarotero committed Aug 26, 2024
1 parent 4f70b7c commit 6cf4079
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ project adheres to [Semantic Versioning](http://semver.org/).

## [0.10.0] - Unreleased
### Changed
- Replaced static menu with the new `tree-menu` web component for build performance.
- Addapt to a BREAKING CHANGE introduced in Lume 1.3.

### Removed
Expand Down
2 changes: 2 additions & 0 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export default function (options?: Options) {
"_includes/layout.vto",
"_includes/templates/menu_item.vto",
"_includes/templates/menu.vto",
"menu.js",
"menu.page.ts",
"styles.css",
];

Expand Down
1 change: 1 addition & 0 deletions plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export default function (options: Options = {}) {
.data("layout", "layout.vto")
.data("order", 0)
.mergeKey("extra_head", "stringArray")
.copy("menu.js")
.copy([
".jpg",
".jpeg",
Expand Down
14 changes: 9 additions & 5 deletions src/_includes/css/menu.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,18 @@
}

.menu {
list-style: none;
margin: 0;
padding: 0;
font: var(--font-small);
color: var(--color-dim);
display: block;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: var(--color-dim) var(--color-background);
font: var(--font-small);
color: var(--color-dim);
}

.menu > ul {
list-style: none;
margin: 0;
padding: 0;

& ul {
list-style: none;
Expand Down
1 change: 1 addition & 0 deletions src/_includes/layout.vto
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<meta name="theme-color" content="hsl(220, 20%, 10%)" media="(prefers-color-scheme: dark)">

<link rel="stylesheet" href="/styles.css">
<script type="module" src="/menu.js"></script>
<link rel="canonical" href="{{ url |> url(true) }}">
{{ it.extra_head?.join("\n") }}
</head>
Expand Down
7 changes: 1 addition & 6 deletions src/_includes/templates/menu.vto
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@
{{ /if }}
{{ /if }}

<ul class="menu">
{{ for item of nav.menu("/", "", "order=asc basename=asc").children }}
<li>
{{ include "templates/menu_item.vto" { item } }}
</li>
{{ /for }}
<tree-menu class="menu" data-url="{{ '/menu.json' |> url }}"></tree-menu>

{{- for link of menu_links }}
<li>
Expand Down
28 changes: 0 additions & 28 deletions src/_includes/templates/menu_item.vto

This file was deleted.

70 changes: 70 additions & 0 deletions src/menu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
customElements.define(
"tree-menu",
class extends HTMLElement {
constructor() {
super();
const ul = document.createElement("ul");
this.appendChild(ul);
this.loadMenu(ul);
}

render(menu, ul, url) {
const fragment = document.createDocumentFragment();

for (const { data, children } of menu) {
let li = document.createElement("li");
fragment.appendChild(li);
if (children) {
li.innerHTML = `<details><summary></summary></details>`;
li = li.querySelector("summary");
}

if (data.url) {
const a = document.createElement("a");
a.href = data.url;
a.textContent = data.title || data.basename;

if (data.url === url) {
a.setAttribute("aria-current", "page");
}
li.appendChild(a);
} else {
li.innerHTML = `<strong>${data.title || data.basename}</strong>`;
}

if (children) {
const ul = document.createElement("ul");
li.parentElement.appendChild(ul);
this.render(children, ul, url);
}
}

ul.appendChild(fragment);
}

async loadMenu(ul) {
const url = this.dataset.url;
const response = await fetch(url);
const data = await response.json();
this.render(data, ul, decodeURIComponentSafe(location.pathname));
const current = ul.querySelector("[aria-current]");

if (current) {
let parent = current.parentElement;

while (parent) {
if (parent.tagName === "DETAILS") {
parent.open = true;
parent = parent.parentElement.parentElement;
} else {
parent = parent.parentElement;
}
}
}
}
},
);

function decodeURIComponentSafe(path) {
return decodeURIComponent(path.replace(/%(?![0-9a-fA-F]+)/g, "%25"));
}
7 changes: 7 additions & 0 deletions src/menu.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const url = "/menu.json";

export default function ({ nav }: Lume.Data) {
const menu = nav.menu("/", "", "order=asc basename=asc").children;

return JSON.stringify(menu, null, 2);
}

0 comments on commit 6cf4079

Please sign in to comment.