@@ -496,10 +496,7 @@ function PythonCodePanel({ isOpen, onClose, algorithm }) {
496496 ) : (
497497 < >
498498 { /* Code Editor + Output (resizable on desktop) */ }
499- < div
500- className = "flex-1 min-h-0 flex flex-col p-2"
501- dir = "ltr"
502- >
499+ < div className = "flex-1 min-h-0 flex flex-col p-2" dir = "ltr" >
503500 < div
504501 ref = { resizeContainerRef }
505502 className = "min-h-0 flex flex-col overflow-hidden flex-1"
@@ -514,119 +511,120 @@ function PythonCodePanel({ isOpen, onClose, algorithm }) {
514511 minHeight : isMobile ? 100 : 80 ,
515512 } }
516513 >
517- < Editor
518- height = "100%"
519- defaultLanguage = "python"
520- value = { code }
521- onChange = { value => setCode ( value ?? '' ) }
522- theme = { isDark ? 'vs-dark' : 'vs-light' }
523- onMount = { ( editor , monaco ) => {
524- editorRef . current = editor ;
525- monacoRef . current = monaco ;
526- editor . addAction ( {
527- id : 'run-python' ,
528- label : 'Run Python' ,
529- keybindings : [
530- monaco . KeyMod . CtrlCmd | monaco . KeyCode . Enter ,
531- ] ,
532- run : ( ) => runHandlerRef . current ?. ( ) ,
533- } ) ;
534- if ( isMobile ) {
535- const container = editor . getContainerDomNode ?. ( ) ;
536- if ( container ) {
537- container . style . touchAction = 'pan-y' ;
538- const scrollable =
539- container . querySelector (
540- '.monaco-scrollable-element'
541- ) ??
542- container . querySelector (
543- '[class*="scrollable"]'
544- ) ;
545- if ( scrollable ) {
546- scrollable . style . webkitOverflowScrolling =
547- 'touch' ;
514+ < Editor
515+ height = "100%"
516+ defaultLanguage = "python"
517+ value = { code }
518+ onChange = { value => setCode ( value ?? '' ) }
519+ theme = { isDark ? 'vs-dark' : 'vs-light' }
520+ onMount = { ( editor , monaco ) => {
521+ editorRef . current = editor ;
522+ monacoRef . current = monaco ;
523+ editor . addAction ( {
524+ id : 'run-python' ,
525+ label : 'Run Python' ,
526+ keybindings : [
527+ monaco . KeyMod . CtrlCmd | monaco . KeyCode . Enter ,
528+ ] ,
529+ run : ( ) => runHandlerRef . current ?. ( ) ,
530+ } ) ;
531+ if ( isMobile ) {
532+ const container = editor . getContainerDomNode ?. ( ) ;
533+ if ( container ) {
534+ container . style . touchAction = 'pan-y' ;
535+ const scrollable =
536+ container . querySelector (
537+ '.monaco-scrollable-element'
538+ ) ??
539+ container . querySelector (
540+ '[class*="scrollable"]'
541+ ) ;
542+ if ( scrollable ) {
543+ scrollable . style . webkitOverflowScrolling =
544+ 'touch' ;
545+ }
548546 }
549547 }
550- }
551- } }
552- options = { {
553- readOnly : false ,
554- minimap : { enabled : ! isMobile } ,
555- scrollBeyondLastLine : false ,
556- fontSize : isMobile ? 12 : 14 ,
557- lineNumbers : 'on' ,
558- folding : true ,
559- wordWrap : 'on' ,
560- automaticLayout : true ,
561- padding : { top : 16 , bottom : 16 } ,
562- scrollbar : {
563- vertical : 'auto' ,
564- horizontal : 'auto' ,
565- } ,
566- } }
567- loading = {
568- < div className = "flex items-center justify-center h-full bg-surface" >
569- < div className = "text-text-secondary" >
570- { t ( 'python_code.loading' ) || 'Loading editor...' }
548+ } }
549+ options = { {
550+ readOnly : false ,
551+ minimap : { enabled : ! isMobile } ,
552+ scrollBeyondLastLine : false ,
553+ fontSize : isMobile ? 12 : 14 ,
554+ lineNumbers : 'on' ,
555+ folding : true ,
556+ wordWrap : 'on' ,
557+ automaticLayout : true ,
558+ padding : { top : 16 , bottom : 16 } ,
559+ scrollbar : {
560+ vertical : 'auto' ,
561+ horizontal : 'auto' ,
562+ } ,
563+ } }
564+ loading = {
565+ < div className = "flex items-center justify-center h-full bg-surface" >
566+ < div className = "text-text-secondary" >
567+ { t ( 'python_code.loading' ) ||
568+ 'Loading editor...' }
569+ </ div >
571570 </ div >
572- </ div >
573- }
574- />
575- </ div >
576- { ! isMobile && isOutputExpanded && (
577- < div
578- role = "separator"
579- aria-orientation = "horizontal"
580- aria-valuenow = { outputHeightPercent }
581- aria-valuemin = { MIN_OUTPUT_PERCENT }
582- aria-valuemax = { MAX_OUTPUT_PERCENT }
583- aria-label = { t ( 'python_code.resize_output' , {
584- defaultValue : 'Resize output panel' ,
585- } ) }
586- onMouseDown = { handleResizeStart }
587- className = { `shrink-0 h-1 flex items-center justify-center cursor-row-resize hover:bg-blue-500/30 active:bg-blue-500/50 transition-colors group ${
588- isResizing
589- ? 'bg-blue-500/50'
590- : 'bg-gray-200 dark:bg-gray-700'
591- } `}
592- >
593- < div className = "w-12 h-0.5 rounded-full bg-gray-400 group-hover:bg-blue-500 opacity-0 group-hover:opacity-100 group-focus-within:opacity-100" />
594- </ div >
595- ) }
596- { isOutputExpanded && (
597- < div
598- className = "min-h-0 overflow-hidden flex flex-col shrink-0"
599- style = { {
600- flex : isMobile
601- ? '0 0 auto'
602- : `0 0 calc(${ outputHeightPercent } % - 2px)` ,
603- minHeight : ! isMobile ? 80 : undefined ,
604- } }
605- >
606- < OutputConsole
607- status = { status }
608- output = { output }
609- error = { error }
610- onClear = { clearOutput }
611- isExpanded = { isOutputExpanded }
612- onToggleExpand = { ( ) =>
613- setIsOutputExpanded ( prev => ! prev )
614571 }
615- onRun = { handleRun }
616- onReset = { ( ) => setCode ( pythonCode ) }
617- isModified = { isModified }
618- testCases = { testCases }
619- testResults = { testResults }
620- testStatus = { testStatus }
621- testError = { testError }
622- onRunTests = { handleRunTests }
623- onAddTestCase = { handleAddTestCase }
624- onEditTestCase = { handleEditTestCase }
625- onDeleteTestCase = { handleDeleteTestCase }
626- onClearTestResults = { clearTestResults }
627572 />
628573 </ div >
629- ) }
574+ { ! isMobile && isOutputExpanded && (
575+ < div
576+ role = "separator"
577+ aria-orientation = "horizontal"
578+ aria-valuenow = { outputHeightPercent }
579+ aria-valuemin = { MIN_OUTPUT_PERCENT }
580+ aria-valuemax = { MAX_OUTPUT_PERCENT }
581+ aria-label = { t ( 'python_code.resize_output' , {
582+ defaultValue : 'Resize output panel' ,
583+ } ) }
584+ onMouseDown = { handleResizeStart }
585+ className = { `shrink-0 h-1 flex items-center justify-center cursor-row-resize hover:bg-blue-500/30 active:bg-blue-500/50 transition-colors group ${
586+ isResizing
587+ ? 'bg-blue-500/50'
588+ : 'bg-gray-200 dark:bg-gray-700'
589+ } `}
590+ >
591+ < div className = "w-12 h-0.5 rounded-full bg-gray-400 group-hover:bg-blue-500 opacity-0 group-hover:opacity-100 group-focus-within:opacity-100" />
592+ </ div >
593+ ) }
594+ { isOutputExpanded && (
595+ < div
596+ className = "min-h-0 overflow-hidden flex flex-col shrink-0"
597+ style = { {
598+ flex : isMobile
599+ ? '0 0 auto'
600+ : `0 0 calc(${ outputHeightPercent } % - 2px)` ,
601+ minHeight : ! isMobile ? 80 : undefined ,
602+ } }
603+ >
604+ < OutputConsole
605+ status = { status }
606+ output = { output }
607+ error = { error }
608+ onClear = { clearOutput }
609+ isExpanded = { isOutputExpanded }
610+ onToggleExpand = { ( ) =>
611+ setIsOutputExpanded ( prev => ! prev )
612+ }
613+ onRun = { handleRun }
614+ onReset = { ( ) => setCode ( pythonCode ) }
615+ isModified = { isModified }
616+ testCases = { testCases }
617+ testResults = { testResults }
618+ testStatus = { testStatus }
619+ testError = { testError }
620+ onRunTests = { handleRunTests }
621+ onAddTestCase = { handleAddTestCase }
622+ onEditTestCase = { handleEditTestCase }
623+ onDeleteTestCase = { handleDeleteTestCase }
624+ onClearTestResults = { clearTestResults }
625+ />
626+ </ div >
627+ ) }
630628 </ div >
631629 { ! isOutputExpanded && (
632630 < div className = "shrink-0 z-10" >
0 commit comments