Leaflet Blog in Deno Fresh
1import { Footer } from "../components/footer.tsx";
2import type { ComponentChildren } from "preact";
3import { useEffect, useState } from "preact/hooks";
4
5export function Layout({ children }: { children: ComponentChildren }) {
6 const [isScrolled, setIsScrolled] = useState(false);
7 const [blogHovered, setBlogHovered] = useState(false);
8 const [aboutHovered, setAboutHovered] = useState(false);
9
10 // Get current path to determine active nav item
11 const path = typeof window !== "undefined" ? window.location.pathname : "";
12 const isActive = (href: string) => {
13 if (href === "/") {
14 return path === "/" || path.startsWith("/post/");
15 }
16 return path === href;
17 };
18
19 useEffect(() => {
20 const handleScroll = () => {
21 setIsScrolled(window.scrollY > 0);
22 };
23
24 window.addEventListener("scroll", handleScroll);
25 handleScroll(); // Check initial scroll position
26
27 return () => window.removeEventListener("scroll", handleScroll);
28 }, []);
29
30 return (
31 <div class="flex flex-col min-h-dvh">
32 <nav class="w-full sticky top-0 z-50 backdrop-blur-sm transition-[padding,border-color] duration-200">
33 <div class="relative">
34 <div
35 class="absolute inset-x-0 bottom-0 h-2 diagonal-pattern opacity-0 transition-opacity duration-300"
36 style={{ opacity: isScrolled ? 0.25 : 0 }}
37 />
38 <div class="max-w-screen-2xl mx-auto px-8 py-5 flex justify-between items-center">
39 <div class="flex items-center gap-7">
40 <a href="/" class="font-serif text-xl">
41 knotbin
42 </a>
43 <div class="h-4 w-px bg-slate-200 dark:bg-slate-700"></div>
44 <div class="text-base flex items-center gap-7">
45 <a
46 href="/"
47 class="relative group"
48 data-current={isActive("/")}
49 data-hovered={blogHovered}
50 onMouseEnter={() => setBlogHovered(true)}
51 onMouseLeave={() => setBlogHovered(false)}
52 >
53 <span class="opacity-50 group-hover:opacity-100 group-data-[current=true]:opacity-100 transition-opacity">
54 blog
55 </span>
56 <div class="absolute bottom-0 left-0 w-full h-px bg-current scale-x-0 group-hover:scale-x-100 group-data-[current=true]:scale-x-100 transition-transform duration-300 ease-in-out group-hover:origin-left group-data-[hovered=false]:origin-right" />
57 </a>
58 <a
59 href="/about"
60 class="relative group"
61 data-current={isActive("/about")}
62 data-hovered={aboutHovered}
63 onMouseEnter={() => setAboutHovered(true)}
64 onMouseLeave={() => setAboutHovered(false)}
65 >
66 <span class="opacity-50 group-hover:opacity-100 group-data-[current=true]:opacity-100 transition-opacity">
67 about
68 </span>
69 <div class="absolute bottom-0 left-0 w-full h-px bg-current scale-x-0 group-hover:scale-x-100 group-data-[current=true]:scale-x-100 transition-transform duration-300 ease-in-out group-hover:origin-left group-data-[hovered=false]:origin-right" />
70 </a>
71 </div>
72 </div>
73 </div>
74 </div>
75 </nav>
76
77 <main class="flex-1">{children}</main>
78
79 <Footer />
80 </div>
81 );
82}