Skip to content

Commit ed2e519

Browse files
committed
updating forge to use the sandbox
1 parent 9950399 commit ed2e519

16 files changed

+1014
-845
lines changed
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import { useMemo } from 'react'
2+
import { useDryRun } from '../store/project'
3+
import { useDeploymentStore } from '../store/deployment'
4+
import { WebContainerPreview } from '../sandbox/webcontainer-preview'
5+
6+
/**
7+
* BuilderPreview - Wrapper component that displays the preview
8+
* Assumes WebContainerProvider is already wrapping this component
9+
*/
10+
export function BuilderPreview() {
11+
const dryRun = useDryRun()
12+
const deploymentStore = useDeploymentStore()
13+
14+
const isDeploying =
15+
deploymentStore.status === 'building' ||
16+
deploymentStore.status === 'deploying'
17+
18+
// Show deployment overlay
19+
if (isDeploying || deploymentStore.status === 'success') {
20+
return (
21+
<div className="relative h-full min-h-0 bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900">
22+
<div className="absolute inset-0 flex flex-col items-center justify-center bg-gradient-to-br from-gray-900/95 via-gray-800/95 to-gray-900/95 backdrop-blur-sm z-10">
23+
<div className="w-full max-w-3xl p-8 flex flex-col items-center">
24+
{/* Deployment Status - Only show during deployment, not on success */}
25+
{isDeploying && deploymentStore.status !== 'success' && (
26+
<>
27+
<div className="text-lg font-semibold mb-4 text-white">
28+
{deploymentStore.message}
29+
</div>
30+
{deploymentStore.status !== 'error' && (
31+
<div className="inline-block animate-spin rounded-full h-10 w-10 border-4 border-purple-500 border-t-transparent mb-6"></div>
32+
)}
33+
34+
{/* Deployment Terminal Output */}
35+
{deploymentStore.terminalOutput.length > 0 &&
36+
deploymentStore.status !== 'error' && (
37+
<div className="w-full bg-black/50 rounded-lg p-4 max-h-64 overflow-hidden">
38+
<div className="font-mono text-xs text-green-400 overflow-y-auto max-h-56 space-y-1">
39+
{deploymentStore.terminalOutput.map((line, i) => (
40+
<div
41+
key={i}
42+
className="whitespace-pre-wrap break-all opacity-90"
43+
>
44+
{line}
45+
</div>
46+
))}
47+
</div>
48+
</div>
49+
)}
50+
51+
{deploymentStore.status === 'error' && (
52+
<div className="text-red-400 font-semibold">
53+
Error: {deploymentStore.errorMessage}
54+
</div>
55+
)}
56+
</>
57+
)}
58+
59+
{/* Success State */}
60+
{deploymentStore.status === 'success' &&
61+
deploymentStore.deployedUrl && (
62+
<div className="w-full max-w-2xl">
63+
<div className="bg-gradient-to-r from-green-500/20 to-emerald-500/20 rounded-lg border border-green-500/50 p-6">
64+
<div className="flex items-center justify-between mb-4">
65+
<h3 className="text-2xl font-bold text-green-400">
66+
🎉 Publish Complete!
67+
</h3>
68+
<button
69+
onClick={() => deploymentStore.reset()}
70+
className="text-white hover:text-white transition-colors"
71+
aria-label="Close"
72+
>
73+
<svg
74+
className="w-6 h-6"
75+
fill="none"
76+
stroke="currentColor"
77+
viewBox="0 0 24 24"
78+
>
79+
<path
80+
strokeLinecap="round"
81+
strokeLinejoin="round"
82+
strokeWidth={2}
83+
d="M6 18L18 6M6 6l12 12"
84+
/>
85+
</svg>
86+
</button>
87+
</div>
88+
89+
<div className="space-y-4">
90+
<div>
91+
<div className="text-white mb-1">
92+
Your site is live at:
93+
</div>
94+
<div className="flex items-center gap-2">
95+
<div className="flex-1 flex items-center bg-black/30 rounded-lg overflow-hidden">
96+
<a
97+
href={deploymentStore.deployedUrl}
98+
target="_blank"
99+
rel="noopener noreferrer"
100+
className="text-white font-mono text-sm px-3 py-2 flex-1 hover:bg-black/10 transition-colors truncate"
101+
title={deploymentStore.deployedUrl}
102+
>
103+
{deploymentStore.deployedUrl}
104+
</a>
105+
<button
106+
onClick={() => {
107+
navigator.clipboard.writeText(
108+
deploymentStore.deployedUrl!
109+
)
110+
}}
111+
className="px-3 py-2 hover:bg-black/20 transition-colors group relative border-l border-gray-700/50"
112+
title="Copy URL"
113+
>
114+
<svg
115+
className="w-5 h-5 text-gray-400 group-hover:text-white"
116+
fill="none"
117+
stroke="currentColor"
118+
viewBox="0 0 24 24"
119+
>
120+
<path
121+
strokeLinecap="round"
122+
strokeLinejoin="round"
123+
strokeWidth={2}
124+
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
125+
/>
126+
</svg>
127+
</button>
128+
</div>
129+
<a
130+
href={deploymentStore.deployedUrl}
131+
target="_blank"
132+
rel="noopener noreferrer"
133+
className="bg-transparent text-white px-2 py-1 rounded-lg text-sm ring-1 ring-white-700 font-semibold transition-colors"
134+
>
135+
Visit Site →
136+
</a>
137+
</div>
138+
</div>
139+
140+
{/* Claim Deployment Button */}
141+
{deploymentStore.claimUrl && (
142+
<div>
143+
<div className="text-white mt-10 mb-2">
144+
🔔 <strong>Note:</strong> This is an unclaimed
145+
deployment. <br />
146+
</div>
147+
<div className="text-white mt-2 mb-3">
148+
Claim it to manage settings, custom domains, and
149+
more:
150+
</div>
151+
<a
152+
href={deploymentStore.claimUrl}
153+
target="_blank"
154+
rel="noopener noreferrer"
155+
className="inline-flex items-center gap-2 bg-gradient-to-r to-blue-500 from-cyan-600 hover:to-blue-600 hover:from-cyan-600 text-white text-shadow-md text-shadow-discord px-6 py-3 rounded-lg font-semibold transition-all duration-200 shadow-lg"
156+
style={{ textShadow: '0 1px 2px rgba(0,0,0,0.3)' }}
157+
>
158+
<svg
159+
className="w-5 h-5 drop-shadow-sm"
160+
fill="none"
161+
stroke="currentColor"
162+
viewBox="0 0 24 24"
163+
>
164+
<path
165+
strokeLinecap="round"
166+
strokeLinejoin="round"
167+
strokeWidth={2}
168+
d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
169+
/>
170+
</svg>
171+
Claim Deployment on Netlify
172+
</a>
173+
</div>
174+
)}
175+
</div>
176+
</div>
177+
</div>
178+
)}
179+
</div>
180+
</div>
181+
</div>
182+
)
183+
}
184+
185+
return <WebContainerPreview />
186+
}

