1
- import { Copy , Play , Check , AlertTriangle } from "lucide-react" ;
1
+ import { Copy , Play , Check , AlertTriangle , Loader2 } from "lucide-react" ;
2
2
import { useState , useCallback } from "react" ;
3
3
import { usePlaygroundContext } from "./PlaygroundContext" ;
4
4
import { useSynthLang } from "./useSynthLang" ;
5
+ import { PlaygroundOutput } from "./PlaygroundContext" ;
6
+ import { useSettingsContext } from "../../services/settingsService" ;
7
+ import { callOpenRouter } from "../../services/openRouterService" ;
5
8
6
9
interface CodeExampleProps {
7
10
code : string ;
@@ -18,8 +21,11 @@ export const CodeExample = ({
18
21
} : CodeExampleProps ) => {
19
22
const [ copied , setCopied ] = useState ( false ) ;
20
23
const [ error , setError ] = useState < string | null > ( null ) ;
24
+ const [ isRunning , setIsRunning ] = useState ( false ) ;
25
+ const [ exampleOutput , setExampleOutput ] = useState < string | null > ( null ) ;
21
26
const { loadExample, isLoading } = usePlaygroundContext ( ) ;
22
27
const { highlightSyntax, validateSynthLang } = useSynthLang ( ) ;
28
+ const { settings } = useSettingsContext ( ) ;
23
29
24
30
const handleCopy = useCallback ( async ( ) => {
25
31
try {
@@ -35,6 +41,8 @@ export const CodeExample = ({
35
41
const handleTryIt = useCallback ( async ( ) => {
36
42
try {
37
43
setError ( null ) ;
44
+ setIsRunning ( true ) ;
45
+ setExampleOutput ( "" ) ;
38
46
39
47
// Only validate if it's SynthLang code
40
48
if ( language === "synthlang" ) {
@@ -51,12 +59,38 @@ export const CodeExample = ({
51
59
}
52
60
}
53
61
62
+ // Call OpenRouter if API key is available
63
+ if ( settings . openRouterApiKey ) {
64
+ await callOpenRouter (
65
+ code ,
66
+ {
67
+ model : settings . defaultModel ,
68
+ temperature : 0.7 ,
69
+ maxTokens : 1000 ,
70
+ autoFormat : true ,
71
+ syntaxHighlighting : true ,
72
+ showLineNumbers : true
73
+ } ,
74
+ settings . openRouterApiKey ,
75
+ 'interpreter' ,
76
+ undefined ,
77
+ ( chunk ) => {
78
+ setExampleOutput ( prev => ( prev || "" ) + chunk ) ;
79
+ }
80
+ ) ;
81
+ } else {
82
+ throw new Error ( "OpenRouter API key not found. Please add your API key in Settings." ) ;
83
+ }
84
+
85
+ // Also load into playground for reference
54
86
await loadExample ( code ) ;
55
87
} catch ( err ) {
56
88
setError ( err instanceof Error ? err . message : "Failed to load example" ) ;
57
89
setTimeout ( ( ) => setError ( null ) , 5000 ) ;
90
+ } finally {
91
+ setIsRunning ( false ) ;
58
92
}
59
- } , [ code , language , loadExample , validateSynthLang ] ) ;
93
+ } , [ code , language , loadExample , validateSynthLang , settings ] ) ;
60
94
61
95
return (
62
96
< div className = "space-y-2" >
@@ -74,48 +108,57 @@ export const CodeExample = ({
74
108
{ description && (
75
109
< p className = "text-sm text-muted-foreground" > { description } </ p >
76
110
) }
77
- < div className = "relative group" >
111
+ < div className = "relative group pt-8 " >
78
112
< div className = "absolute top-2 right-2 flex items-center gap-2 opacity-0
79
113
group-hover:opacity-100 transition-opacity" >
80
114
< button
81
115
onClick = { handleTryIt }
82
- className = " p-1.5 bg-black/20 hover:bg-black/30 rounded-md
83
- transition-colors flex items-center gap-1.5"
116
+ className = { ` p-1.5 rounded-md transition-colors flex items-center gap-1.5
117
+ ${ isRunning || isLoading ? 'bg-purple-500/30 cursor-not-allowed' : 'bg-black/20 hover:bg-black/30' } ` }
84
118
title = "Try in playground"
85
- disabled = { isLoading }
119
+ disabled = { isRunning || isLoading }
86
120
>
87
- < Play className = { `w-3.5 h-3.5 ${ isLoading ? 'text-muted-foreground' : 'text-purple-400' } ` } />
121
+ { isRunning ? (
122
+ < Loader2 className = "w-3.5 h-3.5 text-purple-400 animate-spin" />
123
+ ) : (
124
+ < Play className = { `w-3.5 h-3.5 ${ isLoading ? 'text-muted-foreground' : 'text-purple-400' } ` } />
125
+ ) }
88
126
< span className = { `text-xs ${ isLoading ? 'text-muted-foreground' : 'text-purple-400' } ` } >
89
- { isLoading ? 'Loading...' : 'Try it' }
127
+ { isRunning ? 'Running...' : isLoading ? 'Loading...' : 'Try it' }
90
128
</ span >
91
129
</ button >
92
130
< button
93
131
onClick = { handleCopy }
94
132
className = "p-1.5 bg-black/20 hover:bg-black/30 rounded-md transition-colors"
95
133
title = "Copy code"
96
- disabled = { isLoading }
134
+ disabled = { isRunning || isLoading }
97
135
>
98
136
{ copied ? (
99
137
< Check className = "w-3.5 h-3.5 text-green-400" />
100
138
) : (
101
- < Copy className = { `w-3.5 h-3.5 ${ isLoading ? 'text-muted-foreground' : 'text-muted-foreground hover:text-purple-400' } ` } />
139
+ < Copy className = { `w-3.5 h-3.5 ${ isRunning || isLoading ? 'text-muted-foreground' : 'text-muted-foreground hover:text-purple-400' } ` } />
102
140
) }
103
141
</ button >
104
142
</ div >
105
- < div className = "rounded-lg border border-border/40 bg-black/20 overflow-hidden " >
143
+ < div className = "rounded-lg border border-border/40 bg-black/20" >
106
144
{ language === "synthlang" ? (
107
145
< pre
108
- className = "p-4 font-mono text-sm overflow-x-auto "
146
+ className = "p-4 font-mono text-sm whitespace-pre-wrap break-words "
109
147
dangerouslySetInnerHTML = { {
110
148
__html : highlightSyntax ( code )
111
149
} }
112
150
/>
113
151
) : (
114
- < pre className = "p-4 font-mono text-sm overflow-x-auto " >
152
+ < pre className = "p-4 font-mono text-sm whitespace-pre-wrap break-words " >
115
153
< code > { code } </ code >
116
154
</ pre >
117
155
) }
118
156
</ div >
157
+ { exampleOutput && (
158
+ < div className = "mt-4" >
159
+ < PlaygroundOutput > { exampleOutput } </ PlaygroundOutput >
160
+ </ div >
161
+ ) }
119
162
</ div >
120
163
</ div >
121
164
) ;
0 commit comments