Skip to content

Commit ee69ce7

Browse files
authored
bump: chat-ui and tailwind v4 (#509)
1 parent 0e4ecfa commit ee69ce7

16 files changed

+142
-162
lines changed

.changeset/rare-eyes-protect.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"create-llama": patch
3+
---
4+
5+
bump: chat-ui and tailwind v4

templates/types/streaming/nextjs/app/components/header.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import Image from "next/image";
33
export default function Header() {
44
return (
55
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
6-
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
6+
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-linear-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
77
Get started by editing&nbsp;
88
<code className="font-mono font-bold">app/page.tsx</code>
99
</p>
10-
<div className="fixed bottom-0 left-0 mb-4 flex h-auto w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:w-auto lg:bg-none lg:mb-0">
10+
<div className="fixed bottom-0 left-0 mb-4 flex h-auto w-full items-end justify-center bg-linear-to-t from-white via-white dark:from-black dark:via-black lg:static lg:w-auto lg:bg-none lg:mb-0">
1111
<a
1212
href="https://www.llamaindex.ai/"
1313
className="flex items-center justify-center font-nunito text-lg font-bold gap-2"

templates/types/streaming/nextjs/app/components/ui/button.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as React from "react";
55
import { cn } from "./lib/utils";
66

77
const buttonVariants = cva(
8-
"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",
8+
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
99
{
1010
variants: {
1111
variant: {

templates/types/streaming/nextjs/app/components/ui/card.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const Card = React.forwardRef<
88
<div
99
ref={ref}
1010
className={cn(
11-
"rounded-xl border border-neutral-200 bg-white text-neutral-950 shadow dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50",
11+
"rounded-xl border border-neutral-200 bg-white text-neutral-950 shadow-sm dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50",
1212
className,
1313
)}
1414
{...props}

templates/types/streaming/nextjs/app/components/ui/chat/chat-avatar.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ export function ChatMessageAvatar() {
66
const { message } = useChatMessage();
77
if (message.role === "user") {
88
return (
9-
<div className="flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border bg-background shadow">
9+
<div className="flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border bg-background shadow-sm">
1010
<User2 className="h-4 w-4" />
1111
</div>
1212
);
1313
}
1414

1515
return (
16-
<div className="flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border bg-black text-white shadow">
16+
<div className="flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border bg-black text-white shadow-sm">
1717
<Image
1818
className="rounded-md"
1919
src="/llama.png"
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,19 @@
1-
import {
2-
ChatMessage,
3-
ContentPosition,
4-
getSourceAnnotationData,
5-
useChatMessage,
6-
useChatUI,
7-
} from "@llamaindex/chat-ui";
1+
import { ChatMessage } from "@llamaindex/chat-ui";
82
import { DeepResearchCard } from "./custom/deep-research-card";
9-
import { Markdown } from "./custom/markdown";
103
import { ToolAnnotations } from "./tools/chat-tools";
114

125
export function ChatMessageContent() {
13-
const { isLoading, append } = useChatUI();
14-
const { message } = useChatMessage();
15-
const customContent = [
16-
{
17-
// override the default markdown component
18-
position: ContentPosition.MARKDOWN,
19-
component: (
20-
<Markdown
21-
content={message.content}
22-
sources={getSourceAnnotationData(message.annotations)?.[0]}
23-
/>
24-
),
25-
},
26-
// add the deep research card
27-
{
28-
position: ContentPosition.CHAT_EVENTS,
29-
component: <DeepResearchCard message={message} />,
30-
},
31-
{
32-
// add the tool annotations after events
33-
position: ContentPosition.AFTER_EVENTS,
34-
component: <ToolAnnotations message={message} />,
35-
},
36-
];
376
return (
38-
<ChatMessage.Content
39-
content={customContent}
40-
isLoading={isLoading}
41-
append={append}
42-
/>
7+
<ChatMessage.Content>
8+
<ChatMessage.Content.Event />
9+
<ChatMessage.Content.AgentEvent />
10+
<DeepResearchCard />
11+
<ToolAnnotations />
12+
<ChatMessage.Content.Image />
13+
<ChatMessage.Content.Markdown />
14+
<ChatMessage.Content.DocumentFile />
15+
<ChatMessage.Content.Source />
16+
<ChatMessage.Content.SuggestedQuestions />
17+
</ChatMessage.Content>
4318
);
4419
}

templates/types/streaming/nextjs/app/components/ui/chat/custom/deep-research-card.tsx

+12-19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import { Message } from "@llamaindex/chat-ui";
3+
import { getCustomAnnotation, useChatMessage } from "@llamaindex/chat-ui";
44
import {
55
AlertCircle,
66
CheckCircle2,
@@ -54,7 +54,6 @@ type DeepResearchCardState = {
5454
};
5555

5656
interface DeepResearchCardProps {
57-
message: Message;
5857
className?: string;
5958
}
6059

@@ -143,25 +142,19 @@ const deepResearchEventsToState = (
143142
);
144143
};
145144

146-
export function DeepResearchCard({
147-
message,
148-
className,
149-
}: DeepResearchCardProps) {
150-
const deepResearchEvents = message.annotations as
151-
| DeepResearchEvent[]
152-
| undefined;
153-
const hasDeepResearchEvents = deepResearchEvents?.some(
154-
(event) => event.type === "deep_research_event",
155-
);
145+
export function DeepResearchCard({ className }: DeepResearchCardProps) {
146+
const { message } = useChatMessage();
156147

157-
const state = useMemo(
158-
() => deepResearchEventsToState(deepResearchEvents),
159-
[deepResearchEvents],
160-
);
148+
const state = useMemo(() => {
149+
const deepResearchEvents = getCustomAnnotation<DeepResearchEvent>(
150+
message.annotations,
151+
(annotation) => annotation?.type === "deep_research_event",
152+
);
153+
if (!deepResearchEvents.length) return null;
154+
return deepResearchEventsToState(deepResearchEvents);
155+
}, [message.annotations]);
161156

162-
if (!hasDeepResearchEvents) {
163-
return null;
164-
}
157+
if (!state) return null;
165158

166159
return (
167160
<Card className={cn("w-full", className)}>

templates/types/streaming/nextjs/app/components/ui/chat/tools/chat-tools.tsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
import {
22
Message,
33
MessageAnnotation,
4-
getAnnotationData,
4+
getChatUIAnnotation,
5+
useChatMessage,
56
useChatUI,
67
} from "@llamaindex/chat-ui";
78
import { JSONValue } from "ai";
89
import { useMemo } from "react";
910
import { Artifact, CodeArtifact } from "./artifact";
1011
import { WeatherCard, WeatherData } from "./weather-card";
1112

12-
export function ToolAnnotations({ message }: { message: Message }) {
13+
export function ToolAnnotations() {
1314
// TODO: This is a bit of a hack to get the artifact version. better to generate the version in the tool call and
1415
// store it in CodeArtifact
1516
const { messages } = useChatUI();
17+
const { message } = useChatMessage();
1618
const artifactVersion = useMemo(
1719
() => getArtifactVersion(messages, message),
1820
[messages, message],
1921
);
2022
// Get the tool data from the message annotations
2123
const annotations = message.annotations as MessageAnnotation[] | undefined;
2224
const toolData = annotations
23-
? (getAnnotationData(annotations, "tools") as unknown as ToolData[])
25+
? (getChatUIAnnotation(annotations, "tools") as unknown as ToolData[])
2426
: null;
2527
return toolData?.[0] ? (
2628
<ChatTools data={toolData[0]} artifactVersion={artifactVersion} />
@@ -87,7 +89,7 @@ function getArtifactVersion(
8789
let versionIndex = 1;
8890
for (const m of messages) {
8991
const toolData = m.annotations
90-
? (getAnnotationData(m.annotations, "tools") as unknown as ToolData[])
92+
? (getChatUIAnnotation(m.annotations, "tools") as unknown as ToolData[])
9193
: null;
9294

9395
if (toolData?.some((t) => t.toolCall.name === "artifact")) {

templates/types/streaming/nextjs/app/components/ui/input.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
1111
<input
1212
type={type}
1313
className={cn(
14-
"flex h-10 w-full rounded-md border border-input bg-background 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",
14+
"flex h-10 w-full rounded-md border border-input bg-background 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-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
1515
className,
1616
)}
1717
ref={ref}

templates/types/streaming/nextjs/app/components/ui/select.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const SelectTrigger = React.forwardRef<
1818
<SelectPrimitive.Trigger
1919
ref={ref}
2020
className={cn(
21-
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
21+
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
2222
className,
2323
)}
2424
{...props}
@@ -117,7 +117,7 @@ const SelectItem = React.forwardRef<
117117
<SelectPrimitive.Item
118118
ref={ref}
119119
className={cn(
120-
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
120+
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
121121
className,
122122
)}
123123
{...props}

templates/types/streaming/nextjs/app/components/ui/tabs.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const TabsTrigger = React.forwardRef<
2828
<TabsPrimitive.Trigger
2929
ref={ref}
3030
className={cn(
31-
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
31+
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
3232
className,
3333
)}
3434
{...props}
@@ -43,7 +43,7 @@ const TabsContent = React.forwardRef<
4343
<TabsPrimitive.Content
4444
ref={ref}
4545
className={cn(
46-
"ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
46+
"ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
4747
className,
4848
)}
4949
{...props}

templates/types/streaming/nextjs/app/components/ui/textarea.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
99
return (
1010
<textarea
1111
className={cn(
12-
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background 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",
12+
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
1313
className,
1414
)}
1515
ref={ref}

templates/types/streaming/nextjs/app/globals.css

+91-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,94 @@
1-
@tailwind base;
2-
@tailwind components;
3-
@tailwind utilities;
1+
@import "tailwindcss";
2+
3+
@source '../node_modules/@llamaindex/chat-ui/**/*.{ts,tsx}';
4+
5+
@custom-variant dark (&:is(.dark *));
6+
7+
@theme {
8+
--color-border: hsl(var(--border));
9+
--color-input: hsl(var(--input));
10+
--color-ring: hsl(var(--ring));
11+
--color-background: hsl(var(--background));
12+
--color-foreground: hsl(var(--foreground));
13+
14+
--color-primary: hsl(var(--primary));
15+
--color-primary-foreground: hsl(var(--primary-foreground));
16+
17+
--color-secondary: hsl(var(--secondary));
18+
--color-secondary-foreground: hsl(var(--secondary-foreground));
19+
20+
--color-destructive: hsl(var(--destructive));
21+
--color-destructive-foreground: hsl(var(--destructive-foreground));
22+
23+
--color-muted: hsl(var(--muted));
24+
--color-muted-foreground: hsl(var(--muted-foreground));
25+
26+
--color-accent: hsl(var(--accent));
27+
--color-accent-foreground: hsl(var(--accent-foreground));
28+
29+
--color-popover: hsl(var(--popover));
30+
--color-popover-foreground: hsl(var(--popover-foreground));
31+
32+
--color-card: hsl(var(--card));
33+
--color-card-foreground: hsl(var(--card-foreground));
34+
35+
--radius-xl: calc(var(--radius) + 4px);
36+
--radius-lg: var(--radius);
37+
--radius-md: calc(var(--radius) - 2px);
38+
--radius-sm: calc(var(--radius) - 4px);
39+
40+
--font-sans: var(--font-sans), ui-sans-serif, system-ui, sans-serif,
41+
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
42+
43+
--animate-accordion-down: accordion-down 0.2s ease-out;
44+
--animate-accordion-up: accordion-up 0.2s ease-out;
45+
46+
@keyframes accordion-down {
47+
from {
48+
height: 0;
49+
}
50+
to {
51+
height: var(--radix-accordion-content-height);
52+
}
53+
}
54+
@keyframes accordion-up {
55+
from {
56+
height: var(--radix-accordion-content-height);
57+
}
58+
to {
59+
height: 0;
60+
}
61+
}
62+
}
63+
64+
@utility container {
65+
margin-inline: auto;
66+
padding-inline: 2rem;
67+
@media (width >= --theme(--breakpoint-sm)) {
68+
max-width: none;
69+
}
70+
@media (width >= 1400px) {
71+
max-width: 1400px;
72+
}
73+
}
74+
75+
/*
76+
The default border color has changed to `currentColor` in Tailwind CSS v4,
77+
so we've added these compatibility styles to make sure everything still
78+
looks the same as it did with Tailwind CSS v3.
79+
80+
If we ever want to remove these styles, we need to add an explicit border
81+
color utility to any element that depends on these defaults.
82+
*/
83+
@layer base {
84+
*,
85+
::after,
86+
::before,
87+
::backdrop,
88+
::file-selector-button {
89+
border-color: var(--color-gray-200, currentColor);
90+
}
91+
}
492

593
@layer base {
694
:root {

templates/types/streaming/nextjs/package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"@radix-ui/react-select": "^2.1.1",
1818
"@radix-ui/react-slot": "^1.0.2",
1919
"@radix-ui/react-tabs": "^1.1.0",
20-
"@llamaindex/chat-ui": "0.0.14",
20+
"@llamaindex/chat-ui": "^0.2.0",
2121
"ai": "^4.0.3",
2222
"ajv": "^8.12.0",
2323
"class-variance-authority": "^0.7.1",
@@ -46,15 +46,15 @@
4646
"@types/uuid": "^9.0.8",
4747
"@llamaindex/workflow": "^0.0.3",
4848
"@types/papaparse": "^5.3.15",
49-
"autoprefixer": "^10.4.16",
49+
"@tailwindcss/postcss": "^4.0.8",
5050
"cross-env": "^7.0.3",
5151
"eslint": "^9.14.0",
5252
"eslint-config-next": "^15.1.3",
5353
"eslint-config-prettier": "^9.1.0",
5454
"postcss": "^8.4.32",
5555
"prettier": "^3.2.5",
5656
"prettier-plugin-organize-imports": "^3.2.4",
57-
"tailwindcss": "^3.3.6",
57+
"tailwindcss": "^4.0.8",
5858
"tsx": "^4.7.2",
5959
"typescript": "^5.3.2"
6060
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
module.exports = {
22
plugins: {
3-
tailwindcss: {},
4-
autoprefixer: {},
3+
"@tailwindcss/postcss": {},
54
},
65
};

0 commit comments

Comments
 (0)