Skip to content

Commit c6ef493

Browse files
committed
wire up demo gallery drawer, rename SaveTemplateOverlay to ExportOverlay
- Add Demos button to header and DemoGallery drawer with category filter - Send demo prompt to CopilotChat via appendMessage on "Try it" click - Rename SaveTemplateOverlay → ExportOverlay, drop unused description prop - Remove dead iframe preview code from DemoCard, remove unused html field - Fix trailing blank line in agent system prompt - Update chat suggestion from BFS/DFS to 3D Plane Controls - Add clipboard write error handling in ExportOverlay
1 parent 37aa88e commit c6ef493

12 files changed

Lines changed: 323 additions & 67 deletions

File tree

apps/agent/main.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@
6565
**Quality bar**: Every visualization should look polished and portfolio-ready. Use smooth animations, proper lighting (ambient + directional at minimum), responsive canvas sizing (`window.addEventListener('resize', ...)`), and antialiasing (`antialias: true`). No proof-of-concept quality.
6666
6767
**Critical**: `<script type="module">` is REQUIRED when using import map libraries. Regular `<script>` tags cannot use `import` statements.
68-
6968
""",
7069
)
7170

apps/app/src/app/page.tsx

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
11
"use client";
22

3-
import { useEffect } from "react";
3+
import { useEffect, useState } from "react";
44
import { ExampleLayout } from "@/components/example-layout";
55
import { useGenerativeUIExamples, useExampleSuggestions } from "@/hooks";
66
import { ExplainerCardsPortal } from "@/components/explainer-cards";
7+
import { DemoGallery, type DemoItem } from "@/components/demo-gallery";
78

89
import { CopilotChat } from "@copilotkit/react-core/v2";
10+
import { useCopilotChat } from "@copilotkit/react-core";
911

1012
export default function HomePage() {
1113
useGenerativeUIExamples();
1214
useExampleSuggestions();
1315

16+
const [demoDrawerOpen, setDemoDrawerOpen] = useState(false);
17+
const { appendMessage } = useCopilotChat();
18+
19+
const handleTryDemo = (demo: DemoItem) => {
20+
setDemoDrawerOpen(false);
21+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
22+
appendMessage({ content: demo.prompt, role: "user" } as any);
23+
};
24+
1425
// Widget bridge: handle messages from widget iframes
1526
useEffect(() => {
1627
const handler = (e: MessageEvent) => {
@@ -56,6 +67,25 @@ export default function HomePage() {
5667
</p>
5768
</div>
5869
<div className="flex items-center gap-2">
70+
<button
71+
onClick={() => setDemoDrawerOpen(true)}
72+
className="inline-flex items-center gap-1.5 px-3 py-2 rounded-full text-sm font-medium no-underline whitespace-nowrap transition-all duration-150 hover:-translate-y-px cursor-pointer"
73+
style={{
74+
color: "var(--text-secondary)",
75+
border: "1px solid var(--color-border-glass, rgba(0,0,0,0.1))",
76+
background: "var(--surface-primary, rgba(255,255,255,0.6))",
77+
fontFamily: "var(--font-family)",
78+
}}
79+
title="Open Demo Gallery"
80+
>
81+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
82+
<rect width="7" height="7" x="3" y="3" rx="1" />
83+
<rect width="7" height="7" x="14" y="3" rx="1" />
84+
<rect width="7" height="7" x="14" y="14" rx="1" />
85+
<rect width="7" height="7" x="3" y="14" rx="1" />
86+
</svg>
87+
Demos
88+
</button>
5989
<a
6090
href="https://github.com/CopilotKit/OpenGenerativeUI"
6191
target="_blank"
@@ -84,6 +114,11 @@ export default function HomePage() {
84114
</div>
85115
</div>
86116

117+
<DemoGallery
118+
open={demoDrawerOpen}
119+
onClose={() => setDemoDrawerOpen(false)}
120+
onTryDemo={handleTryDemo}
121+
/>
87122
</>
88123
);
89124
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"use client";
2+
3+
import type { DemoCategory } from "./demo-data";
4+
import { DEMO_CATEGORIES } from "./demo-data";
5+
6+
interface CategoryFilterProps {
7+
selected: DemoCategory | null;
8+
onSelect: (category: DemoCategory | null) => void;
9+
}
10+
11+
export function CategoryFilter({ selected, onSelect }: CategoryFilterProps) {
12+
const categories: (DemoCategory | null)[] = [null, ...DEMO_CATEGORIES];
13+
14+
return (
15+
<div className="flex gap-2 overflow-x-auto pb-1 scrollbar-none">
16+
{categories.map((cat) => {
17+
const isActive = cat === selected;
18+
return (
19+
<button
20+
key={cat ?? "all"}
21+
onClick={() => onSelect(cat)}
22+
className="shrink-0 px-3 py-1.5 rounded-full text-xs font-medium transition-all duration-150 cursor-pointer"
23+
style={{
24+
background: isActive
25+
? "linear-gradient(135deg, var(--color-lilac-dark, #6366f1), var(--color-mint-dark, #10b981))"
26+
: "var(--surface-primary, rgba(255,255,255,0.6))",
27+
color: isActive ? "#fff" : "var(--text-secondary, #666)",
28+
border: isActive
29+
? "none"
30+
: "1px solid var(--color-border-glass, rgba(0,0,0,0.1))",
31+
}}
32+
>
33+
{cat ?? "All"}
34+
</button>
35+
);
36+
})}
37+
</div>
38+
);
39+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"use client";
2+
3+
import type { DemoItem } from "./demo-data";
4+
5+
// Category badge colors
6+
const CATEGORY_COLORS: Record<string, { bg: string; text: string }> = {
7+
"3D / Animation": { bg: "rgba(139,92,246,0.12)", text: "rgba(139,92,246,1)" },
8+
"Data Visualization": { bg: "rgba(59,130,246,0.12)", text: "rgba(59,130,246,1)" },
9+
Diagrams: { bg: "rgba(16,185,129,0.12)", text: "rgba(16,185,129,1)" },
10+
Interactive: { bg: "rgba(245,158,11,0.12)", text: "rgba(245,158,11,1)" },
11+
"UI Components": { bg: "rgba(236,72,153,0.12)", text: "rgba(236,72,153,1)" },
12+
};
13+
14+
// Emoji background gradients
15+
const EMOJI_GRADIENTS: Record<string, string> = {
16+
"3D / Animation":
17+
"linear-gradient(135deg, rgba(139,92,246,0.08) 0%, rgba(59,130,246,0.06) 100%)",
18+
"Data Visualization":
19+
"linear-gradient(135deg, rgba(59,130,246,0.08) 0%, rgba(16,185,129,0.06) 100%)",
20+
Diagrams:
21+
"linear-gradient(135deg, rgba(16,185,129,0.08) 0%, rgba(59,130,246,0.06) 100%)",
22+
Interactive:
23+
"linear-gradient(135deg, rgba(245,158,11,0.08) 0%, rgba(236,72,153,0.06) 100%)",
24+
"UI Components":
25+
"linear-gradient(135deg, rgba(236,72,153,0.08) 0%, rgba(139,92,246,0.06) 100%)",
26+
};
27+
28+
interface DemoCardProps {
29+
demo: DemoItem;
30+
onTry: (demo: DemoItem) => void;
31+
}
32+
33+
export function DemoCard({ demo, onTry }: DemoCardProps) {
34+
const categoryColor = CATEGORY_COLORS[demo.category] ?? {
35+
bg: "rgba(100,100,100,0.12)",
36+
text: "rgba(100,100,100,1)",
37+
};
38+
39+
return (
40+
<div
41+
className="rounded-xl overflow-hidden flex flex-col transition-all duration-200 hover:shadow-lg hover:-translate-y-0.5"
42+
style={{
43+
border: "1px solid var(--color-border-glass, rgba(0,0,0,0.1))",
44+
background: "var(--surface-primary, #fff)",
45+
}}
46+
>
47+
{/* Preview area */}
48+
<div
49+
className="relative overflow-hidden"
50+
style={{
51+
height: 160,
52+
background:
53+
EMOJI_GRADIENTS[demo.category] ??
54+
"var(--color-background-secondary)",
55+
}}
56+
>
57+
<div className="flex items-center justify-center h-full">
58+
<span className="text-5xl" role="img" aria-label={demo.title}>
59+
{demo.emoji}
60+
</span>
61+
</div>
62+
63+
{/* Category badge */}
64+
<span
65+
className="absolute top-2 right-2 text-[10px] font-semibold px-2 py-0.5 rounded-full"
66+
style={{
67+
background: categoryColor.bg,
68+
color: categoryColor.text,
69+
}}
70+
>
71+
{demo.category}
72+
</span>
73+
</div>
74+
75+
{/* Info */}
76+
<div className="flex flex-col gap-1 p-3 flex-1">
77+
<div className="flex items-center gap-2">
78+
<span className="text-base">{demo.emoji}</span>
79+
<h3
80+
className="text-sm font-semibold truncate"
81+
style={{ color: "var(--text-primary, #1a1a1a)" }}
82+
>
83+
{demo.title}
84+
</h3>
85+
</div>
86+
<p
87+
className="text-xs line-clamp-2"
88+
style={{ color: "var(--text-secondary, #666)" }}
89+
>
90+
{demo.description}
91+
</p>
92+
</div>
93+
94+
{/* Action */}
95+
<div className="p-3 pt-0">
96+
<button
97+
onClick={() => onTry(demo)}
98+
className="w-full text-xs font-medium py-2 rounded-lg transition-all duration-150 hover:scale-[1.02] text-white cursor-pointer"
99+
style={{
100+
background:
101+
"linear-gradient(135deg, var(--color-lilac-dark, #6366f1), var(--color-mint-dark, #10b981))",
102+
}}
103+
>
104+
Try it
105+
</button>
106+
</div>
107+
</div>
108+
);
109+
}

apps/app/src/components/demo-gallery/demo-data.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ export interface DemoItem {
1212
category: DemoCategory;
1313
emoji: string;
1414
prompt: string;
15-
html?: string;
1615
}
1716

1817
export const DEMO_EXAMPLES: DemoItem[] = [

0 commit comments

Comments
 (0)