Skip to content

Commit

Permalink
Merge pull request #57 from auth0-lab/mobile-review
Browse files Browse the repository at this point in the history
reviewing mobile styles
  • Loading branch information
cristiandouce authored Oct 9, 2024
2 parents 8c6ff79 + da7b8ae commit 91060af
Show file tree
Hide file tree
Showing 8 changed files with 671 additions and 103 deletions.
66 changes: 14 additions & 52 deletions app/chat/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,17 @@
import { generateId } from "ai";
import { useActions, useUIState } from "ai/rsc";
import Link from "next/link";
import { use, useEffect } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";

import { useChat } from "@/components/chat/context";
import { ArrowUpIcon, ChevronRightIcon, CircleIcon, Market0Icon } from "@/components/icons";
import { Examples } from "@/components/chat/examples";
import { ArrowUpIcon, CircleIcon, Market0Icon } from "@/components/icons";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Form, FormControl, FormField, FormItem } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { useScrollAnchor } from "@/hooks/chat/use-scroll-anchor";
import { examples, menuItems } from "@/lib/examples";
import { examples } from "@/lib/examples";
import { cn } from "@/lib/utils";
import { ClientMessage } from "@/llm/types";
import { useUser } from "@auth0/nextjs-auth0/client";
Expand Down Expand Up @@ -77,7 +69,9 @@ export default function Chat({ params }: { params: { id: string } }) {
<div ref={scrollRef} className="flex flex-col flex-no-wrap h-full overflow-y-auto overscroll-y-none">
<div
ref={messagesRef}
className={cn("flex-1 min-w-0 max-w-4xl mx-auto w-full pb-[100px]", { hidden: conversation.length === 0 })}
className={cn("flex-1 min-w-0 max-w-4xl mx-auto w-full pb-[100px] px-3 sm:px-0", {
hidden: conversation.length === 0,
})}
>
{conversation.map((message: ClientMessage) =>
message.role === "user" ? (
Expand Down Expand Up @@ -105,15 +99,15 @@ export default function Chat({ params }: { params: { id: string } }) {
</div>
{conversation.length === 0 && (
<div className="flex flex-col gap-80 max-w-4xl mx-auto w-full mb-5 mt-auto">
<div className="min-w-0 min-h-0 w-full flex flex-col items-center gap-6">
<div className="min-w-0 min-h-0 w-full flex flex-col items-center gap-2 sm:gap-6">
<Market0Icon />
<h1 className="text-6xl tracking-tight leading-[72px]">
<h1 className="text-4xl sm:text-6xl tracking-tight leading-[72px]">
Welcome to{" "}
<span className="bg-text-gradient bg-clip-text" style={{ WebkitTextFillColor: "transparent" }}>
Market0
</span>
</h1>
<p className="text-base tracking-wide text-slate-500 font-light leading-6">
<p className="text-base tracking-wide text-slate-500 font-light leading-6 text-center px-10 sm:px-0">
Market0 is a demo app that showcases secure auth patterns for GenAI apps
</p>
</div>
Expand All @@ -122,7 +116,7 @@ export default function Chat({ params }: { params: { id: string } }) {
<CircleIcon />
<span className="text-slate-500 text-sm font-light">Get started with these examples</span>
</div>
<div className="grid grid-cols-3 gap-4 w-full">
<div className="grid grid-cols-1 sm:grid-cols-3 gap-2 sm:gap-4 w-full px-3 sm:px-0">
{examples.map((example) => (
<button
key={example.id}
Expand All @@ -136,8 +130,8 @@ export default function Chat({ params }: { params: { id: string } }) {
</div>
</div>
)}
<div className="sticky bottom-0 flex-shrink-0 min-w-0 min-h-0 bg-white max-w-4xl mx-auto w-full">
<div className="p-4 py-3 bg-white border border-gray-200 rounded-lg focus-within:ring-stone-700 focus-within:ring-2 transition-all duration-150">
<div className="sticky bottom-0 flex-shrink-0 min-w-0 min-h-0 bg-white max-w-4xl mx-auto w-full px-3 sm:px-0">
<div className="p-3 bg-white border border-gray-200 rounded-lg focus-within:ring-stone-700 focus-within:ring-2 transition-all duration-150">
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
Expand All @@ -161,39 +155,7 @@ export default function Chat({ params }: { params: { id: string } }) {
)}
/>

{!form.formState.disabled && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
className="flex flex-row gap-2 text-black text-sm leading-6 bg-gray-100 border-none px-3 py-2 focus-visible:ring-0 hover:bg-gray-200/90 transition-all duration-300 shadow-none font-light"
>
Examples
<ChevronRightIcon />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-96 p-0" align="end" sideOffset={8}>
<DropdownMenuGroup>
{menuItems.map((menuItem, idx) => (
<DropdownMenuItem
key={menuItem.id}
onClick={onExampleClick(menuItem.message)}
className={cn(
"cursor-pointer px-4 py-3 focus:bg-gray-50 rounded-none",
idx < menuItems.length - 1 && "border-b border-gray-900/5"
)}
>
<div className="flex flex-row items-center w-full gap-4">
{menuItem.icon}
<span className="text-sm text-gray-900 leading-6">{menuItem.message}</span>
</div>
<ArrowUpIcon />
</DropdownMenuItem>
))}
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
)}
{!form.formState.disabled && <Examples onExampleClick={onExampleClick} />}

<Button
disabled={!form.formState.isDirty || form.formState.disabled}
Expand All @@ -206,7 +168,7 @@ export default function Chat({ params }: { params: { id: string } }) {
</Form>
</div>
{conversation.length > 0 && (
<div className="relative px-2 py-2 text-center text-xs font-light text-slate-500 md:px-[60px]">
<div className="relative px-2 py-2 text-center text-[11px] sm:text-xs font-light text-slate-500 md:px-[60px]">
<span>Market0 is a demo app that showcases secure auth patterns for GenAI apps</span>
</div>
)}
Expand Down
111 changes: 111 additions & 0 deletions components/chat/examples.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"use client";

import { ArrowUpIcon, ChevronRightIcon, CloseIcon } from "@/components/icons";
import { Button } from "@/components/ui/button";
import { Drawer, DrawerClose, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from "@/components/ui/drawer";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { menuItems } from "@/lib/examples";
import { cn } from "@/lib/utils";

function ExamplesDesktop({ onExampleClick }: { onExampleClick: (input: string) => () => Promise<void> }) {
return (
<div className="hidden sm:inline-block">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
className="flex flex-row gap-2 text-black text-sm leading-6 bg-gray-100 border-none px-3 py-2 focus-visible:ring-0 hover:bg-gray-200/90 transition-all duration-300 shadow-none font-light"
>
Examples
<ChevronRightIcon />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-96 p-0" align="end" sideOffset={8}>
<DropdownMenuGroup>
{menuItems.map((menuItem, idx) => (
<DropdownMenuItem
key={menuItem.id}
onClick={onExampleClick(menuItem.message)}
className={cn(
"cursor-pointer px-4 py-3 focus:bg-gray-50 rounded-none",
idx < menuItems.length - 1 && "border-b border-gray-900/5"
)}
>
<div className="flex flex-row items-center w-full gap-4">
{menuItem.icon}
<span className="text-sm text-gray-900 leading-6">{menuItem.message}</span>
</div>
<ArrowUpIcon />
</DropdownMenuItem>
))}
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>
);
}

function ExamplesMobile({ onExampleClick }: { onExampleClick: (input: string) => () => Promise<void> }) {
return (
<div className="sm:hidden flex items-center">
<Drawer direction="left">
<DrawerTrigger asChild={true}>
<Button
variant="outline"
className="flex flex-row gap-2 text-black text-sm leading-6 bg-gray-100 border-none px-3 py-2 focus-visible:ring-0 hover:bg-gray-200/90 transition-all duration-300 shadow-none font-light"
>
<ArrowUpIcon />
</Button>
</DrawerTrigger>
<DrawerContent className="h-full rounded-none">
<DrawerHeader>
<DrawerTitle className="px-1">
<div className="flex justify-between items-center">
<div className="text-base font-medium leading-6">Examples</div>

<DrawerClose>
<Button variant="ghost" className="p-0">
<CloseIcon />
</Button>
</DrawerClose>
</div>
</DrawerTitle>
</DrawerHeader>
<ul>
{menuItems.map((menuItem, idx) => (
<li key={menuItem.id} className="border-t last:border-b border-[#E2E8F0]">
<DrawerClose className="w-full">
<button
onClick={onExampleClick(menuItem.message)}
className="flex items-center justify-between py-3 px-5 w-full"
>
<div className="flex items-center gap-4">
{menuItem.icon}
<span className="text-sm text-gray-900">{menuItem.message}</span>
</div>
<ArrowUpIcon />
</button>
</DrawerClose>
</li>
))}
</ul>
</DrawerContent>
</Drawer>
</div>
);
}

export function Examples({ onExampleClick }: { onExampleClick: (input: string) => () => Promise<void> }) {
return (
<>
<ExamplesDesktop onExampleClick={onExampleClick} />
<ExamplesMobile onExampleClick={onExampleClick} />
</>
);
}
44 changes: 5 additions & 39 deletions components/chat/header.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import Link from "next/link";

import { ArrowRightIcon, DiscordIcon, GHIcon, IconAuth0 } from "@/components/icons";
import { ArrowRightIcon, IconAuth0 } from "@/components/icons";
import { getSession } from "@auth0/nextjs-auth0";

import UserButton from "../auth0/user-button";
import { DropdownMenu, DropdownMenuGroup, DropdownMenuItem, DropdownMenuShortcut } from "../ui/dropdown-menu";
import { Menu } from "./mobile-menu";

export async function Header({ children }: { children?: React.ReactNode }) {
const session = await getSession();
const user = session?.user!;

return (
<header className="sticky top-0 z-50 flex items-center justify-between w-full px-6 py-3 h-14 shrink-0 bg-background backdrop-blur-xl">
<header className="sticky top-0 z-50 flex items-center justify-between w-full px-5 sm:px-6 py-3 h-14 shrink-0 bg-background backdrop-blur-xl">
<div className="flex items-center gap-6">
<span className="inline-flex items-center home-links whitespace-nowrap">
<Link href="https://lab.auth0.com" rel="noopener" target="_blank">
Expand All @@ -22,46 +21,13 @@ export async function Header({ children }: { children?: React.ReactNode }) {
href="#"
target="_blank"
rel="noopener noreferrer"
className="hover:text-black transition-all duration-300 text-sm font-light text-slate-500 flex items-center gap-1"
className="hover:text-black transition-all duration-300 text-sm font-light text-slate-500 items-center gap-1 hidden sm:flex"
>
Learn about Auth for GenAI <ArrowRightIcon />
</Link>
</div>
<div className="flex items-center justify-end gap-6">
<div className="flex items-center justify-end gap-4">
{children}

<Link
href="https://discord.gg/QGHxwDsbQQ"
rel="noopener noreferrer"
target="_blank"
className="min-w-12 border border-gray-300 bg-white text-slate-800 flex gap-2 items-center justify-center px-3 py-2 rounded-md shadow-none hover:ring-2 ring-[#CFD1D4] text-sm hover:text-black hover:border-[transparent] transition-all duration-300"
>
<DiscordIcon />
</Link>

<Link
href="https://github.com/auth0-lab/market0"
rel="noopener noreferrer"
target="_blank"
className="min-w-12 border border-gray-300 bg-white text-slate-800 flex gap-2 items-center justify-center px-3 py-2 rounded-md shadow-none hover:ring-2 ring-[#CFD1D4] text-sm hover:text-black hover:border-[transparent] transition-all duration-300"
>
<GHIcon />
</Link>
<UserButton user={user}>
<DropdownMenu>
<DropdownMenuGroup>
<DropdownMenuItem>
<Link href="/profile" className="flex gap-2 items-center">
Profile
</Link>
<DropdownMenuShortcut>⌘P</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenu>
</UserButton>
</div>
</div>
<Menu user={user}>{children}</Menu>
</header>
);
}
Loading

0 comments on commit 91060af

Please sign in to comment.