@@ -666,8 +666,16 @@ function SensorStreamControls({
666666 onStartSensorStreaming,
667667 onStopSensorStreaming,
668668} : SensorStreamControlsProps ) {
669+ // Each sensor module is collapsed by default; the play button stays visible.
670+ const [ expandedSensors , setExpandedSensors ] = useState < Set < string > > ( new Set ( ) )
671+ const toggleSensor = ( sensorId : string ) => setExpandedSensors ( prev => {
672+ const next = new Set ( prev )
673+ next . has ( sensorId ) ? next . delete ( sensorId ) : next . add ( sensorId )
674+ return next
675+ } )
676+
669677 return (
670- < div className = "space-y-3 " >
678+ < div className = "space-y-1.5 " >
671679 { sensors . map ( ( sensor ) => {
672680 const sensorStreamConfigs = streamsBySensor [ sensor . sensor_id ] || [ ]
673681 if ( sensorStreamConfigs . length === 0 ) return null
@@ -680,6 +688,7 @@ function SensorStreamControls({
680688 const sensorConfig = sensorConfigs [ sensor . sensor_id ]
681689
682690 const canStartSensor = hasEnabledSensorStreams && streamingMode !== 'pipeline'
691+ const isExpanded = expandedSensors . has ( sensor . sensor_id )
683692
684693 const computeCommonOptions = ( ) => {
685694 const profiles = sensor . supported_stream_profiles
@@ -706,15 +715,25 @@ function SensorStreamControls({
706715 const { resolutions : availableResolutions , fps : availableFps } = computeCommonOptions ( )
707716
708717 return (
709- < div key = { sensor . sensor_id } className = "bg-gray-800/50 rounded-lg p-2" >
710- { /* Sensor header with per-sensor start button */ }
711- < div className = "flex items-center justify-between mb-2" >
712- < div className = "flex items-center gap-2" >
713- < span className = "text-sm font-medium text-gray-300" > { sensor . name } </ span >
718+ < div key = { sensor . sensor_id } className = "bg-gray-800/50 rounded-lg px-2 py-1" >
719+ { /* Sensor header: collapse toggle (name) on the left, start button always visible on the right */ }
720+ < div className = { `flex items-center justify-between ${ isExpanded ? 'mb-2' : '' } ` } >
721+ < button
722+ onClick = { ( ) => toggleSensor ( sensor . sensor_id ) }
723+ className = "flex items-center gap-2 flex-1 min-w-0 text-left"
724+ aria-expanded = { isExpanded }
725+ >
726+ < svg
727+ className = { `w-3 h-3 shrink-0 text-gray-400 transition-transform ${ isExpanded ? 'rotate-90' : '' } ` }
728+ fill = "none" stroke = "currentColor" viewBox = "0 0 24 24"
729+ >
730+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M9 5l7 7-7 7" />
731+ </ svg >
732+ < span className = "text-sm font-medium text-gray-300 truncate" > { sensor . name } </ span >
714733 { isSensorStreaming && (
715- < span className = "w-2 h-2 bg-green-500 rounded-full animate-pulse" />
734+ < span className = "w-2 h-2 bg-green-500 rounded-full animate-pulse shrink-0 " />
716735 ) }
717- </ div >
736+ </ button >
718737 < button
719738 onClick = { ( ) => isSensorStreaming
720739 ? onStopSensorStreaming ( sensor . sensor_id )
@@ -744,6 +763,7 @@ function SensorStreamControls({
744763 </ div >
745764 ) }
746765
766+ { isExpanded && ( < >
747767 { sensorConfig && ! sensorConfig . isMotionSensor && (
748768 < div className = "mb-2 flex items-center gap-2 text-xs" >
749769 < div className = "flex items-center gap-1" >
@@ -794,6 +814,7 @@ function SensorStreamControls({
794814 />
795815 ) ) }
796816 </ div >
817+ </ > ) }
797818 </ div >
798819 )
799820 } ) }
@@ -987,22 +1008,20 @@ function SensorOptionsPanel({ sensor, options, searchQuery, isExpanded, onToggle
9871008 onClick = { onToggle }
9881009 className = "w-full flex items-center justify-between p-1.5 bg-gray-800/50 rounded hover:bg-gray-700 transition-colors text-xs"
9891010 >
990- < span className = "font-medium" > { sensor . name } </ span >
991- < div className = "flex items-center gap-1" >
992- { modifiedCount > 0 && (
993- < span className = "px-1.5 py-0.5 bg-rs-blue/20 text-rs-blue rounded text-[10px]" >
994- { modifiedCount } modified
995- </ span >
996- ) }
1011+ < span className = "flex items-center gap-1.5 font-medium min-w-0" >
9971012 < svg
998- className = { `w-4 h-4 transition-transform ${ isExpanded ? 'rotate-180' : '' } ` }
999- fill = "none"
1000- stroke = "currentColor"
1001- viewBox = "0 0 24 24"
1013+ className = { `w-3.5 h-3.5 shrink-0 text-gray-400 transition-transform ${ isExpanded ? 'rotate-90' : '' } ` }
1014+ fill = "none" stroke = "currentColor" viewBox = "0 0 24 24"
10021015 >
1003- < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M19 9l-7 7-7- 7" />
1016+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M9 5l7 7-7 7" />
10041017 </ svg >
1005- </ div >
1018+ < span className = "truncate" > { sensor . name } </ span >
1019+ </ span >
1020+ { modifiedCount > 0 && (
1021+ < span className = "px-1.5 py-0.5 bg-rs-blue/20 text-rs-blue rounded text-[10px]" >
1022+ { modifiedCount } modified
1023+ </ span >
1024+ ) }
10061025 </ button >
10071026
10081027 { isExpanded && (
@@ -1086,17 +1105,15 @@ function CategorySection({ category, options, searchQuery, isExpanded, onToggle,
10861105 < div className = "flex items-center bg-gray-750 hover:bg-gray-700 transition-colors" >
10871106 < button
10881107 onClick = { onToggle }
1089- className = "flex-1 flex items-center justify-between p-1.5"
1108+ className = "flex-1 flex items-center gap-1.5 p-1.5"
10901109 >
1091- < span className = "text-xs font-medium text-gray-300" > { category } </ span >
10921110 < svg
1093- className = { `w-3 h-3 transition-transform ${ isExpanded ? 'rotate-180' : '' } ` }
1094- fill = "none"
1095- stroke = "currentColor"
1096- viewBox = "0 0 24 24"
1111+ className = { `w-3 h-3 shrink-0 text-gray-400 transition-transform ${ isExpanded ? 'rotate-90' : '' } ` }
1112+ fill = "none" stroke = "currentColor" viewBox = "0 0 24 24"
10971113 >
1098- < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M19 9l-7 7-7- 7" />
1114+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M9 5l7 7-7 7" />
10991115 </ svg >
1116+ < span className = "text-xs font-medium text-gray-300" > { category } </ span >
11001117 </ button >
11011118 { hasModifiedOptions && (
11021119 < button
@@ -1177,17 +1194,15 @@ function PostProcessingSection({ options, searchQuery, isExpanded, onToggle, onR
11771194 < div className = "flex items-center bg-gray-750 hover:bg-gray-700 transition-colors" >
11781195 < button
11791196 onClick = { onToggle }
1180- className = "flex-1 flex items-center justify-between p-1.5"
1197+ className = "flex-1 flex items-center gap-1.5 p-1.5"
11811198 >
1182- < span className = "text-xs font-medium text-gray-300" > Post-Processing</ span >
11831199 < svg
1184- className = { `w-3 h-3 transition-transform ${ isExpanded ? 'rotate-180' : '' } ` }
1185- fill = "none"
1186- stroke = "currentColor"
1187- viewBox = "0 0 24 24"
1200+ className = { `w-3 h-3 shrink-0 text-gray-400 transition-transform ${ isExpanded ? 'rotate-90' : '' } ` }
1201+ fill = "none" stroke = "currentColor" viewBox = "0 0 24 24"
11881202 >
1189- < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M19 9l-7 7-7- 7" />
1203+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M9 5l7 7-7 7" />
11901204 </ svg >
1205+ < span className = "text-xs font-medium text-gray-300" > Post-Processing</ span >
11911206 </ button >
11921207 { hasModifiedOptions && (
11931208 < button
0 commit comments