feat: mobile nav with animations
This commit is contained in:
parent
a839560bff
commit
3bf65ae7ab
4 changed files with 97 additions and 23 deletions
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
import HeaderLink from "./HeaderLink.astro";
|
||||
---
|
||||
|
||||
<header class="mb-8 w-full lg:w-[768px] max-w-[calc(100%-2em)] lg:mx-auto">
|
||||
<nav>
|
||||
<div class="flex gap-4">
|
||||
<HeaderLink href="/">Home</HeaderLink>
|
||||
<HeaderLink href="/blog">Blog</HeaderLink>
|
||||
<HeaderLink href="/projects">Projects</HeaderLink>
|
||||
<HeaderLink href="/publications">Publications</HeaderLink>
|
||||
<HeaderLink href="/contact">Contact</HeaderLink>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
78
src/components/NavMenu.astro
Normal file
78
src/components/NavMenu.astro
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import HeaderLink from "./HeaderLink.astro";
|
||||
---
|
||||
|
||||
<header
|
||||
class="mb-8 w-full lg:w-[768px] max-w-[calc(100%-2em)] lg:mx-auto overflow-scroll hidden lg:block"
|
||||
>
|
||||
<nav>
|
||||
<div class="flex gap-4">
|
||||
<HeaderLink href="/">Home</HeaderLink>
|
||||
<HeaderLink href="/blog">Blog</HeaderLink>
|
||||
<HeaderLink href="/projects">Projects</HeaderLink>
|
||||
<HeaderLink href="/publications">Publications</HeaderLink>
|
||||
<HeaderLink href="/contact">Contact</HeaderLink>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<button id="menu" class="lg:hidden relative w-[30px] h-[30px]">
|
||||
<Icon
|
||||
name="mdi:menu"
|
||||
id="iconMenu"
|
||||
class="absolute inset-0 transition-all duration-300 ease-in-out"
|
||||
size={30}
|
||||
/>
|
||||
<Icon
|
||||
name="mdi:close"
|
||||
id="iconClose"
|
||||
class="absolute inset-0 opacity-0 rotate-90 transition-all duration-300 ease-in-out"
|
||||
size={30}
|
||||
/>
|
||||
</button>
|
||||
<header
|
||||
id="drawer"
|
||||
class="fixed top-16 right-0 h-full bg-neutral-50 shadow dark:bg-gray-700 p-6 rounded w-54 transform translate-x-full transition-transform duration-300 ease-in-out"
|
||||
>
|
||||
<div class="flex flex-col gap-4">
|
||||
<HeaderLink href="/">Home</HeaderLink>
|
||||
<HeaderLink href="/blog">Blog</HeaderLink>
|
||||
<HeaderLink href="/projects">Projects</HeaderLink>
|
||||
<HeaderLink href="/publications">Publications</HeaderLink>
|
||||
<HeaderLink href="/contact">Contact</HeaderLink>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<script>
|
||||
const menu = document.getElementById("menu");
|
||||
const drawer = document.getElementById("drawer");
|
||||
|
||||
function toggle() {
|
||||
drawer.classList.toggle("translate-x-full");
|
||||
document.body.classList.toggle("overflow-hidden");
|
||||
if (iconMenu.classList.contains("opacity-0")) {
|
||||
iconMenu.classList.remove("opacity-0", "rotate-90");
|
||||
iconClose.classList.add("opacity-0", "rotate-90");
|
||||
} else {
|
||||
iconMenu.classList.add("opacity-0", "rotate-90");
|
||||
iconClose.classList.remove("opacity-0", "rotate-90");
|
||||
}
|
||||
}
|
||||
|
||||
menu.addEventListener("click", () => {
|
||||
toggle();
|
||||
});
|
||||
|
||||
// click-away listener
|
||||
document.addEventListener("click", (event) => {
|
||||
console.log("click outside");
|
||||
if (
|
||||
!drawer.classList.contains("hidden") &&
|
||||
!drawer.contains(event.target) &&
|
||||
!menu.contains(event.target)
|
||||
) {
|
||||
toggle();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
@ -23,7 +23,12 @@ Pretty cool gimmick! This effectively binds the CV document to my personal websi
|
|||
|
||||
On this astro page, I have a route `/admin` which allows me to create a new verification id. This endpoint is secured with Cloudflare access.
|
||||
|
||||
<div align="center" style={{ width: '500px', margin: '0 auto' }}>
|
||||
<div style={{
|
||||
maxWidth: '500px',
|
||||
width: '100%',
|
||||
margin: '0 auto',
|
||||
textAlign: 'center'
|
||||
}}>
|
||||

|
||||
</div>
|
||||
|
||||
|
|
@ -100,7 +105,12 @@ if __name__ == "__main__":
|
|||
|
||||
Finally, I enter the generated sha256 hash and the PGP signature into the second page of the create verification workflow.
|
||||
|
||||
<div align="center" style={{ width: '500px', margin: '0 auto' }}>
|
||||
<div style={{
|
||||
maxWidth: '500px',
|
||||
width: '100%',
|
||||
margin: '0 auto',
|
||||
textAlign: 'center'
|
||||
}}>
|
||||

|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import BaseHead from "../components/BaseHead.astro";
|
||||
import Header from "../components/Header.astro";
|
||||
import NavMenu from "../components/NavMenu.astro";
|
||||
import Footer from "../components/Footer.astro";
|
||||
import { SITE_TITLE, SITE_DESCRIPTION } from "../consts";
|
||||
import DarkModeToggle from "../components/DarkModeToggle.astro";
|
||||
|
|
@ -36,13 +36,14 @@ const { title = SITE_TITLE, description = SITE_DESCRIPTION } = Astro.props;
|
|||
<!-- Mobile layout -->
|
||||
<div class="lg:hidden flex flex-col min-h-screen p-4">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="font-bold text-lg">
|
||||
<h2 class="font-bold text-lg mb-0">
|
||||
<a href="/">{SITE_TITLE}</a>
|
||||
</h2>
|
||||
<div class="flex items-center gap-4">
|
||||
<DarkModeToggle />
|
||||
<NavMenu />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Header />
|
||||
|
||||
<main class="flex-grow">
|
||||
<slot />
|
||||
|
|
@ -60,7 +61,7 @@ const { title = SITE_TITLE, description = SITE_DESCRIPTION } = Astro.props;
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<Header />
|
||||
<NavMenu />
|
||||
<main class="w-full lg:w-[768px] max-w-[calc(100%-2em)] mx-auto p-2">
|
||||
<slot />
|
||||
</main>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue