+
Pricing
@@ -35,6 +42,15 @@ export const Header = ({ className, ...props }: HeaderProps) => {
Sign in
+
+
setIsHamburgerMenuOpen((v) => !v)}
+ isMenuOpen={isHamburgerMenuOpen}
+ />
+
);
};
diff --git a/apps/marketing/src/components/(marketing)/mobile-hamburger.tsx b/apps/marketing/src/components/(marketing)/mobile-hamburger.tsx
new file mode 100644
index 000000000..30c80f1d0
--- /dev/null
+++ b/apps/marketing/src/components/(marketing)/mobile-hamburger.tsx
@@ -0,0 +1,20 @@
+'use client';
+
+import { Menu, X } from 'lucide-react';
+
+import { Button } from '@documenso/ui/primitives/button';
+
+export interface HamburgerMenuProps {
+ isMenuOpen: boolean;
+ onToggleMenuOpen?: () => void;
+}
+
+export const HamburgerMenu = ({ isMenuOpen, onToggleMenuOpen }: HamburgerMenuProps) => {
+ return (
+
+
+
+ );
+};
diff --git a/apps/marketing/src/components/(marketing)/mobile-navigation.tsx b/apps/marketing/src/components/(marketing)/mobile-navigation.tsx
new file mode 100644
index 000000000..bc64e7f59
--- /dev/null
+++ b/apps/marketing/src/components/(marketing)/mobile-navigation.tsx
@@ -0,0 +1,121 @@
+'use client';
+
+import Image from 'next/image';
+import Link from 'next/link';
+
+import { motion, useReducedMotion } from 'framer-motion';
+import { Github, MessagesSquare, Twitter } from 'lucide-react';
+
+import { Sheet, SheetContent } from '@documenso/ui/primitives/sheet';
+
+export type MobileNavigationProps = {
+ isMenuOpen: boolean;
+ onMenuOpenChange?: (_value: boolean) => void;
+};
+
+export const MENU_NAVIGATION_LINKS = [
+ {
+ href: '/blog',
+ text: 'Blog',
+ },
+ {
+ href: '/pricing',
+ text: 'Pricing',
+ },
+ {
+ href: 'https://status.documenso.com',
+ text: 'Status',
+ },
+ {
+ href: 'mailto:support@documenso.com',
+ text: 'Support',
+ },
+ {
+ href: '/privacy',
+ text: 'Privacy',
+ },
+ {
+ href: 'https://app.documenso.com/login',
+ text: 'Sign in',
+ },
+];
+
+export const MobileNavigation = ({ isMenuOpen, onMenuOpenChange }: MobileNavigationProps) => {
+ const shouldReduceMotion = useReducedMotion();
+
+ const handleMenuItemClick = () => {
+ onMenuOpenChange?.(false);
+ };
+
+ return (
+
+
+
+
+
+
+
+ {MENU_NAVIGATION_LINKS.map(({ href, text }) => (
+
+ handleMenuItemClick()}
+ >
+ {text}
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/marketing/src/hooks/use-window-size.ts b/apps/marketing/src/hooks/use-window-size.ts
new file mode 100644
index 000000000..7dfd97a5c
--- /dev/null
+++ b/apps/marketing/src/hooks/use-window-size.ts
@@ -0,0 +1,27 @@
+import { useEffect, useState } from 'react';
+
+export function useWindowSize() {
+ const [size, setSize] = useState({
+ width: 0,
+ height: 0,
+ });
+
+ const onResize = () => {
+ setSize({
+ width: window.innerWidth,
+ height: window.innerHeight,
+ });
+ };
+
+ useEffect(() => {
+ onResize();
+
+ window.addEventListener('resize', onResize);
+
+ return () => {
+ window.removeEventListener('resize', onResize);
+ };
+ }, []);
+
+ return size;
+}