diff --git a/apps/web/src/components/footer.tsx b/apps/web/src/components/footer.tsx
new file mode 100644
index 0000000000..f7f9a1ec37
--- /dev/null
+++ b/apps/web/src/components/footer.tsx
@@ -0,0 +1,242 @@
+import { Link, useRouterState } from "@tanstack/react-router";
+
+function getMaxWidthClass(pathname: string): string {
+ const isBlogOrDocs =
+ pathname.startsWith("/blog") || pathname.startsWith("/docs");
+ return isBlogOrDocs ? "max-w-6xl" : "max-w-6xl";
+}
+
+export function Footer() {
+ const currentYear = new Date().getFullYear();
+ const router = useRouterState();
+ const maxWidthClass = getMaxWidthClass(router.location.pathname);
+
+ return (
+
+ );
+}
diff --git a/apps/web/src/components/header.tsx b/apps/web/src/components/header.tsx
new file mode 100644
index 0000000000..51fd56cf71
--- /dev/null
+++ b/apps/web/src/components/header.tsx
@@ -0,0 +1,344 @@
+import { Link, useRouterState } from "@tanstack/react-router";
+import { ChevronDown, ChevronUp, Menu } from "lucide-react";
+import { useState } from "react";
+
+import { getPlatformCTA, usePlatform } from "@/hooks/use-platform";
+
+function getMaxWidthClass(pathname: string): string {
+ const isBlogOrDocs =
+ pathname.startsWith("/blog") || pathname.startsWith("/docs");
+ return isBlogOrDocs ? "max-w-6xl" : "max-w-6xl";
+}
+
+const productsList = [
+ { to: "/product/notepad", label: "Notepad" },
+ { to: "/product/bot", label: "Bot", badge: "Coming Soon" },
+ { to: "/product/api", label: "API", badge: "Coming Soon" },
+ { to: "/product/extensions", label: "Extensions", badge: "Coming Soon" },
+];
+
+const featuresList = [
+ { to: "/product/ai-notetaking", label: "AI Notetaking" },
+ { to: "/product/ai-assistant", label: "AI Assistant" },
+ { to: "/product/mini-apps", label: "Mini Apps" },
+ { to: "/product/workflows", label: "Workflows", badge: "Coming Soon" },
+];
+
+export function Header() {
+ const [isMenuOpen, setIsMenuOpen] = useState(false);
+ const [isProductOpen, setIsProductOpen] = useState(false);
+ const platform = usePlatform();
+ const platformCTA = getPlatformCTA(platform);
+ const router = useRouterState();
+ const maxWidthClass = getMaxWidthClass(router.location.pathname);
+
+ return (
+ <>
+
+
+
+
+
+

+
+
setIsProductOpen(true)}
+ onMouseLeave={() => setIsProductOpen(false)}
+ >
+
+ {isProductOpen && (
+
+
+
+
+
+ Products
+
+ {productsList.map((link) => (
+
setIsProductOpen(false)}
+ className="py-2 text-sm text-neutral-700 flex items-center justify-between hover:underline decoration-dotted"
+ >
+
{link.label}
+ {link.badge && (
+
+ {link.badge}
+
+ )}
+
+ ))}
+
+
+
+ Features
+
+
+ {featuresList.map((link) => (
+ setIsProductOpen(false)}
+ className="py-2 text-sm text-neutral-700 flex items-center justify-between hover:underline decoration-dotted"
+ >
+ {link.label}
+ {link.badge && (
+
+ {link.badge}
+
+ )}
+
+ ))}
+
+
+
+
+
+ )}
+
+
+ Docs
+
+
+ Blog
+
+
+ Pricing
+
+
+ Enterprise
+
+
+
+
+

