Skip to content

Commit 50e7fe0

Browse files
committed
Add directives to change how sites generate
1 parent 5a705e8 commit 50e7fe0

File tree

5 files changed

+81
-5
lines changed

5 files changed

+81
-5
lines changed

app/api/html/route.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ export async function POST(req: NextRequest) {
2828
const url = formData.get("url")! as string;
2929
const rawDeps = (formData.get("deps") as string) || "[]";
3030
const deps = JSON.parse(rawDeps);
31+
const prompts = JSON.parse((formData.get("prompts")! as string) || "[]");
3132
const settings: Settings = JSON.parse(formData.get("settings")! as string);
3233
const programStream = await createProgramStream({
3334
url,
35+
prompts,
3436
// Keep only the last 3 deps
3537
deps: deps
3638
.filter(
@@ -57,11 +59,22 @@ async function createProgramStream({
5759
url,
5860
deps,
5961
settings,
62+
prompts,
6063
}: {
6164
url: string;
6265
deps: { url: string; html: string }[];
6366
settings: Settings;
67+
prompts: string[];
6468
}) {
69+
const makeMessage = (url: string) => {
70+
if (!prompts.length) {
71+
return `<url>${url}</url>`;
72+
}
73+
74+
return `${prompts
75+
.map((prompt) => `<directive>${prompt}</directive>`)
76+
.join("\n")}\n<url>${url}</url>`;
77+
};
6578
const params: ChatCompletionCreateParamsStreaming = {
6679
messages: [
6780
{
@@ -71,7 +84,7 @@ async function createProgramStream({
7184
...deps.flatMap((dep): ChatCompletionMessageParam[] => [
7285
{
7386
role: "user",
74-
content: dep.url,
87+
content: makeMessage(dep.url),
7588
},
7689
{
7790
role: "assistant",
@@ -83,7 +96,7 @@ async function createProgramStream({
8396
]),
8497
{
8598
role: "user",
86-
content: url,
99+
content: makeMessage(url),
87100
},
88101
],
89102

components/BottomBar.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Hand, MousePointer2, PanelTop } from "lucide-react";
1+
import { Hand, MousePointer2, PanelTop, ScrollText } from "lucide-react";
22
import { Card } from "./ui/card";
33
import { ToggleGroupItem, ToggleGroup } from "./ui/toggle-group";
44
import { useEditor, useValue } from "tldraw";
@@ -29,6 +29,9 @@ export function BottomBar() {
2929
<ToggleGroupItem value="browser" aria-label="browser">
3030
<PanelTop className="h-4 w-4" />
3131
</ToggleGroupItem>
32+
<ToggleGroupItem value="prompt" aria-label="prompt">
33+
<ScrollText className="h-4 w-4" />
34+
</ToggleGroupItem>
3235
</ToggleGroup>
3336
</Card>
3437
);

components/BrowserShape.tsx

+20-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
TLBaseShape,
88
TLShape,
99
TLShapeId,
10+
TLTextShape,
1011
Vec,
1112
toDomPrecision,
1213
useIsEditing,
@@ -245,6 +246,21 @@ export class BrowserShapeUtil extends BaseBoxShapeUtil<BrowserShape> {
245246
[this.editor]
246247
);
247248

249+
const promptsParam = useValue(
250+
"prompts",
251+
() => {
252+
return JSON.stringify(
253+
this.editor
254+
.getCurrentPageShapes()
255+
.filter((s): s is TLTextShape =>
256+
Boolean(s.type === "text" && s.meta.prompt)
257+
)
258+
.map((t) => t.props.text)
259+
);
260+
},
261+
[this.editor]
262+
);
263+
248264
// The deps are in top to bottom order
249265
const depsParams = useValue(
250266
"deps",
@@ -346,6 +362,7 @@ export class BrowserShapeUtil extends BaseBoxShapeUtil<BrowserShape> {
346362
/>
347363
<input type="hidden" name="deps" value={depsParams} />
348364
<input type="hidden" name="settings" value={settings} />
365+
<input type="hidden" name="prompts" value={promptsParam} />
349366
<Button
350367
type="submit"
351368
variant="ghost"
@@ -451,7 +468,9 @@ function getRotatedBoxShadow(rotation: number) {
451468
}
452469

453470
function LoadingBar() {
454-
return <div className="w-full h-2 bg-blue-600 animate-pulse" />;
471+
return (
472+
<div className="w-full h-1 bg-blue-600 animate-pulse absolute top-0 left-0" />
473+
);
455474
}
456475

457476
class RegisterOnce {

components/Canvas.tsx

+22-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { Button } from "./ui/button";
1111
import { snapshot } from "@/lib/snapshot";
1212
import { shouldUseAuth } from "@/lib/shouldUseAuth";
1313
import { Settings } from "@/components/Settings";
14+
import { PromptShapeTool } from "@/tools/PromptShapeTool";
1415

1516
const Tldraw = dynamic(async () => (await import("tldraw")).Tldraw, {
1617
ssr: false,
@@ -25,7 +26,7 @@ export function Canvas() {
2526
persistenceKey="tlweb"
2627
shapeUtils={shapeUtils}
2728
hideUi={false}
28-
tools={[BrowserTool]}
29+
tools={[BrowserTool, PromptShapeTool]}
2930
components={{
3031
Toolbar: null,
3132
PageMenu: null,
@@ -48,6 +49,26 @@ function UI() {
4849
}
4950
}, [editor]);
5051

52+
// useEffect(() => {
53+
// const unlisten = editor.store.listen(
54+
// (update) => {
55+
// for (const record of Object.values(update.changes.added)) {
56+
// if (record.typeName === "shape" && record.type === "text") {
57+
// editor.updateShape({
58+
// id: record.id,
59+
// type: record.type,
60+
// meta: {
61+
// prompt: true,
62+
// },
63+
// });
64+
// }
65+
// }
66+
// },
67+
// { scope: "document", source: "user" }
68+
// );
69+
// return unlisten;
70+
// }, [editor]);
71+
5172
return (
5273
<>
5374
<div

tools/PromptShapeTool.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { TLCompleteEventInfo, TLTextShape, TextShapeTool } from "tldraw";
2+
3+
export class PromptShapeTool extends TextShapeTool {
4+
static override id = "prompt";
5+
onExit = (info: TLCompleteEventInfo) => {
6+
const shape = this.editor.getEditingShape();
7+
console.log("onDragExit", shape);
8+
if (!shape) return;
9+
this.editor.updateShape<TLTextShape>({
10+
id: shape.id,
11+
type: "text",
12+
meta: {
13+
prompt: true,
14+
},
15+
props: {
16+
color: "light-violet",
17+
},
18+
});
19+
};
20+
}

0 commit comments

Comments
 (0)