Skip to content

Commit 1e9d11d

Browse files
breadonceejerelvelarde
authored andcommitted
feat: improve template apply UX with data input step
- Apply button now prompts user to describe their new data before sending to the agent (textarea with placeholder example) - Template HTML is passed directly in the prompt so the agent doesn't need to look it up from backend state (fixes state sync issue where frontend setState wasn't visible to agent tools) - Fix template card callback signatures
1 parent 245b314 commit 1e9d11d

2 files changed

Lines changed: 102 additions & 7 deletions

File tree

apps/app/src/components/template-library/index.tsx

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

3+
import { useState } from "react";
34
import { useAgent } from "@copilotkit/react-core/v2";
45
import { TemplateCard } from "./template-card";
56

@@ -22,11 +23,39 @@ export function TemplateLibrary({ open, onClose, onSendPrompt }: TemplateLibrary
2223
const { agent } = useAgent();
2324
const templates: Template[] = agent.state?.templates || [];
2425

25-
const handleApply = (id: string, name: string) => {
26-
onSendPrompt(`Apply the "${name}" template (id: ${id}) to my new data`);
26+
// Apply flow: show input for new data before sending
27+
const [applyingTemplate, setApplyingTemplate] = useState<Template | null>(null);
28+
const [applyData, setApplyData] = useState("");
29+
30+
const handleApplyClick = (id: string) => {
31+
const template = templates.find((t) => t.id === id);
32+
if (template) {
33+
setApplyingTemplate(template);
34+
setApplyData("");
35+
}
36+
};
37+
38+
const handleApplyConfirm = () => {
39+
if (!applyingTemplate) return;
40+
const dataDesc = applyData.trim();
41+
if (!dataDesc) return;
42+
43+
// Send the template HTML directly in the prompt so the agent doesn't
44+
// need to look it up from state (frontend setState may not sync to backend)
45+
onSendPrompt(
46+
`Use this saved template called "${applyingTemplate.name}" as a base layout and adapt it for the following new data: ${dataDesc}\n\n` +
47+
`Here is the template HTML to adapt:\n\n${applyingTemplate.html}`
48+
);
49+
setApplyingTemplate(null);
50+
setApplyData("");
2751
onClose();
2852
};
2953

54+
const handleApplyCancel = () => {
55+
setApplyingTemplate(null);
56+
setApplyData("");
57+
};
58+
3059
const handleDelete = (id: string) => {
3160
agent.setState({
3261
templates: templates.filter((t) => t.id !== id),
@@ -126,13 +155,79 @@ export function TemplateLibrary({ open, onClose, onSendPrompt }: TemplateLibrary
126155
html={t.html}
127156
dataDescription={t.data_description}
128157
version={t.version}
129-
onApply={handleApply}
158+
onApply={handleApplyClick}
130159
onDelete={handleDelete}
131160
/>
132161
))}
133162
</div>
134163
)}
135164
</div>
165+
166+
{/* Apply data input — slides up from bottom of drawer */}
167+
{applyingTemplate && (
168+
<div
169+
className="shrink-0 px-4 pb-4 pt-3"
170+
style={{
171+
borderTop: "1px solid var(--color-border-glass, rgba(0,0,0,0.1))",
172+
animation: "tmpl-slideIn 0.2s ease-out",
173+
}}
174+
>
175+
<p
176+
className="text-xs font-semibold mb-1"
177+
style={{ color: "var(--text-primary, #1a1a1a)" }}
178+
>
179+
Apply &quot;{applyingTemplate.name}&quot;
180+
</p>
181+
<p
182+
className="text-[11px] mb-2"
183+
style={{ color: "var(--text-tertiary, #999)" }}
184+
>
185+
Describe the new data you want to populate this template with:
186+
</p>
187+
<textarea
188+
value={applyData}
189+
onChange={(e) => setApplyData(e.target.value)}
190+
onKeyDown={(e) => {
191+
if (e.key === "Enter" && !e.shiftKey) {
192+
e.preventDefault();
193+
handleApplyConfirm();
194+
}
195+
if (e.key === "Escape") handleApplyCancel();
196+
}}
197+
autoFocus
198+
placeholder='e.g. "$2,400 web design project for Sarah Chen, due April 15"'
199+
rows={2}
200+
className="w-full text-xs px-3 py-2 rounded-lg outline-none resize-none"
201+
style={{
202+
background: "var(--color-background-secondary, #f5f5f5)",
203+
color: "var(--text-primary, #1a1a1a)",
204+
border: "1px solid var(--color-border-tertiary, rgba(0,0,0,0.1))",
205+
}}
206+
/>
207+
<div className="flex gap-2 mt-2">
208+
<button
209+
onClick={handleApplyConfirm}
210+
disabled={!applyData.trim()}
211+
className="flex-1 text-xs font-medium py-1.5 rounded-lg text-white transition-all duration-150 disabled:opacity-40"
212+
style={{
213+
background: "linear-gradient(135deg, var(--color-lilac-dark, #6366f1), var(--color-mint-dark, #10b981))",
214+
}}
215+
>
216+
Apply Template
217+
</button>
218+
<button
219+
onClick={handleApplyCancel}
220+
className="text-xs px-3 py-1.5 rounded-lg"
221+
style={{
222+
border: "1px solid var(--color-border-tertiary, rgba(0,0,0,0.1))",
223+
color: "var(--text-secondary, #666)",
224+
}}
225+
>
226+
Cancel
227+
</button>
228+
</div>
229+
</div>
230+
)}
136231
</div>
137232
</>
138233
);

apps/app/src/components/template-library/template-card.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ interface TemplateCardProps {
99
html: string;
1010
dataDescription: string;
1111
version: number;
12-
onApply: (id: string, name: string) => void;
13-
onDelete: (id: string, name: string) => void;
12+
onApply: (id: string) => void;
13+
onDelete: (id: string) => void;
1414
}
1515

1616
export function TemplateCard({
@@ -106,7 +106,7 @@ body { font-family: system-ui, sans-serif; font-size: 16px; color: #1a1a1a; back
106106
className="flex gap-2 p-3 pt-0"
107107
>
108108
<button
109-
onClick={() => onApply(id, name)}
109+
onClick={() => onApply(id)}
110110
className="flex-1 text-xs font-medium py-1.5 rounded-lg transition-all duration-150 hover:scale-[1.02] text-white"
111111
style={{
112112
background: "linear-gradient(135deg, var(--color-lilac-dark, #6366f1), var(--color-mint-dark, #10b981))",
@@ -115,7 +115,7 @@ body { font-family: system-ui, sans-serif; font-size: 16px; color: #1a1a1a; back
115115
Apply
116116
</button>
117117
<button
118-
onClick={() => onDelete(id, name)}
118+
onClick={() => onDelete(id)}
119119
className="text-xs px-3 py-1.5 rounded-lg transition-colors duration-150"
120120
style={{
121121
border: "1px solid var(--color-border-tertiary, rgba(0,0,0,0.1))",

0 commit comments

Comments
 (0)