Skip to content

Commit

Permalink
add component primitives
Browse files Browse the repository at this point in the history
  • Loading branch information
warrengalyen committed Aug 10, 2023
1 parent 2a24402 commit f69a4e0
Show file tree
Hide file tree
Showing 14 changed files with 205 additions and 56 deletions.
7 changes: 7 additions & 0 deletions .idea/prettier.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
26 changes: 16 additions & 10 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
import '../styles/globals.css'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import { NavBar } from "@/components/navbar";
import "../styles/globals.css";
import { Footer } from "@/components/footer";
import type { Metadata } from "next";
import { Inter } from "next/font/google";

const inter = Inter({ subsets: ['latin'] })
const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
title: "Create Next App",
description: "Generated by create next app",
};

export default function RootLayout({
children,
}: {
children: React.ReactNode
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
<body className="min-h-screen w-full flex flex-col bg-gray-50">
<NavBar />
<main className="h-full flex-1">{children}</main>
<Footer />
</body>
</html>
)
);
}
20 changes: 9 additions & 11 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
'use client'
"use client";

import Image from 'next/image'
// import { Inter } from 'next/font/google'
import { useState } from 'react'
import { Button } from '@/components/ui/button'
import { Button } from "@/components/ui/button";

// const inter = Inter({ subsets: ['latin'] })

export default function Home() {
const [dark, setDark] = useState (false)
return (
<main className="">
<Button primary={true} size="md" label="dd"></Button>
<h1>Hello</h1>
</main>
)
<>
<Button variant="default" size="default">
Shop now!
</Button>
<h1>Hello</h1>
</>
);
}
11 changes: 11 additions & 0 deletions components/content-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { cn } from "@/lib/utils";
import { type PropsWithChildren } from "react";

export const ContentWrapper = ({
children,
padding = "6",
}: PropsWithChildren<{ padding?: string }>) => {
return (
<div className={cn("max-w-7xl m-auto", `p-${padding}`)}>{children}</div>
);
};
12 changes: 12 additions & 0 deletions components/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ContentWrapper } from "./content-wrapper";
import { Logo } from "./logo";

export const Footer = () => {
return (
<footer className="p-6 text-primary-foreground bg-primary">
<ContentWrapper>
<Logo />
</ContentWrapper>
</footer>
);
};
3 changes: 3 additions & 0 deletions components/line.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const Line = () => {
return <div className="h-[1px] bg-border w-full" />;
};
5 changes: 5 additions & 0 deletions components/logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Heading } from "./ui/heading";

export const Logo = () => {
return <Heading size="h2">Outpost</Heading>;
};
18 changes: 18 additions & 0 deletions components/menu-items.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Link from "next/link";
import { Button } from "./ui/button";

export const MenuItems = () => {
return (
<ul className="flex items-center justify-center gap-4 pt-1">
{["Home", "About", "Contact"].map((item) => (
<li>
<Link href="/">
<Button variant="ghost" size="default">
{item}
</Button>
</Link>
</li>
))}
</ul>
);
};
33 changes: 33 additions & 0 deletions components/navbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Link from "next/link";
import { Logo } from "./logo";
import { ContentWrapper } from "./content-wrapper";
import { ShoppingCart } from "lucide-react";
import { Search } from "./search";
import { MenuItems } from "./menu-items";
import { Line } from "./line";

export const NavBar = () => {
return (
<nav className="border-b border-border pb-1">
<ContentWrapper>
<ul className="flex items-center justify-between gap-12">
<li>
<Link href="/">
<Logo />
</Link>
</li>
<li className="flex-1">
<Search />
</li>
<li>
<ShoppingCart />
</li>
</ul>
</ContentWrapper>
<Line />
<ContentWrapper padding="0">
<MenuItems />
</ContentWrapper>
</nav>
);
};
5 changes: 5 additions & 0 deletions components/search.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Input } from "./ui/input";

export const Search = () => {
return <Input />;
};
80 changes: 45 additions & 35 deletions components/ui/button.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,51 @@
import React, { useMemo } from 'react';
import * as React from "react";
import { VariantProps, cva } from "class-variance-authority";

const getSizeClasses = (size: string) => {
switch (size) {
case 'small': {
return 'px-4 py-2.5';
}
case 'large': {
return 'px-6 py-3';
}
default: {
return 'px-5 py-2.5';
}
}
};
import { cn } from "@/lib/utils";

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

const BASE_BUTTON_CLASSES =
'cursor-pointer rounded-full border-2 font-bold leading-none inline-block';

/**
* Primary UI component for user interaction
*/
export const Button = ({ primary = false, size = 'medium', label, ...props }: {primary: boolean, size: string; label: string;}) => {
const computedClasses = useMemo(() => {
const modeClass = getModeClasses(primary);
const sizeClass = getSizeClasses(size);

return [modeClass, sizeClass].join(' ');
}, [primary, size]);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, ...props }, ref) => {
return (
<button type="button" className={`${BASE_BUTTON_CLASSES} ${computedClasses}`} {...props}>
{label}
</button>
<button
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
};
}
);
Button.displayName = "Button";

export { Button, buttonVariants };
15 changes: 15 additions & 0 deletions components/ui/heading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { type PropsWithChildren } from "react";

const headingStyles = {
h1: "scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl",
h2: "scroll-m-20 text-3xl font-semibold tracking-tight transition-colors first:mt-0",
h3: "scroll-m-20 text-2xl font-semibold tracking-tight",
h4: "scroll-m-20 text-xl font-semibold tracking-tight",
};

export const Heading = ({
children,
size: Tag,
}: PropsWithChildren<{ size: "h1" | "h2" | "h3" | "h4" }>) => {
return <Tag className={headingStyles[Tag]}>{children}</Tag>;
};
25 changes: 25 additions & 0 deletions components/ui/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as React from "react";

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

export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}

const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
);
}
);
Input.displayName = "Input";

export { Input };

0 comments on commit f69a4e0

Please sign in to comment.