Skip to content

Commit

Permalink
Add responsive nav
Browse files Browse the repository at this point in the history
  • Loading branch information
josephdburdick committed Jun 5, 2024
1 parent 3b0b497 commit 35e56a0
Show file tree
Hide file tree
Showing 10 changed files with 303 additions and 24 deletions.
Binary file modified bun.lockb
Binary file not shown.
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
},
"dependencies": {
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-slot": "^1.0.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"front-matter": "^4.0.2",
Expand All @@ -20,7 +22,8 @@
"react": "^18",
"react-dom": "^18",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7"
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.1"
},
"devDependencies": {
"@types/node": "^20",
Expand Down
1 change: 1 addition & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface Result {
[key: string]: FrontMatterContent;
}
const searchRegex = /\$\{basePath\}/gi

export async function getData(): Promise<Result> {
const dataDir = path.join(process.cwd(), "src/api/")
const files = await fs.readdir(dataDir)
Expand Down
6 changes: 3 additions & 3 deletions src/api/profile.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ links:
email:
url: "mailto:[email protected]"
label: "Email"
github:
url: "https://github.com/josephdburdick"
label: "Github"
linkedin:
url: "https://linkedin.com/in/josephdburdick"
label: "LinkedIn"
readcv:
url: "https://read.cv/josephdburdick"
label: "Read.cv"
github:
url: "https://github.com/josephdburdick"
label: "Github"
intro: >
j0e.me is the eponymous online home of Joe Burdick— web designer, software engineer, leader, and photographer.
---
Expand Down
13 changes: 11 additions & 2 deletions src/app/_content/Intro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ import { useData } from "@/lib/providers/DataProvider"
import WorkAvailability from "@/components/global/WorkAvailability"
import ContactLinks from "@/components/global/ContactLinks"
import LogoMarquee from "@/components/global/LogoMarquee"
import { ContactLink } from "@/lib/types"
import MobileNav from "@/components/global/MobileNav"

function Intro() {
const { data } = useData()
const { logo } = data.site.attributes

const links: ContactLink[] = Object.values(data.profile.attributes.links)
const filter = ["Email"]

return (
<div className="flex flex-1 w-full">
<div className="grid grid-rows-[auto_1fr_auto] gap-4 lg:gap-6 items-center w-full">
Expand Down Expand Up @@ -51,8 +57,11 @@ function Intro() {
</svg>
<span>{data.profile.attributes.location}</span>
</div>

<ContactLinks />
<ContactLinks
links={links.filter(({ label }) => !filter.includes(label))}
className="hidden md:block"
/>
<MobileNav links={links} className="block md:hidden" />
</div>
</footer>
</div>
Expand Down
34 changes: 16 additions & 18 deletions src/components/global/ContactLinks.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
import { useData } from "@/lib/providers/DataProvider"
type ContactLink = {
url: string;
label: string;
import { ContactLink } from "@/lib/types"

type Props = {
className?: string;
links: ContactLink[];
};
export default function ContactLinks() {
const { data } = useData()
const contactLinks: ContactLink[] = data.profile.attributes.links
const filter = ["Email"]
const links = Object.values(contactLinks)
.filter(({ label }) => !filter.includes(label))
.map(({ url, label }, index: number) => (
<li key={index} className="text-right md:text-left">
<a href={url} target="_blank" rel="noreferrer">
{label}
</a>
</li>
))

export default function ContactLinks(props: Props) {
const { className = "", links: linksProp = [] } = props
const links = linksProp.map(({ url, label }, index: number) => (
<li key={index} className="text-right md:text-left">
<a href={url} target="_blank" rel="noreferrer">
{label}
</a>
</li>
))

return (
<nav>
<nav className={className}>
<ul className="flex gap-4 md:gap-8 flex-col md:flex-row justify-end md:items-center">
{links}
</ul>
Expand Down
88 changes: 88 additions & 0 deletions src/components/global/MobileNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"use client"
import { buttonVariants, Button } from "@/components/ui/button"
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer"

import { ContactLink } from "@/lib/types"
import { cn } from "@/lib/utils"

type Props = {
className?: string;
links: ContactLink[];
};

export default function MobileNav(props: Props) {
const { className = "", links: linksProp = [] } = props

const links = linksProp.map(({ url, label }, index: number) => (
<li key={index}>
<a
href={url}
target="_blank"
rel="noreferrer"
className={cn(
buttonVariants({ variant: "default", size: "lg" }),
"w-full text-lg",
)}
>
{label}
</a>
</li>
))

return (
<Drawer>
<DrawerTrigger asChild className={className}>
<Button
variant="outline"
size="lg"
className="rounded-full text-heading-xs py-4"
>
<span className="flex items-center gap-2">
Let&apos;s Connect
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="m22 2-7 20-4-9-9-4Z" />
<path d="M22 2 11 13" />
</svg>
</span>
</Button>
</DrawerTrigger>
<DrawerContent>
<div className="mx-auto w-full max-w-md">
<DrawerHeader>
<DrawerTitle>Let&apos;s connect</DrawerTitle>
<DrawerDescription>
Find me on social media or send me an email
</DrawerDescription>
</DrawerHeader>
<DrawerFooter>
<nav>
<ul className="space-y-4">{links}</ul>
</nav>
<DrawerClose asChild>
<Button variant="outline">Close</Button>
</DrawerClose>
</DrawerFooter>
</div>
</DrawerContent>
</Drawer>
)
}
57 changes: 57 additions & 0 deletions src/components/ui/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/lib/utils"

const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "px-4 py-2",
sm: "rounded-md px-3 text-xs",
lg: "rounded-md px-8 py-8",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
)

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
},
)
Button.displayName = "Button"

export { Button, buttonVariants }
118 changes: 118 additions & 0 deletions src/components/ui/drawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"use client"

import * as React from "react"
import { Drawer as DrawerPrimitive } from "vaul"

import { cn } from "@/lib/utils"

const Drawer = ({
shouldScaleBackground = true,
...props
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
<DrawerPrimitive.Root
shouldScaleBackground={shouldScaleBackground}
{...props}
/>
)
Drawer.displayName = "Drawer"

const DrawerTrigger = DrawerPrimitive.Trigger

const DrawerPortal = DrawerPrimitive.Portal

const DrawerClose = DrawerPrimitive.Close

const DrawerOverlay = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Overlay
ref={ref}
className={cn("fixed inset-0 z-50 bg-black/80", className)}
{...props}
/>
))
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName

const DrawerContent = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
className
)}
{...props}
>
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
{children}
</DrawerPrimitive.Content>
</DrawerPortal>
))
DrawerContent.displayName = "DrawerContent"

const DrawerHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
{...props}
/>
)
DrawerHeader.displayName = "DrawerHeader"

const DrawerFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props}
/>
)
DrawerFooter.displayName = "DrawerFooter"

const DrawerTitle = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
DrawerTitle.displayName = DrawerPrimitive.Title.displayName

const DrawerDescription = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
DrawerDescription.displayName = DrawerPrimitive.Description.displayName

export {
Drawer,
DrawerPortal,
DrawerOverlay,
DrawerTrigger,
DrawerClose,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
}
5 changes: 5 additions & 0 deletions src/lib/types/experience.ts → src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
export type ContactLink = {
url: string;
label: string;
};

export interface Role {
title: string;
type: string;
Expand Down

0 comments on commit 35e56a0

Please sign in to comment.