File size: 4,349 Bytes
13ae717
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c9b2910
13ae717
 
 
 
 
 
 
 
 
 
c9b2910
13ae717
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
"use client";

import { useRef, useState } from "react";
import Image from "next/image";
import Link from "next/link";
import { useMount, useUnmount } from "react-use";
import classNames from "classnames";

import { Button } from "@/components/ui/button";
import Logo from "@/assets/logo.svg";
import { useUser } from "@/hooks/useUser";
import { UserMenu } from "@/components/user-menu";

const navigationLinks = [
  {
    name: "Create Website",
    href: "/projects/new",
  },
  {
    name: "Features",
    href: "#features",
  },
  {
    name: "Community",
    href: "#community",
  },
  {
    name: "Deploy",
    href: "#deploy",
  },
];

export default function Navigation() {
  const { openLoginWindow, user } = useUser();
  const [hash, setHash] = useState("");

  const selectorRef = useRef<HTMLDivElement>(null);
  const linksRef = useRef<HTMLLIElement[]>(
    new Array(navigationLinks.length).fill(null)
  );
  const [isScrolled, setIsScrolled] = useState(false);

  useMount(() => {
    const handleScroll = () => {
      const scrollTop = window.scrollY;
      setIsScrolled(scrollTop > 100);
    };

    const initialHash = window.location.hash;
    if (initialHash) {
      setHash(initialHash);
      calculateSelectorPosition(initialHash);
    }

    window.addEventListener("scroll", handleScroll);
  });

  useUnmount(() => {
    window.removeEventListener("scroll", () => {});
  });

  const handleClick = (href: string) => {
    setHash(href);
    calculateSelectorPosition(href);
  };

  const calculateSelectorPosition = (href: string) => {
    if (selectorRef.current && linksRef.current) {
      const index = navigationLinks.findIndex((l) => l.href === href);
      const targetLink = linksRef.current[index];
      if (targetLink) {
        const targetRect = targetLink.getBoundingClientRect();
        selectorRef.current.style.left = targetRect.left + "px";
        selectorRef.current.style.width = targetRect.width + "px";
      }
    }
  };

  return (
    <div
      className={classNames(
        "sticky top-0 z-10 transition-all duration-200 backdrop-blur-md",
        {
          "bg-black/30": isScrolled,
        }
      )}
    >
      <nav className="grid grid-cols-2 p-4 container mx-auto">
        <Link href="/" className="flex items-center gap-1">
          <Image
            src={Logo}
            className="w-9 mr-1"
            alt="DeepSite Logo"
            width={64}
            height={64}
          />
          <p className="font-sans text-white text-xl font-bold">DeepSite</p>
        </Link>
        <ul className="items-center justify-center gap-6 hidden">
          {navigationLinks.map((link) => (
            <li
              key={link.name}
              ref={(el) => {
                const index = navigationLinks.findIndex(
                  (l) => l.href === link.href
                );
                if (el && linksRef.current[index] !== el) {
                  linksRef.current[index] = el;
                }
              }}
              className="inline-block font-sans text-sm"
            >
              <Link
                href={link.href}
                className={classNames(
                  "text-neutral-500 hover:text-primary transition-colors",
                  {
                    "text-primary": hash === link.href,
                  }
                )}
                onClick={() => {
                  handleClick(link.href);
                }}
              >
                {link.name}
              </Link>
            </li>
          ))}
          <div
            ref={selectorRef}
            className={classNames(
              "h-1 absolute bottom-4 transition-all duration-200 flex items-center justify-center",
              {
                "opacity-0": !hash,
              }
            )}
          >
            <div className="size-1 bg-white rounded-full" />
          </div>
        </ul>
        <div className="flex items-center justify-end gap-2">
          {user ? (
            <UserMenu className="!pl-3 !pr-4 !py-2 !h-auto !rounded-lg" />
          ) : (
            <>
              <Button variant="link" size={"sm"} onClick={openLoginWindow}>
                Log In
              </Button>
              <Button size={"sm"}>Sign Up</Button>
            </>
          )}
        </div>
      </nav>
    </div>
  );
}