src/cta/components/cta-ui.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,31 @@
1+
import { useMemo } from 'react'
12
import { BuilderSidebar } from './cta-sidebar'
23
import { BuilderHeader } from './header'
34
import { CTABackgroundAnimation } from './background-animation'
45
import FileNavigator from './file-navigator'
56
import StartupDialog from './startup-dialog'
67
import { CTAProvider } from './cta-provider'
7-
import { BuilderPreview } from './preview'
8-
import WebContainerProvider from './web-container-provider'
8+
import { BuilderPreview } from './builder-preview'
99
import { Tabs, TabsContent, TabsList, TabsTrigger } from './ui/tabs'
10+
import { useDryRun } from '../store/project'
11+
import WebContainerProvider from '../sandbox/web-container-provider'
1012

1113
export default function BuilderRoot() {
14+
const dryRun = useDryRun()
15+
16+
// Convert dryRun.files (Record<string, string>) to projectFiles array
17+
const projectFiles = useMemo(() => {
18+
if (!dryRun?.files) return []
19+
20+
return Object.entries(dryRun.files).map(([path, content]) => ({
21+
path: path.startsWith('./') ? path : `./${path}`,
22+
content: String(content),
23+
}))
24+
}, [dryRun.files])
25+
1226
return (
1327
<CTAProvider>
14-
<WebContainerProvider>
28+
<WebContainerProvider projectFiles={projectFiles} shouldShimALS={true}>
1529
<main className="w-screen min-w-[1280px]">
1630
<CTABackgroundAnimation />
1731
<div className="h-dvh p-2 sm:p-4 flex flex-col gap-2 sm:gap-4 @container">

0 commit comments

Comments
 (0)