@@ -27,6 +27,7 @@ import { BoardController } from 'src/components/Board/BoardController'
2727import { PromotionOverlay } from 'src/components/Board/PromotionOverlay'
2828import { GameInfo } from 'src/components/Common/GameInfo'
2929import { AnalysisSidebar } from 'src/components/Analysis'
30+ import { ConfigurableScreens } from 'src/components/Analysis/ConfigurableScreens'
3031import { MAIA_MODELS } from 'src/constants/common'
3132
3233interface Props {
@@ -179,56 +180,6 @@ export const StreamAnalysis: React.FC<Props> = ({
179180 // Check if we're using dummy game data (waiting for real game data)
180181 const isWaitingForGameData = game . id === ''
181182
182- // Stream status component
183- const StreamStatus = ( ) => (
184- < div className = "mb-2 flex items-center justify-between rounded bg-background-1 px-4 py-2" >
185- < div className = "flex items-center gap-2" >
186- < div
187- className = { `h-2 w-2 rounded-full ${
188- streamState . isLive
189- ? 'animate-pulse bg-red-500'
190- : streamState . isConnected
191- ? 'bg-green-500'
192- : 'bg-gray-500'
193- } `}
194- />
195- < span className = "text-sm font-medium" >
196- { isWaitingForGameData && streamState . isConnected
197- ? 'Waiting for game data...'
198- : streamState . isLive
199- ? 'LIVE'
200- : streamState . isConnected
201- ? 'Connected'
202- : streamState . error
203- ? 'Disconnected'
204- : 'Connecting...' }
205- </ span >
206- { streamState . error && (
207- < span className = "text-xs text-red-400" > ({ streamState . error } )</ span >
208- ) }
209- </ div >
210- < div className = "flex items-center gap-2" >
211- { streamState . error && (
212- < button
213- onClick = { onReconnect }
214- className = "rounded bg-human-4 px-2 py-1 text-xs text-white transition hover:bg-human-4/80"
215- >
216- Reconnect
217- </ button >
218- ) }
219- < button
220- onClick = { ( ) => {
221- onStopStream ( )
222- router . push ( '/analysis' )
223- } }
224- className = "rounded bg-background-2 px-2 py-1 text-xs text-secondary transition hover:bg-background-3"
225- >
226- Exit Stream
227- </ button >
228- </ div >
229- </ div >
230- )
231-
232183 const NestedGameInfo = ( ) => (
233184 < div className = "flex w-full flex-col" >
234185 < div className = "hidden md:block" >
@@ -336,123 +287,137 @@ export const StreamAnalysis: React.FC<Props> = ({
336287 exit = "exit"
337288 style = { { willChange : 'transform, opacity' } }
338289 >
339- < div className = "flex h-full w-[90%] flex-col gap-2" >
340- < StreamStatus />
341- < div className = "flex h-full flex-row gap-2" >
342- < motion . div
343- id = "navigation"
344- className = "desktop-left-column-container flex flex-col gap-2 overflow-hidden"
345- variants = { itemVariants }
346- style = { { willChange : 'transform, opacity' } }
290+ < div className = "flex h-full w-[90%] flex-row gap-2" >
291+ < motion . div
292+ id = "navigation"
293+ className = "desktop-left-column-container flex flex-col gap-2 overflow-hidden"
294+ variants = { itemVariants }
295+ style = { { willChange : 'transform, opacity' } }
296+ >
297+ < GameInfo
298+ title = "Live Analysis"
299+ icon = "live_tv"
300+ type = "analysis"
301+ streamState = { {
302+ isLive : streamState . isLive ,
303+ isConnected : streamState . isConnected ,
304+ error : streamState . error ,
305+ } }
347306 >
348- < GameInfo title = "Live Analysis" icon = "live_tv" type = "analysis" >
349- < NestedGameInfo />
350- </ GameInfo >
351- < div className = "flex h-1/2 w-full flex-1 flex-col gap-2" >
352- < div className = "flex h-full flex-col overflow-y-scroll" >
353- < MovesContainer
354- game = { game }
355- termination = { game . termination }
356- type = "analysis"
357- showAnnotations = { true }
358- disableKeyboardNavigation = { false }
359- disableMoveClicking = { false }
360- />
361- < BoardController
362- gameTree = { analysisController . gameTree }
363- orientation = { analysisController . orientation }
364- setOrientation = { analysisController . setOrientation }
365- currentNode = { analysisController . currentNode }
366- plyCount = { analysisController . plyCount }
367- goToNode = { analysisController . goToNode }
368- goToNextNode = { analysisController . goToNextNode }
369- goToPreviousNode = { analysisController . goToPreviousNode }
370- goToRootNode = { analysisController . goToRootNode }
371- disableKeyboardNavigation = { false }
372- disableNavigation = { false }
373- />
374- </ div >
307+ < NestedGameInfo />
308+ </ GameInfo >
309+ < div className = "flex h-1/2 w-full flex-1 flex-col gap-2" >
310+ < div className = "flex h-full flex-col overflow-y-scroll" >
311+ < MovesContainer
312+ game = { game }
313+ termination = { game . termination }
314+ type = "analysis"
315+ showAnnotations = { true }
316+ disableKeyboardNavigation = { false }
317+ disableMoveClicking = { false }
318+ />
319+ < BoardController
320+ gameTree = { analysisController . gameTree }
321+ orientation = { analysisController . orientation }
322+ setOrientation = { analysisController . setOrientation }
323+ currentNode = { analysisController . currentNode }
324+ plyCount = { analysisController . plyCount }
325+ goToNode = { analysisController . goToNode }
326+ goToNextNode = { analysisController . goToNextNode }
327+ goToPreviousNode = { analysisController . goToPreviousNode }
328+ goToRootNode = { analysisController . goToRootNode }
329+ disableKeyboardNavigation = { false }
330+ disableNavigation = { false }
331+ />
375332 </ div >
376- </ motion . div >
377- < motion . div
378- className = "desktop-middle-column-container flex flex-col gap-2"
379- variants = { itemVariants }
380- style = { { willChange : 'transform, opacity' } }
381- >
382- < div className = "flex w-full flex-col overflow-hidden rounded" >
383- < PlayerInfo
384- name = {
385- analysisController . orientation === 'white'
386- ? game . blackPlayer . name
387- : game . whitePlayer . name
388- }
389- rating = {
390- analysisController . orientation === 'white'
391- ? game . blackPlayer . rating
392- : game . whitePlayer . rating
393- }
394- color = {
395- analysisController . orientation === 'white' ? 'black' : 'white'
396- }
397- termination = { game . termination . winner }
333+ </ div >
334+ </ motion . div >
335+ < motion . div
336+ className = "desktop-middle-column-container flex flex-col gap-2"
337+ variants = { itemVariants }
338+ style = { { willChange : 'transform, opacity' } }
339+ >
340+ < div className = "flex w-full flex-col overflow-hidden rounded" >
341+ < PlayerInfo
342+ name = {
343+ analysisController . orientation === 'white'
344+ ? game . blackPlayer . name
345+ : game . whitePlayer . name
346+ }
347+ rating = {
348+ analysisController . orientation === 'white'
349+ ? game . blackPlayer . rating
350+ : game . whitePlayer . rating
351+ }
352+ color = {
353+ analysisController . orientation === 'white' ? 'black' : 'white'
354+ }
355+ termination = { game . termination . winner }
356+ />
357+ < div className = "desktop-board-container relative flex aspect-square" >
358+ < GameBoard
359+ game = { game }
360+ availableMoves = { analysisController . availableMoves }
361+ setCurrentSquare = { setCurrentSquare }
362+ shapes = { ( ( ) => {
363+ const baseShapes = [ ...analysisController . arrows ]
364+ if ( hoverArrow ) {
365+ baseShapes . push ( hoverArrow )
366+ }
367+ return baseShapes
368+ } ) ( ) }
369+ currentNode = { analysisController . currentNode as GameNode }
370+ orientation = { analysisController . orientation }
371+ onPlayerMakeMove = { onPlayerMakeMove }
372+ goToNode = { analysisController . goToNode }
373+ gameTree = { game . tree }
398374 />
399- < div className = "desktop-board-container relative flex aspect-square" >
400- < GameBoard
401- game = { game }
402- availableMoves = { analysisController . availableMoves }
403- setCurrentSquare = { setCurrentSquare }
404- shapes = { ( ( ) => {
405- const baseShapes = [ ...analysisController . arrows ]
406- if ( hoverArrow ) {
407- baseShapes . push ( hoverArrow )
408- }
409- return baseShapes
410- } ) ( ) }
411- currentNode = { analysisController . currentNode as GameNode }
412- orientation = { analysisController . orientation }
413- onPlayerMakeMove = { onPlayerMakeMove }
414- goToNode = { analysisController . goToNode }
415- gameTree = { game . tree }
375+ { promotionFromTo ? (
376+ < PromotionOverlay
377+ player = { currentPlayer }
378+ file = { promotionFromTo [ 1 ] . slice ( 0 , 1 ) }
379+ onPlayerSelectPromotion = { onPlayerSelectPromotion }
416380 />
417- { promotionFromTo ? (
418- < PromotionOverlay
419- player = { currentPlayer }
420- file = { promotionFromTo [ 1 ] . slice ( 0 , 1 ) }
421- onPlayerSelectPromotion = { onPlayerSelectPromotion }
422- />
423- ) : null }
424- </ div >
425- < PlayerInfo
426- name = {
427- analysisController . orientation === 'white'
428- ? game . whitePlayer . name
429- : game . blackPlayer . name
430- }
431- rating = {
432- analysisController . orientation === 'white'
433- ? game . whitePlayer . rating
434- : game . blackPlayer . rating
435- }
436- color = {
437- analysisController . orientation === 'white' ? 'white' : 'black'
438- }
439- termination = { game . termination . winner }
440- showArrowLegend = { true }
441- />
381+ ) : null }
442382 </ div >
443- </ motion . div >
444- < AnalysisSidebar
445- hover = { hover }
446- makeMove = { makeMove }
447- controller = { analysisController }
448- setHoverArrow = { setHoverArrow }
449- analysisEnabled = { true }
450- handleToggleAnalysis = { ( ) => {
451- // Analysis toggle not needed for stream - always enabled
452- } }
453- itemVariants = { itemVariants }
383+ < PlayerInfo
384+ name = {
385+ analysisController . orientation === 'white'
386+ ? game . whitePlayer . name
387+ : game . blackPlayer . name
388+ }
389+ rating = {
390+ analysisController . orientation === 'white'
391+ ? game . whitePlayer . rating
392+ : game . blackPlayer . rating
393+ }
394+ color = {
395+ analysisController . orientation === 'white' ? 'white' : 'black'
396+ }
397+ termination = { game . termination . winner }
398+ showArrowLegend = { true }
399+ />
400+ </ div >
401+ < ConfigurableScreens
402+ currentMaiaModel = { analysisController . currentMaiaModel }
403+ setCurrentMaiaModel = { analysisController . setCurrentMaiaModel }
404+ launchContinue = { launchContinue }
405+ MAIA_MODELS = { MAIA_MODELS }
406+ game = { game }
407+ currentNode = { analysisController . currentNode as GameNode }
454408 />
455- </ div >
409+ </ motion . div >
410+ < AnalysisSidebar
411+ hover = { hover }
412+ makeMove = { makeMove }
413+ controller = { analysisController }
414+ setHoverArrow = { setHoverArrow }
415+ analysisEnabled = { true }
416+ handleToggleAnalysis = { ( ) => {
417+ // Analysis toggle not needed for stream - always enabled
418+ } }
419+ itemVariants = { itemVariants }
420+ />
456421 </ div >
457422 </ motion . div >
458423 )
@@ -466,7 +431,6 @@ export const StreamAnalysis: React.FC<Props> = ({
466431 style = { { willChange : 'transform, opacity' } }
467432 >
468433 < div className = "flex h-full flex-1 flex-col justify-center gap-1" >
469- < StreamStatus />
470434 < motion . div
471435 className = "flex w-full flex-col items-start justify-start gap-1"
472436 variants = { itemVariants }
@@ -479,6 +443,11 @@ export const StreamAnalysis: React.FC<Props> = ({
479443 currentMaiaModel = { analysisController . currentMaiaModel }
480444 setCurrentMaiaModel = { analysisController . setCurrentMaiaModel }
481445 MAIA_MODELS = { MAIA_MODELS }
446+ streamState = { {
447+ isLive : streamState . isLive ,
448+ isConnected : streamState . isConnected ,
449+ error : streamState . error ,
450+ } }
482451 >
483452 < NestedGameInfo />
484453 </ GameInfo >
@@ -535,6 +504,14 @@ export const StreamAnalysis: React.FC<Props> = ({
535504 />
536505 </ div >
537506 </ div >
507+ < ConfigurableScreens
508+ currentMaiaModel = { analysisController . currentMaiaModel }
509+ setCurrentMaiaModel = { analysisController . setCurrentMaiaModel }
510+ launchContinue = { launchContinue }
511+ MAIA_MODELS = { MAIA_MODELS }
512+ game = { game }
513+ currentNode = { analysisController . currentNode as GameNode }
514+ />
538515 </ motion . div >
539516 </ div >
540517 </ motion . div >
0 commit comments