+
+
+
+
+
+ {platformCTA.action === "download" ? (
+
+ {platformCTA.label}
+
+ ) : (
+
+ {platform === "mobile" ? "Get reminder" : platformCTA.label}
+
+ )}
+
+
+
+
+
+
+ {isMenuOpen && (
+ <>
+
setIsMenuOpen(false)}
+ />
+
+
+
+
+ >
+ )}
+ >
+ );
+}
diff --git a/apps/web/src/components/not-found.tsx b/apps/web/src/components/not-found.tsx
index de777879e2..fdfe2418f4 100644
--- a/apps/web/src/components/not-found.tsx
+++ b/apps/web/src/components/not-found.tsx
@@ -1,115 +1,39 @@
-import { Link } from "@tanstack/react-router";
+import { Footer } from "./footer";
+import { Header } from "./header";
export function NotFoundDocument() {
return (
-
-
-
- Page Not Found
-
+
+
+
+
+ Page Not Found
+
-
- 404
-
+
+ 404
+
-
- We couldn't find the page you were looking for. If you think this is
- an error, you can{" "}
-
- let us know
-
- .
-
+
+ We couldn't find the page you were looking for. If you think this
+ is an error, you can{" "}
+
+ let us know
+
+ .
+
+
);
}
-
-function Header() {
- return (
-
-
-
-
-
-
-
-
- );
-}
-
-function Footer() {
- const currentYear = new Date().getFullYear();
-
- return (
-
- );
-}
diff --git a/apps/web/src/routes/_view/route.tsx b/apps/web/src/routes/_view/route.tsx
index 692deff827..1f6abd7b94 100644
--- a/apps/web/src/routes/_view/route.tsx
+++ b/apps/web/src/routes/_view/route.tsx
@@ -1,13 +1,12 @@
import {
createFileRoute,
- Link,
Outlet,
useRouterState,
} from "@tanstack/react-router";
-import { ChevronDown, ChevronUp, Menu } from "lucide-react";
import { createContext, useContext, useState } from "react";
-import { getPlatformCTA, usePlatform } from "@/hooks/use-platform";
+import { Footer } from "@/components/footer";
+import { Header } from "@/components/header";
export const Route = createFileRoute("/_view")({
component: Component,
@@ -25,12 +24,6 @@ export function useHeroContext() {
return useContext(HeroContext);
}
-function getMaxWidthClass(pathname: string): string {
- const isBlogOrDocs =
- pathname.startsWith("/blog") || pathname.startsWith("/docs");
- return isBlogOrDocs ? "max-w-6xl" : "max-w-6xl";
-}
-
function Component() {
const router = useRouterState();
const isDocsPage = router.location.pathname.startsWith("/docs");
@@ -53,571 +46,3 @@ function Component() {
);
}
-
-const productsList = [
- { to: "/product/notepad", label: "Notepad" },
- { to: "/product/bot", label: "Bot", badge: "Coming Soon" },
- { to: "/product/api", label: "API", badge: "Coming Soon" },
- { to: "/product/extensions", label: "Extensions", badge: "Coming Soon" },
-];
-
-const featuresList = [
- { to: "/product/ai-notetaking", label: "AI Notetaking" },
- { to: "/product/ai-assistant", label: "AI Assistant" },
- { to: "/product/mini-apps", label: "Mini Apps" },
- { to: "/product/workflows", label: "Workflows", badge: "Coming Soon" },
-];
-
-function Header() {
- const [isMenuOpen, setIsMenuOpen] = useState(false);
- const [isProductOpen, setIsProductOpen] = useState(false);
- const platform = usePlatform();
- const platformCTA = getPlatformCTA(platform);
- const router = useRouterState();
- const maxWidthClass = getMaxWidthClass(router.location.pathname);
-
- return (
- <>
-
-
-
-
-
-

-
-
setIsProductOpen(true)}
- onMouseLeave={() => setIsProductOpen(false)}
- >
-
- {isProductOpen && (
-
-
-
-
-
- Products
-
- {productsList.map((link) => (
-
setIsProductOpen(false)}
- className="py-2 text-sm text-neutral-700 flex items-center justify-between hover:underline decoration-dotted"
- >
-
{link.label}
- {link.badge && (
-
- {link.badge}
-
- )}
-
- ))}
-
-
-
- Features
-
-
- {featuresList.map((link) => (
- setIsProductOpen(false)}
- className="py-2 text-sm text-neutral-700 flex items-center justify-between hover:underline decoration-dotted"
- >
- {link.label}
- {link.badge && (
-
- {link.badge}
-
- )}
-
- ))}
-
-
-
-
-
- )}
-
-
- Docs
-
-
- Blog
-
-
- Pricing
-
-
- Enterprise
-
-
-
-
-

-
-
-
-
-
- {platformCTA.action === "download" ? (
-
- {platformCTA.label}
-
- ) : (
-
- {platform === "mobile" ? "Get reminder" : platformCTA.label}
-
- )}
-
-
-
-
-
-
- {isMenuOpen && (
- <>
- setIsMenuOpen(false)}
- />
-
-
-
-
- >
- )}
- >
- );
-}
-
-function Footer() {
- const currentYear = new Date().getFullYear();
- const router = useRouterState();
- const maxWidthClass = getMaxWidthClass(router.location.pathname);
-
- return (
-
- );
-}