diff --git a/apps/marketing/package.json b/apps/marketing/package.json index 5fd2ff59e..9089405fb 100644 --- a/apps/marketing/package.json +++ b/apps/marketing/package.json @@ -37,4 +37,4 @@ "@types/react": "18.2.18", "@types/react-dom": "18.2.7" } -} +} \ No newline at end of file diff --git a/apps/marketing/public/logo_icon.png b/apps/marketing/public/logo_icon.png new file mode 100644 index 000000000..cb4765fcf Binary files /dev/null and b/apps/marketing/public/logo_icon.png differ diff --git a/apps/marketing/src/components/(marketing)/footer.tsx b/apps/marketing/src/components/(marketing)/footer.tsx index e82318a38..701d9b60f 100644 --- a/apps/marketing/src/components/(marketing)/footer.tsx +++ b/apps/marketing/src/components/(marketing)/footer.tsx @@ -3,7 +3,7 @@ import { HTMLAttributes } from 'react'; import Image from 'next/image'; import Link from 'next/link'; -import { Github, Slack, Twitter } from 'lucide-react'; +import { Github, MessagesSquare, Twitter } from 'lucide-react'; import { cn } from '@documenso/ui/lib/utils'; @@ -36,11 +36,11 @@ export const Footer = ({ className, ...props }: FooterProps) => { - + diff --git a/apps/marketing/src/components/(marketing)/header.tsx b/apps/marketing/src/components/(marketing)/header.tsx index 611aff96c..4b9458ce2 100644 --- a/apps/marketing/src/components/(marketing)/header.tsx +++ b/apps/marketing/src/components/(marketing)/header.tsx @@ -1,20 +1,27 @@ -import { HTMLAttributes } from 'react'; +'use client'; + +import { HTMLAttributes, useState } from 'react'; import Image from 'next/image'; import Link from 'next/link'; import { cn } from '@documenso/ui/lib/utils'; +import { HamburgerMenu } from './mobile-hamburger'; +import { MobileNavigation } from './mobile-navigation'; + export type HeaderProps = HTMLAttributes; export const Header = ({ className, ...props }: HeaderProps) => { + const [isHamburgerMenuOpen, setIsHamburgerMenuOpen] = useState(false); + return (
- - Documenso Logo + setIsHamburgerMenuOpen(false)}> + Documenso Logo -
+
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 ( + + + + Documenso Logo + + + + {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; +}