Skip to content

Commit

Permalink
Create nav component (#158)
Browse files Browse the repository at this point in the history
Closes #155 

# Created nav component
![Screenshot of Nav component in dark
mode](https://github.com/LetsGetTechnical/gridiron-survivor/assets/40150036/954db134-5f79-47d3-aa6f-df152bf9b4b8)


https://github.com/LetsGetTechnical/gridiron-survivor/assets/40150036/0e143fbb-a8f7-45b9-9465-0983c3dfbc10

## Todo
- [x] Add hamburger icon
~~- [ ] Add logic to show sign out only if user is signed in (?)~~ Not
needed for MVP
- [x] Integrate `Button.tsx` component from #132 and use in place of
standard `<button>` element

---------

Co-authored-by: Shashi Lo <[email protected]>
  • Loading branch information
2 people authored and Clue355 committed May 1, 2024
1 parent f2fce55 commit d1baca0
Show file tree
Hide file tree
Showing 16 changed files with 705 additions and 104 deletions.
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.github/
*.config.js
.prettierrc.js
*.md
*.md
settings.json
18 changes: 10 additions & 8 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
import { GeistSans } from 'geist/font/sans'
import './globals.css'
import { GeistSans } from 'geist/font/sans';
import './globals.css';
import Nav from '@/components/Nav/Nav';

const defaultUrl = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: 'http://localhost:3000'
: 'http://localhost:3000';

export const metadata = {
metadataBase: new URL(defaultUrl),
title: 'Next.js and Appwrite',
description: 'The fastest way to build apps with Next.js and Appwrite'
}
description: 'The fastest way to build apps with Next.js and Appwrite',
};

export default function RootLayout({
children,
}: {
children: React.ReactNode
children: React.ReactNode;
}) {
return (
<html lang="en" className={GeistSans.className}>
<body className="bg-background text-foreground">
<main className="min-h-screen flex flex-col items-center">
<Nav />
<main className="flex min-h-screen flex-col items-center">
{children}
</main>
</body>
</html>
)
);
}
3 changes: 0 additions & 3 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import AuthButton from '../components/AuthButton';

export default function Index() {
return (
<div className="flex w-full flex-1 flex-col items-center justify-center">
<nav className="flex w-full flex-1 flex-col items-center justify-center">
<p>Gridiron Survivor</p>
<AuthButton />
</nav>
</div>
);
Expand Down
16 changes: 10 additions & 6 deletions components/AuthButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@ export default async function AuthButton() {
return user ? (
<div className="flex items-center gap-4">
Hey, {user.email}!
<form onSubmit={signOut}>
<button type="submit" className="py-2 px-4 rounded-md no-underline bg-btn-background hover:bg-btn-background-hover">
Logout
</button>
</form>
<button
type="submit"
className="bg-btn-background hover:bg-btn-background-hover rounded-md px-4 py-2 no-underline"
>
Logout
</button>
</div>
) : (
<Link href="/login" className="py-2 px-3 flex rounded-md no-underline bg-btn-background hover:bg-btn-background-hover">
<Link
href="/login"
className="bg-btn-background hover:bg-btn-background-hover flex rounded-md px-3 py-2 no-underline"
>
Login
</Link>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { Meta, StoryObj } from '@storybook/react';
import { fn } from "@storybook/test";
import { fn } from '@storybook/test';
import { Button } from './Button';

//👇 This default export determines where your story goes in the story list
const meta: Meta<typeof Button> = {
title: "Components/Button",
title: 'Components/Button',
component: Button,
tags: ["autodocs"],
tags: ['autodocs'],
parameters: {
docs: {
description: {
Expand All @@ -17,14 +17,14 @@ const meta: Meta<typeof Button> = {
argTypes: {
size: {
options: ['default', 'sm', 'lg', 'icon'],
control: {type: 'radio'},
description: "How large should the button be?",
control: { type: 'radio' },
description: 'How large should the button be?',
},
variant: {
description: 'Which type of button?'
description: 'Which type of button?',
},
label: { description: "Button text content" },
onClick: { description: "Click handler" },
label: { description: 'Button text content' },
onClick: { description: 'Click handler' },
},
args: { onClick: fn() },
} satisfies Meta<typeof Button>;
Expand All @@ -36,7 +36,6 @@ export const Default: Story = {
args: {
variant: 'default',
size: 'default',
label: "Click Me",
label: 'Click Me',
},

};
};
15 changes: 15 additions & 0 deletions components/Button/Button.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { Button } from './Button';

test('should render a button with no variant defined', () => {
render(<Button />);
const defaultButton = screen.getByRole('button');
expect(defaultButton).toHaveClass('bg-orange-600');
});

test('should render a button with the link variant defined. It should have no background or border, only an underline on hover', () => {
render(<Button variant="link" />);
const defaultButton = screen.getByRole('button');
expect(defaultButton).toHaveClass('underline-offset-4');
});
61 changes: 61 additions & 0 deletions components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import * as React from 'react';
import { Slot } from '@radix-ui/react-slot';
import { cva, type VariantProps } from 'class-variance-authority';
import { LucideProps } from 'lucide-react';

import { cn } from '../../lib/utils';

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

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
label?: string;
icon?: React.ComponentType<LucideProps & { className?: string }>;
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild, label, icon, ...props }, ref) => {
return (
<button
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
>
<Slot />
{label}
</button>
);
},
);
Button.displayName = 'Button';

export { Button, buttonVariants };
17 changes: 17 additions & 0 deletions components/LogoNav/LogoNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Image from 'next/image'
import logo from '/public/assets/logo-colored-nav.svg'

export const LogoNav = () => {
return (
<Image
src={logo}
alt="Gridiron Survivor logo"
width={1}
height={1}
priority
className='w-20'
/>
)
}

export default LogoNav
46 changes: 46 additions & 0 deletions components/Nav/Nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import LogoNav from '../LogoNav/LogoNav';
import { Menu } from 'lucide-react';
import { Button } from '../Button/Button';
import {
Drawer,
DrawerContent,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from '../NavDrawer/NavDrawer';

export const Nav = () => {
return (
<nav className="flex h-16 items-center border-b border-zinc-100 from-[#4E160E] to-zinc-950 px-4 dark:border-zinc-800 dark:bg-gradient-to-b">
<div className="mr-auto">
<LogoNav />
</div>
<ul>
<li>
<Drawer>
<DrawerTrigger>
<Menu />
</DrawerTrigger>
<DrawerContent>
<DrawerHeader>
<DrawerTitle>Gridiron Survivor</DrawerTitle>
</DrawerHeader>
<ul className="m-0 flex flex-col gap-4 p-0">
<li>
<Button
className="p-0 text-base font-normal text-zinc-600"
variant="link"
label="Sign Out"
/>
</li>
</ul>
</DrawerContent>
</Drawer>
</li>
</ul>
</nav>
);
};

export default Nav;
Loading

0 comments on commit d1baca0

Please sign in to comment.