Run it in TeamUp: live React preview of a task's artifact
Adds LivePreview — a sandboxed iframe that transpiles an agent's component with Babel and renders it live with React + Tailwind from CDN (no build step), so a generated page runs inside TeamUp. A "Preview" button on any task with an artifact opens a full-screen live view. Pairs with steering the engineer agent to output a single self-contained App component. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,9 +8,10 @@ import {
|
||||
useSensors,
|
||||
type DragEndEvent,
|
||||
} from '@dnd-kit/core'
|
||||
import { Bot, Plus, Trash2 } from 'lucide-react'
|
||||
import { Bot, Play, Plus, Trash2 } from 'lucide-react'
|
||||
import { toast } from 'sonner'
|
||||
import { AppShell, REVIEWS_CHANGED } from '@/components/AppShell'
|
||||
import { LivePreview } from '@/components/LivePreview'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
@@ -405,6 +406,7 @@ function TaskDrawer({
|
||||
}) {
|
||||
const [busy, setBusy] = useState(false)
|
||||
const [seatId, setSeatId] = useState<string>('')
|
||||
const [preview, setPreview] = useState(false)
|
||||
const aiSeats = seats.filter((s) => s.state === 'Ai')
|
||||
|
||||
if (!task) {
|
||||
@@ -564,10 +566,16 @@ function TaskDrawer({
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-2 border-t pt-4">
|
||||
<div className="mt-2 flex items-center gap-2 border-t pt-4">
|
||||
{task.description && (
|
||||
<Button variant="outline" size="sm" onClick={() => setPreview(true)}>
|
||||
<Play data-icon="inline-start" /> Preview
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
className="ml-auto"
|
||||
disabled={busy}
|
||||
onClick={() => {
|
||||
if (window.confirm(`Delete "${task.title}"? This can't be undone.`)) {
|
||||
@@ -579,6 +587,19 @@ function TaskDrawer({
|
||||
</Button>
|
||||
</div>
|
||||
</SheetContent>
|
||||
|
||||
{preview && task.description && (
|
||||
<div className="fixed inset-0 z-[100] flex flex-col gap-2 bg-background/95 p-4 backdrop-blur-sm">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm font-medium">Live preview · {task.title}</span>
|
||||
<Button size="sm" variant="outline" onClick={() => setPreview(false)}>Close</Button>
|
||||
</div>
|
||||
<LivePreview artifact={task.description} className="w-full flex-1 rounded-lg border bg-white" />
|
||||
<p className="text-center text-xs text-muted-foreground">
|
||||
Runs the artifact as a React component (Babel + Tailwind, no build). Define a component named App.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</Sheet>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user