@@ -34,10 +34,12 @@ import {
3434 DocumentTextIcon ,
3535 BeakerIcon
3636} from '@heroicons/react/24/outline' ;
37+ import { useToast } from '@chakra-ui/react' ;
3738
3839const StreamingCodeGenerator = ( ) => {
3940 const { user } = useAuth ( ) ;
4041 const { currentTheme } = useTheme ( ) ;
42+ const toast = useToast ( ) ;
4143 const wsRef = useRef ( null ) ;
4244 const [ isConnected , setIsConnected ] = useState ( false ) ;
4345
@@ -144,6 +146,13 @@ const StreamingCodeGenerator = () => {
144146 switch ( message . type ) {
145147 case 'connection_established' :
146148 console . log ( '✅ Code generation WebSocket ready' ) ;
149+ toast ( {
150+ title : "Connected" ,
151+ description : "Ready to generate code" ,
152+ status : "success" ,
153+ duration : 3000 ,
154+ isClosable : true ,
155+ } ) ;
147156 break ;
148157
149158 case 'code_generation_started' :
@@ -152,6 +161,13 @@ const StreamingCodeGenerator = () => {
152161 setCurrentStep ( 'Starting code generation...' ) ;
153162 setError ( '' ) ;
154163 clearResults ( ) ;
164+ toast ( {
165+ title : "Generation Started" ,
166+ description : "Your code is being generated" ,
167+ status : "info" ,
168+ duration : 3000 ,
169+ isClosable : true ,
170+ } ) ;
155171 break ;
156172
157173 case 'code_generation_progress' :
@@ -236,14 +252,25 @@ const StreamingCodeGenerator = () => {
236252 minH = "100vh"
237253 bg = { currentTheme . colors . background }
238254 color = { currentTheme . colors . text }
239- p = { 6 }
255+ p = { { base : 4 , md : 6 } }
240256 >
241- < VStack spacing = { 6 } maxW = "6xl" mx = "auto" >
257+ < VStack spacing = { { base : 4 , md : 6 } } maxW = "6xl" mx = "auto" px = { { base : 2 , sm : 4 } } >
242258 { /* Header */ }
243- < Flex align = "center" gap = { 3 } >
244- < SparklesIcon className = "w-8 h-8" />
245- < Heading size = "lg" > Streaming Code Generator</ Heading >
246- < Badge colorScheme = { isConnected ? 'green' : 'red' } >
259+ < Flex
260+ align = "center"
261+ gap = { 3 }
262+ role = "banner"
263+ direction = { { base : "column" , sm : "row" } }
264+ textAlign = { { base : "center" , sm : "left" } }
265+ >
266+ < SparklesIcon className = "w-8 h-8" aria-hidden = "true" />
267+ < Heading size = { { base : "md" , lg : "lg" } } as = "h1" >
268+ Streaming Code Generator
269+ </ Heading >
270+ < Badge
271+ colorScheme = { isConnected ? 'green' : 'red' }
272+ aria-label = { `Connection status: ${ isConnected ? 'Connected' : 'Disconnected' } ` }
273+ >
247274 { isConnected ? 'Connected' : 'Disconnected' }
248275 </ Badge >
249276 </ Flex >
@@ -257,9 +284,9 @@ const StreamingCodeGenerator = () => {
257284 ) }
258285
259286 { /* Input Form */ }
260- < Card w = "full" >
287+ < Card w = "full" as = "section" role = "form" aria-labelledby = "form-heading" >
261288 < CardHeader >
262- < Heading size = "md" > Code Generation Request</ Heading >
289+ < Heading size = "md" as = "h2" id = "form-heading" > Code Generation Request</ Heading >
263290 </ CardHeader >
264291 < CardBody >
265292 < VStack spacing = { 4 } >
@@ -270,12 +297,30 @@ const StreamingCodeGenerator = () => {
270297 size = "lg"
271298 minH = "120px"
272299 resize = "vertical"
300+ aria-label = "Code description"
301+ aria-describedby = "description-help"
302+ required
273303 />
274-
275- < HStack w = "full" spacing = { 4 } >
276- < Box flex = { 1 } >
277- < Text mb = { 2 } fontWeight = "semibold" > Language</ Text >
278- < Select value = { language } onChange = { ( e ) => setLanguage ( e . target . value ) } >
304+ < Text id = "description-help" fontSize = "sm" color = "gray.600" sr-only >
305+ Provide a detailed description of the code you want to generate
306+ </ Text >
307+
308+ < VStack
309+ spacing = { 4 }
310+ w = "full"
311+ direction = { { base : "column" , md : "row" } }
312+ as = { HStack }
313+ >
314+ < Box flex = { 1 } w = "full" >
315+ < Text mb = { 2 } fontWeight = "semibold" as = "label" htmlFor = "language-select" >
316+ Language
317+ </ Text >
318+ < Select
319+ id = "language-select"
320+ value = { language }
321+ onChange = { ( e ) => setLanguage ( e . target . value ) }
322+ aria-label = "Select programming language"
323+ >
279324 { languages . map ( lang => (
280325 < option key = { lang . value } value = { lang . value } >
281326 { lang . label }
@@ -284,55 +329,92 @@ const StreamingCodeGenerator = () => {
284329 </ Select >
285330 </ Box >
286331
287- < Box flex = { 1 } >
288- < Text mb = { 2 } fontWeight = "semibold" > Code Type</ Text >
289- < Select value = { codeType } onChange = { ( e ) => setCodeType ( e . target . value ) } >
332+ < Box flex = { 1 } w = "full" >
333+ < Text mb = { 2 } fontWeight = "semibold" as = "label" htmlFor = "code-type-select" >
334+ Code Type
335+ </ Text >
336+ < Select
337+ id = "code-type-select"
338+ value = { codeType }
339+ onChange = { ( e ) => setCodeType ( e . target . value ) }
340+ aria-label = "Select code type"
341+ >
290342 { codeTypes . map ( type => (
291343 < option key = { type . value } value = { type . value } >
292344 { type . label }
293345 </ option >
294346 ) ) }
295347 </ Select >
296348 </ Box >
297- </ HStack >
349+ </ VStack >
298350
299351 < HStack >
300352 < Button
301- leftIcon = { < PlayIcon className = "w-4 h-4" /> }
353+ leftIcon = { < PlayIcon className = "w-4 h-4" aria-hidden = "true" /> }
302354 colorScheme = "blue"
303355 onClick = { handleGenerateCode }
304356 disabled = { ! isConnected || isGenerating || ! description . trim ( ) }
305357 isLoading = { isGenerating }
306358 loadingText = "Generating..."
359+ aria-label = "Generate code based on description"
360+ aria-describedby = { ! isConnected ? "connection-error" : undefined }
307361 >
308362 Generate Code
309363 </ Button >
310364
311365 { isGenerating && (
312366 < Button
313- leftIcon = { < StopIcon className = "w-4 h-4" /> }
367+ leftIcon = { < StopIcon className = "w-4 h-4" aria-hidden = "true" /> }
314368 colorScheme = "red"
315369 variant = "outline"
316370 onClick = { handleStopGeneration }
371+ aria-label = "Stop code generation"
317372 >
318373 Stop
319374 </ Button >
320375 ) }
321376 </ HStack >
377+
378+ { ! isConnected && (
379+ < Text id = "connection-error" fontSize = "sm" color = "red.500" sr-only >
380+ Connection required to generate code
381+ </ Text >
382+ ) }
322383 </ VStack >
323384 </ CardBody >
324385 </ Card >
325386
326387 { /* Progress */ }
327388 { isGenerating && (
328- < Card w = "full" >
389+ < Card w = "full" role = "status" aria-live = "polite" aria-label = "Code generation progress" >
329390 < CardBody >
330391 < VStack spacing = { 3 } >
331- < Text fontWeight = "semibold" > { currentStep } </ Text >
332- < Progress value = { progress } w = "full" colorScheme = "blue" hasStripe isAnimated />
333- < Text fontSize = "sm" color = { currentTheme . colors . textSecondary } >
334- { progress } % complete
335- </ Text >
392+ < HStack w = "full" justify = "space-between" align = "center" >
393+ < Text fontWeight = "semibold" aria-describedby = "progress-bar" >
394+ { currentStep }
395+ </ Text >
396+ < Text fontSize = "sm" fontWeight = "medium" color = "blue.500" >
397+ { progress } %
398+ </ Text >
399+ </ HStack >
400+ < Progress
401+ id = "progress-bar"
402+ value = { progress }
403+ w = "full"
404+ colorScheme = "blue"
405+ hasStripe
406+ isAnimated
407+ size = "lg"
408+ aria-label = { `Code generation ${ progress } % complete` }
409+ />
410+ < HStack w = "full" justify = "space-between" align = "center" >
411+ < Text fontSize = "sm" color = { currentTheme . colors . textSecondary } >
412+ Generating your code...
413+ </ Text >
414+ < Text fontSize = "xs" color = { currentTheme . colors . textSecondary } >
415+ { Math . ceil ( ( 100 - progress ) / 20 ) } steps remaining
416+ </ Text >
417+ </ HStack >
336418 </ VStack >
337419 </ CardBody >
338420 </ Card >
0 commit comments