Skip to content

Commit 28bcf17

Browse files
committed
Add shadcn to initial prompt
1 parent bfe5b2d commit 28bcf17

23 files changed

Lines changed: 214 additions & 43 deletions

_components/code-viewer.tsx

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import * as shadcnComponents from "@/utils/shadcn";
3+
import * as shadcnComponents from "@/lib/shadcn";
44
import { Sandpack } from "@codesandbox/sandpack-react";
55
import {
66
SandpackPreview,
@@ -17,21 +17,7 @@ export default function CodeViewer({
1717
code: string;
1818
showEditor?: boolean;
1919
}) {
20-
return showEditor ? (
21-
<Sandpack
22-
options={{
23-
showNavigator: true,
24-
editorHeight: "80vh",
25-
showTabs: false,
26-
...sharedOptions,
27-
}}
28-
files={{
29-
"App.tsx": code,
30-
...sharedFiles,
31-
}}
32-
{...sharedProps}
33-
/>
34-
) : (
20+
return (
3521
<SandpackProvider
3622
files={{
3723
"App.tsx": code,

app/(main)/actions.ts

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
"use server";
22

33
import prisma from "@/lib/prisma";
4+
import shadcnDocs from "@/lib/shadcn-docs";
45
import dedent from "dedent";
56
import { notFound } from "next/navigation";
67
import Together from "together-ai";
78
import { z } from "zod";
89

910
const together = new Together();
1011

11-
export async function createChat(prompt: string, model: string) {
12+
export async function createChat(
13+
prompt: string,
14+
model: string,
15+
shadcn: boolean = true,
16+
) {
1217
const res = await together.chat.completions.create({
1318
model: "meta-llama/Llama-3.2-3B-Instruct-Turbo",
1419
// model: "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
@@ -33,7 +38,7 @@ export async function createChat(prompt: string, model: string) {
3338
messages: {
3439
createMany: {
3540
data: [
36-
{ role: "system", content: systemPrompt, position: 0 },
41+
{ role: "system", content: getSystemPrompt(shadcn), position: 0 },
3742
{ role: "user", content: prompt, position: 1 },
3843
],
3944
},
@@ -136,6 +141,84 @@ export async function getNextCompletionStreamPromise(
136141
};
137142
}
138143

144+
function getSystemPrompt(shadcn: boolean) {
145+
let systemPrompt = `
146+
You are an expert frontend React engineer who is also a great UI/UX designer. Follow the instructions carefully, I will tip you $1 million if you do a good job:
147+
148+
- Think carefully step by step.
149+
- Create a React component for whatever the user asked you to create and make sure it can run by itself by using a default export
150+
- Make sure the React app is interactive and functional by creating state when needed and having no required props
151+
- If you use any imports from React like useState or useEffect, make sure to import them directly
152+
- Use TypeScript as the language for the React component
153+
- Use Tailwind classes for styling. DO NOT USE ARBITRARY VALUES (e.g. \`h-[600px]\`). Make sure to use a consistent color palette.
154+
- Use Tailwind margin and padding classes to style the components and ensure the components are spaced out nicely
155+
- ONLY IF the user asks for a dashboard, graph or chart, the recharts library is available to be imported, e.g. \`import { LineChart, XAxis, ... } from "recharts"\` & \`<LineChart ...><XAxis dataKey="name"> ...\`. Please only use this when needed.
156+
- For placeholder images, please use a <div className="bg-gray-200 border-2 border-dashed rounded-xl w-16 h-16" />
157+
`;
158+
159+
// - The lucide-react library is also available to be imported IF NECCESARY ONLY FOR THE FOLLOWING ICONS: Heart, Shield, Clock, Users, Play, Home, Search, Menu, User, Settings, Mail, Bell, Calendar, Clock, Heart, Star, Upload, Download, Trash, Edit, Plus, Minus, Check, X, ArrowRight.
160+
// - Here's an example of importing and using one: import { Heart } from "lucide-react"\` & \`<Heart className="" />\`.
161+
// - PLEASE ONLY USE THE ICONS LISTED ABOVE IF AN ICON IS NEEDED IN THE USER'S REQUEST. Please DO NOT use the lucide-react library if it's not needed.
162+
163+
if (shadcn) {
164+
systemPrompt += `
165+
There are some prestyled components available for use. Please use your best judgement to use any of these components if the app calls for one.
166+
167+
Here are the components that are available, along with how to import them, and how to use them:
168+
169+
${shadcnDocs
170+
.map(
171+
(component) => `
172+
<component>
173+
<name>
174+
${component.name}
175+
</name>
176+
<import-instructions>
177+
${component.importDocs}
178+
</import-instructions>
179+
<usage-instructions>
180+
${component.usageDocs}
181+
</usage-instructions>
182+
</component>
183+
`,
184+
)
185+
.join("\n")}
186+
187+
Remember, if you use a prestyled component, make sure to import it.
188+
`;
189+
}
190+
191+
systemPrompt += `
192+
NO OTHER LIBRARIES (e.g. zod, hookform) ARE INSTALLED OR ABLE TO BE IMPORTED.
193+
194+
Explain your work. The first codefence should be the main React component. It should also use "tsx" as the language, and be followed by a sensible filename for the code. Use this format: \`\`\`tsx{filename=calculator.tsx}.
195+
`;
196+
197+
// systemPrompt += `
198+
// Here are some examples of a good response:
199+
200+
// ${examples
201+
// .map(
202+
// (example) => `
203+
// <example>
204+
// <prompt>
205+
// ${example.prompt}
206+
// </prompt>
207+
// <response>
208+
// ${example.response}
209+
// </response>
210+
// </example>
211+
// `,
212+
// )
213+
// .join("\n")}
214+
// `;
215+
216+
return dedent(systemPrompt);
217+
}
218+
219+
/*
220+
This is the prompt we originaly used for the new chat interface.
221+
139222
const systemPrompt = dedent`
140223
You are an expert software developer who knows three technologies: React, Python, and Node.js.
141224
@@ -150,5 +233,5 @@ const systemPrompt = dedent`
150233
- If you're writing a React component, make sure you don't use any external dependencies, and export a single React component as the default export. Use TypeScript as the language, with "tsx" for any code fences. You can also use Tailwind classes for styling, making sure not to use arbitrary values.
151234
152235
- If you're writing a Python or Node script, make sure running the script executes the code you wrote and prints some output to the console.
153-
154236
`;
237+
*/

app/(main)/chats/[id]/chat-box.tsx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ export default function ChatBox({
4444
}}
4545
>
4646
<fieldset className="w-full" disabled={disabled}>
47-
<div className="relative flex rounded-lg border-4 border-gray-300 bg-white pb-8">
47+
<div className="relative flex rounded-lg border-4 border-gray-300 bg-white">
4848
<TextareaAutosize
4949
placeholder="Follow up"
50+
autoFocus
5051
required
5152
name="prompt"
52-
rows={1}
53+
rows={2}
54+
minRows={2}
5355
className="peer relative w-full resize-none bg-transparent p-2 placeholder-gray-500 focus:outline-none disabled:opacity-50"
5456
onKeyDown={(event) => {
5557
if (event.key === "Enter" && !event.shiftKey) {
@@ -62,19 +64,17 @@ export default function ChatBox({
6264
/>
6365
<div className="pointer-events-none absolute inset-0 rounded peer-focus:outline peer-focus:outline-offset-0 peer-focus:outline-blue-500" />
6466

65-
<div className="absolute inset-x-1.5 bottom-1.5 flex justify-end">
66-
<div className="relative flex has-[:disabled]:opacity-50">
67-
<div className="pointer-events-none absolute inset-0 -bottom-[1px] rounded bg-blue-700" />
67+
<div className="absolute bottom-1.5 right-1.5 flex has-[:disabled]:opacity-50">
68+
<div className="pointer-events-none absolute inset-0 -bottom-[1px] rounded bg-blue-700" />
6869

69-
<button
70-
className="relative inline-flex size-6 items-center justify-center rounded bg-blue-500 font-medium text-white shadow-lg outline-blue-300 focus:outline focus:outline-2 focus:outline-offset-2"
71-
type="submit"
72-
>
73-
<Spinner loading={disabled}>
74-
<ArrowRightIcon />
75-
</Spinner>
76-
</button>
77-
</div>
70+
<button
71+
className="relative inline-flex size-6 items-center justify-center rounded bg-blue-500 font-medium text-white shadow-lg outline-blue-300 hover:bg-blue-500/75 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
72+
type="submit"
73+
>
74+
<Spinner loading={disabled}>
75+
<ArrowRightIcon />
76+
</Spinner>
77+
</button>
7878
</div>
7979
</div>
8080
</fieldset>

app/(main)/chats/[id]/code-viewer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export default function CodeViewer({
6464

6565
return (
6666
<>
67-
<div className="flex h-16 items-center justify-between border-b border-gray-300 px-4">
67+
<div className="flex h-16 shrink-0 items-center justify-between border-b border-gray-300 px-4">
6868
<div className="inline-flex items-center gap-4">
6969
<button
7070
className="text-gray-400 hover:text-gray-700"

app/(main)/chats/[id]/share.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export function Share({ message }: { message?: Message }) {
2525
<button
2626
type="submit"
2727
disabled={!message}
28-
className="inline-flex items-center gap-1 rounded border border-gray-300 px-1.5 py-0.5 text-sm text-gray-600 transition enabled:hover:bg-white disabled:opacity-50"
28+
className="inline-flex items-center gap-1 rounded border border-gray-300 px-1.5 py-0.5 text-sm text-gray-600 enabled:hover:bg-white disabled:opacity-50"
2929
>
3030
<ShareIcon className="size-3" />
3131
Share

app/(main)/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export default function Home() {
8080
}}
8181
>
8282
<Fieldset>
83-
<div className="relative flex rounded-lg border-4 border-gray-300 bg-white pb-8">
83+
<div className="relative flex rounded-lg border-4 border-gray-300 bg-white pb-10">
8484
<TextareaAutosize
8585
placeholder="Build me a budgeting app..."
8686
required
@@ -114,7 +114,7 @@ export default function Home() {
114114
<div className="relative flex has-[:disabled]:opacity-50">
115115
<div className="pointer-events-none absolute inset-0 -bottom-[1px] rounded bg-blue-700" />
116116
<LoadingButton
117-
className="relative inline-flex size-6 items-center justify-center rounded bg-blue-500 font-medium text-white shadow-lg outline-blue-300 focus:outline focus:outline-2 focus:outline-offset-2"
117+
className="relative inline-flex size-6 items-center justify-center rounded bg-blue-500 font-medium text-white shadow-lg outline-blue-300 hover:bg-blue-500/75 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
118118
type="submit"
119119
>
120120
<ArrowRightIcon />
@@ -128,7 +128,7 @@ export default function Home() {
128128
key={v}
129129
type="button"
130130
onClick={() => setPrompt(v)}
131-
className="rounded bg-gray-200 px-2.5 py-1.5 text-xs outline-blue-300"
131+
className="rounded bg-gray-200 px-2.5 py-1.5 text-xs hover:bg-gray-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-300"
132132
>
133133
{v}
134134
</button>

app/api/generateCode/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import shadcnDocs from "@/utils/shadcn-docs";
1+
import shadcnDocs from "@/lib/shadcn-docs";
22
import dedent from "dedent";
33
import Together from "together-ai";
44
import { z } from "zod";

app/api/og/route.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ImageResponse } from "next/og";
2-
import { domain } from "@/utils/domain";
2+
import { domain } from "@/lib/domain";
33
export async function GET(request: Request) {
44
const { searchParams } = new URL(request.url);
55
const prompt = searchParams.get("prompt");

components/code-runner-react.tsx

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,132 @@
11
"use client";
22

3+
import * as shadcnComponents from "@/lib/shadcn";
34
import {
45
SandpackPreview,
56
SandpackProvider,
67
} from "@codesandbox/sandpack-react/unstyled";
8+
import dedent from "dedent";
79

810
export default function ReactCodeRunner({ code }: { code: string }) {
911
return (
1012
<SandpackProvider
1113
key={code}
12-
files={{ "App.tsx": { code } }}
1314
template="react-ts"
15+
files={{
16+
"App.tsx": code,
17+
...shadcnFiles,
18+
}}
1419
options={{
1520
externalResources: [
1621
"https://unpkg.com/@tailwindcss/ui/dist/tailwind-ui.min.css",
1722
],
1823
}}
24+
customSetup={{
25+
dependencies,
26+
}}
1927
>
2028
<SandpackPreview
2129
showNavigator={false}
2230
showOpenInCodeSandbox={false}
2331
showRefreshButton={false}
2432
showRestartButton={false}
2533
showOpenNewtab={false}
26-
className="aspect-square w-full"
34+
className="w-full"
2735
/>
2836
</SandpackProvider>
2937
);
3038
}
39+
40+
const shadcnFiles = {
41+
"/lib/utils.ts": shadcnComponents.utils,
42+
"/components/ui/accordion.tsx": shadcnComponents.accordian,
43+
"/components/ui/alert-dialog.tsx": shadcnComponents.alertDialog,
44+
"/components/ui/alert.tsx": shadcnComponents.alert,
45+
"/components/ui/avatar.tsx": shadcnComponents.avatar,
46+
"/components/ui/badge.tsx": shadcnComponents.badge,
47+
"/components/ui/breadcrumb.tsx": shadcnComponents.breadcrumb,
48+
"/components/ui/button.tsx": shadcnComponents.button,
49+
"/components/ui/calendar.tsx": shadcnComponents.calendar,
50+
"/components/ui/card.tsx": shadcnComponents.card,
51+
"/components/ui/carousel.tsx": shadcnComponents.carousel,
52+
"/components/ui/checkbox.tsx": shadcnComponents.checkbox,
53+
"/components/ui/collapsible.tsx": shadcnComponents.collapsible,
54+
"/components/ui/dialog.tsx": shadcnComponents.dialog,
55+
"/components/ui/drawer.tsx": shadcnComponents.drawer,
56+
"/components/ui/dropdown-menu.tsx": shadcnComponents.dropdownMenu,
57+
"/components/ui/input.tsx": shadcnComponents.input,
58+
"/components/ui/label.tsx": shadcnComponents.label,
59+
"/components/ui/menubar.tsx": shadcnComponents.menuBar,
60+
"/components/ui/navigation-menu.tsx": shadcnComponents.navigationMenu,
61+
"/components/ui/pagination.tsx": shadcnComponents.pagination,
62+
"/components/ui/popover.tsx": shadcnComponents.popover,
63+
"/components/ui/progress.tsx": shadcnComponents.progress,
64+
"/components/ui/radio-group.tsx": shadcnComponents.radioGroup,
65+
"/components/ui/select.tsx": shadcnComponents.select,
66+
"/components/ui/separator.tsx": shadcnComponents.separator,
67+
"/components/ui/skeleton.tsx": shadcnComponents.skeleton,
68+
"/components/ui/slider.tsx": shadcnComponents.slider,
69+
"/components/ui/switch.tsx": shadcnComponents.switchComponent,
70+
"/components/ui/table.tsx": shadcnComponents.table,
71+
"/components/ui/tabs.tsx": shadcnComponents.tabs,
72+
"/components/ui/textarea.tsx": shadcnComponents.textarea,
73+
"/components/ui/toast.tsx": shadcnComponents.toast,
74+
"/components/ui/toaster.tsx": shadcnComponents.toaster,
75+
"/components/ui/toggle-group.tsx": shadcnComponents.toggleGroup,
76+
"/components/ui/toggle.tsx": shadcnComponents.toggle,
77+
"/components/ui/tooltip.tsx": shadcnComponents.tooltip,
78+
"/components/ui/use-toast.tsx": shadcnComponents.useToast,
79+
"/public/index.html": dedent`
80+
<!DOCTYPE html>
81+
<html lang="en">
82+
<head>
83+
<meta charset="UTF-8">
84+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
85+
<title>Document</title>
86+
<script src="https://cdn.tailwindcss.com"></script>
87+
</head>
88+
<body>
89+
<div id="root"></div>
90+
</body>
91+
</html>
92+
`,
93+
};
94+
95+
const dependencies = {
96+
"lucide-react": "latest",
97+
recharts: "2.9.0",
98+
"react-router-dom": "latest",
99+
"@radix-ui/react-accordion": "^1.2.0",
100+
"@radix-ui/react-alert-dialog": "^1.1.1",
101+
"@radix-ui/react-aspect-ratio": "^1.1.0",
102+
"@radix-ui/react-avatar": "^1.1.0",
103+
"@radix-ui/react-checkbox": "^1.1.1",
104+
"@radix-ui/react-collapsible": "^1.1.0",
105+
"@radix-ui/react-dialog": "^1.1.1",
106+
"@radix-ui/react-dropdown-menu": "^2.1.1",
107+
"@radix-ui/react-hover-card": "^1.1.1",
108+
"@radix-ui/react-label": "^2.1.0",
109+
"@radix-ui/react-menubar": "^1.1.1",
110+
"@radix-ui/react-navigation-menu": "^1.2.0",
111+
"@radix-ui/react-popover": "^1.1.1",
112+
"@radix-ui/react-progress": "^1.1.0",
113+
"@radix-ui/react-radio-group": "^1.2.0",
114+
"@radix-ui/react-select": "^2.1.1",
115+
"@radix-ui/react-separator": "^1.1.0",
116+
"@radix-ui/react-slider": "^1.2.0",
117+
"@radix-ui/react-slot": "^1.1.0",
118+
"@radix-ui/react-switch": "^1.1.0",
119+
"@radix-ui/react-tabs": "^1.1.0",
120+
"@radix-ui/react-toast": "^1.2.1",
121+
"@radix-ui/react-toggle": "^1.1.0",
122+
"@radix-ui/react-toggle-group": "^1.1.0",
123+
"@radix-ui/react-tooltip": "^1.1.2",
124+
"class-variance-authority": "^0.7.0",
125+
clsx: "^2.1.1",
126+
"date-fns": "^3.6.0",
127+
"embla-carousel-react": "^8.1.8",
128+
"react-day-picker": "^8.10.1",
129+
"tailwind-merge": "^2.4.0",
130+
"tailwindcss-animate": "^1.0.7",
131+
vaul: "^0.9.1",
132+
};

0 commit comments

Comments
 (0)