This commit is contained in:
Jared Palmer 2023-05-19 12:33:56 -04:00
commit a04776256d
56 changed files with 6808 additions and 0 deletions

View file

@ -0,0 +1,9 @@
"use client";
import * as React from "react";
import { ThemeProvider as NextThemesProvider } from "next-themes";
import { ThemeProviderProps } from "next-themes/dist/types";
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}

View file

@ -0,0 +1,28 @@
"use client";
import { useTheme } from "next-themes";
import { Button } from "@/components/ui/button";
import { Moon, Sun } from "lucide-react";
export function ThemeToggle() {
const { setTheme, theme } = useTheme();
return (
<Button
variant="ghost"
size="xs"
className="p-0 leading-4 h-4 font-normal w-full"
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
>
<span className="flex flex-row justify-between text-xs text-zinc-900 dark:text-zinc-400 w-full">
<span className="">Toggle theme</span>
{!theme ? null : theme === "dark" ? (
<Moon className="h-4 transition-all" />
) : (
<Sun className="h-4 transition-all" />
)}
</span>
</Button>
);
}

52
components/ui/button.tsx Normal file
View file

@ -0,0 +1,52 @@
import * as React from "react";
import { VariantProps, cva } from "class-variance-authority";
import { cn } from "@/lib/utils";
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",
xs: "h-6 px-3 rounded-md",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, ...props }, ref) => {
return (
<button
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
}
);
Button.displayName = "Button";
export { Button, buttonVariants };

14
components/ui/login.tsx Normal file
View file

@ -0,0 +1,14 @@
"use client";
import Link from "next/link";
export function Login() {
return (
<Link
className="inline-flex w-full items-center justify-center rounded border border-zinc-800 bg-white h-8 px-4 -my-1.5 text-sm leading-6 tracking-tight text-zinc-900 transition-colors ease-in-out hover:bg-zinc-100 disabled:cursor-not-allowed disabled:opacity-50"
href="/api/auth/login?next=/?s=1"
>
<span className="font-medium">Login</span>
</Link>
);
}

View file

@ -0,0 +1,97 @@
"use client";
import { ThemeToggle } from "@/components/theme-toggle";
import { type Session } from "next-auth";
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
import Image from "next/image";
export interface UserMenuProps {
session: Session;
}
export function UserMenu({ session }: UserMenuProps) {
return (
<div className="flex items-center justify-between">
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild>
<button className="focus:outline-none">
{session.user?.image ? (
<Image
width={24}
height={24}
className="h-6 w-6 rounded-full select-none ring-zinc-100/10 ring-1 hover:opacity-80 transition-opacity duration-300"
src={session.user?.image ? `${session.user.image}&s=60` : ""}
alt={session.user.name ?? "Avatar"}
/>
) : (
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-gradient-to-r from-cyan-500 to-blue-500 p-2 select-none">
<div
className="font-medium uppercase text-zinc-100"
style={{ fontSize: 12 }}
>
{session.user?.name ? session.user?.name.slice(0, 2) : null}
</div>
</div>
)}
</button>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content
className="min-w-[200px] bg-white dark:bg-zinc-950 rounded-lg shadow-lg text-zinc-900 dark:text-zinc-400 overflow-hidden border border-transparent dark:border-zinc-700 focus:outline-none relative z-20 py-2"
sideOffset={8}
align="end"
>
<DropdownMenu.Item className="py-2 px-3 focus:outline-none">
<div className="text-xs font-medium">{session.user?.name}</div>
<div className="text-xs text-zinc-500">{session.user?.email}</div>
</DropdownMenu.Item>
<DropdownMenu.Separator className="my-1 h-[1px] bg-zinc-100 dark:bg-zinc-800" />
<DropdownMenu.Item className="py-2 px-3 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-800 transition-colors duration-200 cursor-pointer text-xs focus:outline-none">
<ThemeToggle />
</DropdownMenu.Item>
<DropdownMenu.Separator className="my-1 h-[1px] bg-zinc-100 dark:bg-zinc-800" />
<DropdownMenu.Item className="py-2 px-3 hover:bg-zinc-200 dark:hover:bg-zinc-800 transition-colors duration-200 cursor-pointer text-xs focus:outline-none ">
<a
href="https://vercel.com"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-between w-full"
>
<span>Vercel Homepage</span>
<span>
<svg
fill="none"
height={16}
shapeRendering="geometricPrecision"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
viewBox="0 0 24 24"
width={16}
aria-hidden="true"
className="mr-1"
>
<path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" />
<path d="M15 3h6v6" />
<path d="M10 14L21 3" />
</svg>
</span>
</a>
</DropdownMenu.Item>
<DropdownMenu.Item
className="py-2 px-3 hover:bg-zinc-200 dark:hover:bg-zinc-800 transition-colors duration-200 cursor-pointer text-xs focus:outline-none"
onClick={() => {
window.location.href = "/api/auth/logout";
}}
>
Log Out
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
</div>
);
}
UserMenu.displayName = "Signout";

View file

@ -0,0 +1,14 @@
import { cn } from "@/lib/utils";
export const VercelLogo = ({ className }: { className?: string }) => (
<svg
height={22}
viewBox="0 0 235 203"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-label="Vercel Logo"
className={cn(className, "dark:fill-white fill-black")}
>
<path d="M117.082 0L234.164 202.794H0L117.082 0Z" fill="currentColor" />
</svg>
);