diff --git a/apps/next/src/app/(home)/page.tsx b/apps/next/src/app/(home)/page.tsx index a777163a81a20f42f1438ef330d7ecd3d01c37b8..ab071c2bd1ffcb0cbc3012a4da351b36f6b763f3 100644 --- a/apps/next/src/app/(home)/page.tsx +++ b/apps/next/src/app/(home)/page.tsx @@ -16,18 +16,18 @@ export default function HomePage() { Build RAG Web App using <br /> <span className="text-blue-500">LlamaIndex.TS</span> </h1> - <p className="text-xl text-center text-gray-600 mb-12"> + <p className="text-xl text-center text-fd-muted-foreground mb-12 "> LlamaIndex.TS is the JS/TS library from our popular Python library llama-index for building LLM applications </p> - <div className="text-center text-lg text-gray-600 mb-12"> + <div className="text-center text-lg text-fd-muted-foreground mb-12"> <span>Designed for building web applications under </span> <TextEffect /> </div> <div className="flex flex-wrap justify-center gap-4"> <Link href="/docs"> - <Button className="bg-black text-white">Get Started</Button> + <Button variant="outline">Get Started</Button> </Link> <NpmInstall /> <Link diff --git a/apps/next/src/app/global.css b/apps/next/src/app/global.css index 89ed20c2d93534a7b39486be1b9cd54a753c012c..dfcd53dc3fb3650266ee07d9a3eeb030718f0547 100644 --- a/apps/next/src/app/global.css +++ b/apps/next/src/app/global.css @@ -47,6 +47,20 @@ --radius: 0.5rem; } .dark { + --color-neutral-000: #0e0c15; + --color-neutral-100: #252134; + --color-neutral-200: #757185; + --color-neutral-400: #cac6dd; + --color-neutral-800: #f7f6fc; + --color-neutral-900: #ffffff; + + --color-purple-400: #858dff; + --color-red-400: #ff776f; + --color-green-400: #7adb78; + --color-yellow-400: #ffc876; + --color-violet-400: #ac6aff; + --color-pink-400: #ff98e2; + --background: 0 0% 3.9%; --foreground: 0 0% 98%; --card: 0 0% 3.9%; diff --git a/apps/next/src/components/create-app-animation.tsx b/apps/next/src/components/create-app-animation.tsx index 1811d99394648c7f7535fbdd49b4c6f57fa60c52..b2e21ba2844f7184c0fa36a83d2802e2ce8f4b2d 100644 --- a/apps/next/src/components/create-app-animation.tsx +++ b/apps/next/src/components/create-app-animation.tsx @@ -5,9 +5,11 @@ import { Fragment, HTMLAttributes, ReactElement, + ReactNode, useEffect, useState, } from "react"; +import { Input } from "./ui/input"; export function CreateAppAnimation(): React.ReactElement { const installCmd = "npx create-llama@latest"; @@ -98,6 +100,102 @@ export function CreateAppAnimation(): React.ReactElement { ); } +function UserMessage({ children }: { children: ReactNode }) { + return ( + <div className="group relative flex items-start"> + <div className="flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border shadow-sm bg-background"> + <IconUser /> + </div> + <div className="ml-4 flex-1 space-y-2 overflow-hidden px-1"> + {children} + </div> + </div> + ); +} + +function BotMessage({ + children, + className, +}: { + children: ReactNode; + className?: string; +}) { + return ( + <div className={cn("group relative flex items-start", className)}> + <div className="flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border shadow-sm bg-primary text-primary-foreground"> + <IconAI /> + </div> + <div className="ml-4 flex-1 space-y-2 overflow-hidden px-1"> + {children} + </div> + </div> + ); +} + +export function ChatExample() { + const userMessageFull = + "Hello, please summarize the article on the file I uploaded."; + const botMessageFull = "Processing..."; + + const tickTime = 100; + const userMessageDuration = userMessageFull.length; + const botMessageDelay = userMessageDuration + 10; + const botMessageDuration = botMessageDelay + botMessageFull.length; + const totalDuration = botMessageDuration + 10; + + const [tick, setTick] = useState(0); + + useEffect(() => { + // Increment tick every tickTime milliseconds + const timer = setInterval(() => { + setTick((prev) => (prev >= totalDuration ? prev : prev + 1)); + }, tickTime); + + return () => { + clearInterval(timer); + }; + }, [totalDuration]); + + const userMessageLength = Math.min(tick, userMessageFull.length); + const botMessageLength = Math.max( + 0, + Math.min(tick - botMessageDelay, botMessageFull.length), + ); + + return ( + <div className="max-w-64"> + <div className="flex flex-col px-4 gap-2"> + {userMessageLength === userMessageFull.length && ( + <UserMessage> + <span>{userMessageFull}</span> + </UserMessage> + )} + {tick > botMessageDelay && ( + <BotMessage> + <div> + <p> + {botMessageFull.substring(0, botMessageLength)} + {tick - botMessageDelay < botMessageFull.length && ( + <span className="inline-block h-3 w-1 animate-pulse bg-white" /> + )} + </p> + </div> + </BotMessage> + )} + </div> + <Input + className="mt-4" + value={ + userMessageFull.substring(0, userMessageLength) === userMessageFull + ? "" + : userMessageFull.substring(0, userMessageLength) + } + placeholder="Input message..." + /> + </div> + ); +} + function LaunchAppWindow( props: HTMLAttributes<HTMLDivElement>, ): React.ReactElement { @@ -112,7 +210,38 @@ function LaunchAppWindow( <div className="relative flex h-6 flex-row items-center border-b bg-fd-muted px-4 text-xs text-fd-muted-foreground"> <p className="absolute inset-x-0 text-center">localhost:8080</p> </div> - <div className="p-4 text-sm">New App launched!</div> + <div className="p-4 text-sm"> + <ChatExample /> + </div> </div> ); } + +function IconUser({ className, ...props }: React.ComponentProps<"svg">) { + return ( + <svg + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 256 256" + fill="currentColor" + className={cn("h-4 w-4", className)} + {...props} + > + <path d="M230.92 212c-15.23-26.33-38.7-45.21-66.09-54.16a72 72 0 1 0-73.66 0c-27.39 8.94-50.86 27.82-66.09 54.16a8 8 0 1 0 13.85 8c18.84-32.56 52.14-52 89.07-52s70.23 19.44 89.07 52a8 8 0 1 0 13.85-8ZM72 96a56 56 0 1 1 56 56 56.06 56.06 0 0 1-56-56Z" /> + </svg> + ); +} + +function IconAI({ className, ...props }: React.ComponentProps<"svg">) { + return ( + <svg + fill="currentColor" + viewBox="0 0 256 256" + role="img" + xmlns="http://www.w3.org/2000/svg" + className={cn("h-4 w-4", className)} + {...props} + > + <path d="M197.58,129.06l-51.61-19-19-51.65a15.92,15.92,0,0,0-29.88,0L78.07,110l-51.65,19a15.92,15.92,0,0,0,0,29.88L78,178l19,51.62a15.92,15.92,0,0,0,29.88,0l19-51.61,51.65-19a15.92,15.92,0,0,0,0-29.88ZM140.39,163a15.87,15.87,0,0,0-9.43,9.43l-19,51.46L93,172.39A15.87,15.87,0,0,0,83.61,163h0L32.15,144l51.46-19A15.87,15.87,0,0,0,93,115.61l19-51.46,19,51.46a15.87,15.87,0,0,0,9.43,9.43l51.46,19ZM144,40a8,8,0,0,1,8-8h16V16a8,8,0,0,1,16,0V32h16a8,8,0,0,1,0,16H184V64a8,8,0,0,1-16,0V48H152A8,8,0,0,1,144,40ZM248,88a8,8,0,0,1-8,8h-8v8a8,8,0,0,1-16,0V96h-8a8,8,0,0,1,0-16h8V72a8,8,0,0,1,16,0v8h8A8,8,0,0,1,248,88Z"></path> + </svg> + ); +} diff --git a/apps/next/src/components/npm-install.tsx b/apps/next/src/components/npm-install.tsx index ef47752bcdc4e4b5402ae82a7a8a91ec6b8ef239..bfa0334e63003832d784e8a9bee745439132a118 100644 --- a/apps/next/src/components/npm-install.tsx +++ b/apps/next/src/components/npm-install.tsx @@ -22,7 +22,7 @@ export const NpmInstall = () => { .catch(console.error); }, [copy])} variant="outline" - className="bg-white flex flex-row items-center justify-center" + className="flex flex-row items-center justify-center" > <code className="mr-2">$ npm i llamaindex</code> <div className="relative cursor-pointer bg-transparent w-4 h-4"> @@ -31,14 +31,14 @@ export const NpmInstall = () => { hasCheckIcon ? "scale-0 opacity-0" : "scale-100 opacity-100" }`} > - <Copy className="h-4 w-4 text-zinc-800" /> + <Copy className="h-4 w-4 text-zinc-800 dark:text-zinc-200" /> </div> <div className={`absolute inset-0 transform transition-all duration-300 ${ hasCheckIcon ? "scale-100 opacity-100" : "scale-0 opacity-0" }`} > - <Check className="h-4 w-4 text-zinc-800" /> + <Check className="h-4 w-4 text-zinc-800 dark:text-zinc-200" /> </div> </div> </Button> diff --git a/apps/next/src/components/ui/input.tsx b/apps/next/src/components/ui/input.tsx new file mode 100644 index 0000000000000000000000000000000000000000..ef29a4ac929b2a1d437b35f22e70382895bb4424 --- /dev/null +++ b/apps/next/src/components/ui/input.tsx @@ -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-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50", + className, + )} + ref={ref} + {...props} + /> + ); + }, +); +Input.displayName = "Input"; + +export { Input }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4bab3fff52d3104de81c29c0da3c3520ddd820cf..a30538ba6e98f32a994f738c60b4a62916012d9f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15373,7 +15373,7 @@ snapshots: dependencies: '@aws-sdk/client-sso': 3.675.0 '@aws-sdk/core': 3.667.0 - '@aws-sdk/token-providers': 3.667.0(@aws-sdk/client-sso-oidc@3.678.0(@aws-sdk/client-sts@3.678.0)) + '@aws-sdk/token-providers': 3.667.0(@aws-sdk/client-sso-oidc@3.678.0(@aws-sdk/client-sts@3.650.0)) '@aws-sdk/types': 3.667.0 '@smithy/property-provider': 3.1.8 '@smithy/shared-ini-file-loader': 3.1.9 @@ -20905,7 +20905,7 @@ snapshots: '@types/react-router@5.1.20': dependencies: '@types/history': 4.7.11 - '@types/react': 18.3.5 + '@types/react': 18.3.12 '@types/react-syntax-highlighter@15.5.13': dependencies: @@ -23517,7 +23517,7 @@ snapshots: is-bun-module: 1.1.0 is-glob: 4.0.3 optionalDependencies: - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@8.10.0(eslint@8.57.0)(typescript@5.6.2))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node