typst-web-template/lib/nav_menu.typ
Jean-Marie 'Histausse' Mineau 49c9b373d6
add animations to nav-menu
2026-03-18 22:34:12 +01:00

164 lines
5.2 KiB
Typst

#import "./custom_html.typ" as chtml
// Need inline svg for css color control, so no `image` element :(
#let menu-icon = html.elem(
"svg",
attrs: (
//width: "24",
//height: "24",
style: "width: 2em; height: 2em;",
fill: "currentcolor",
viewBox: "0 0 24 24",
xmlns: "http://www.w3.org/2000/svg"
),
html.elem("path", attrs: (
clip-rule: "evenodd",
fill-rule: "evenodd",
d: "M3 6.75A.75.75.0 013.75 6h16.5a.75.75.0 010 1.5H3.75A.75.75.0 013 6.75zM3 12a.75.75.0 01.75-.75h16.5a.75.75.0 010 1.5H3.75A.75.75.0 013 12zm0 5.25a.75.75.0 01.75-.75h16.5a.75.75.0 010 1.5H3.75A.75.75.0 013 17.25z"
))
)
#let close-icon = html.elem(
"svg",
attrs: (
//width: "24",
//height: "24",
style: "width: 2em; height: 2em;",
fill: "currentcolor",
viewBox: "0 0 24 24",
xmlns: "http://www.w3.org/2000/svg"
),
html.elem("path", attrs: (
clip-rule: "evenodd",
fill-rule: "evenodd",
d: "M5.47 5.47a.75.75.0 011.06.0L12 10.94l5.47-5.47a.75.75.0 111.06 1.06L13.06 12l5.47 5.47a.75.75.0 11-1.06 1.06L12 13.06l-5.47 5.47a.75.75.0 01-1.06-1.06L10.94 12 5.47 6.53a.75.75.0 010-1.06z"
))
)
/// Buttons to toggle the navigation menu.
/// aria-label is the accessibility label for the toggle.
/// menu-icon and close-icon are the content of the toggle deppending on
/// its state. Be carefull to keep it compatible with both light and dark
/// theme.
#let nav-menu-toggle(
aria-label: "Menu Toggle",
menu-icon: menu-icon,
close-icon: close-icon,
) = {
```raw-css
body:has(#nav-menu-toggle:checked) #icon-nav-menu { display: none; }
body:has(#nav-menu-toggle:checked) #icon-nav-menu-close { display: flex; }
body:has(#nav-menu-toggle:not(:checked)) #icon-nav-menu { display: flex; }
body:has(#nav-menu-toggle:not(:checked)) #icon-nav-menu-close { display: none; }
#nav-menu-toggle-label {
display: flex;
justify-content: center;
align-items: center;
&:has(input:focus-visible) icon-container {
outline: 2px solid var(--color-button-focus);
}
&:hover icon-container {
box-shadow: inset 0px 0px 0.4em 0px var(--color-button-shadow);
cursor: pointer;
}
icon-container {
padding: 0.2em;
border-radius: 0.5em;
justify-content: center;
align-items: center;
}
input {
opacity: 0;
position: absolute;
pointer-event: none;
}
}
```
html.label(id: "nav-menu-toggle-label", aria-label: aria-label, {
html.input(type: "checkbox", name: "nav-menu-toggle", id: "nav-menu-toggle")
chtml.icon-container(id: "icon-nav-menu", menu-icon)
chtml.icon-container(id: "icon-nav-menu-close", close-icon)
})
/*
<button class="btn btn-square" id="menu-toggle" aria-expanded="true" type="button" title="Menu">
<svg class="icon-menu" width="24" height="24" fill="currentcolor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path clip-rule="evenodd" fill-rule="evenodd" d="M3 6.75A.75.75.0 013.75 6h16.5a.75.75.0 010 1.5H3.75A.75.75.0 013 6.75zM3 12a.75.75.0 01.75-.75h16.5a.75.75.0 010 1.5H3.75A.75.75.0 013 12zm0 5.25a.75.75.0 01.75-.75h16.5a.75.75.0 010 1.5H3.75A.75.75.0 013 17.25z"></path>
</svg>
<svg class="icon-close hidden" width="24" height="24" fill="currentcolor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path clip-rule="evenodd" fill-rule="evenodd" d="M5.47 5.47a.75.75.0 011.06.0L12 10.94l5.47-5.47a.75.75.0 111.06 1.06L13.06 12l5.47 5.47a.75.75.0 11-1.06 1.06L12 13.06l-5.47 5.47a.75.75.0 01-1.06-1.06L10.94 12 5.47 6.53a.75.75.0 010-1.06z"></path>
</svg>
</button>
*/
}
#let nav-menu(body) = {
```raw-css
body:has(#nav-menu-toggle:not(:checked)) nav-menu {
/*display: none;*/
/* visibility: hidden + max-height: 0 ~= display: none
*/
visibility: hidden;
opacity: 0;
max-height: 0;
}
nav-menu {
border-top: solid 1px var(--color-border);
border-bottom: solid 1px var(--color-border);
text-align: center;
font-size: 1.25em;
padding-left: 2rem;
padding-right: 2rem;
max-height: 100%;
visibility: visible;
@starting-style {
opacity: 0;
max-height: 0;
}
/* Uses visibility instead of diplay for animation because Firefox
* preferes making slopeware instead of fixing this bug:
* https://bugzilla.mozilla.org/show_bug.cgi?id=1882408
*/
transition:
opacity 0.5s ease-in,
/*display 0.5s,*/
visibility 0.5s,
max-height 0.5s ease-out;
transition-behavior: allow-discrete;
ul {
list-style: none;
padding: 0px;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
li {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
a {
/* If a list item is considered only of a link, expend link to
* the whole item. */
margin: 0px;
display: block;
width: 100%;
height: 100%;
/* Unstyle link */
color: inherit;
text-decoration: inherit;
/* cursor: inherit; // we want to keep the clickable cursor */
}
}
li:hover {
border-top: solid 1px var(--color-border);
border-bottom: solid 1px var(--color-border);
}
}
```
chtml.nav-menu(body)
}