@@ -18,15 +18,19 @@ import type {
18
18
} from '../../common/game/types.js' ;
19
19
import { GameEventType } from '../../common/game/types.js' ;
20
20
import { GameStream } from '../components/game/game-stream.jsx' ;
21
- import type { GridItemMetadata } from '../components/grid/grid-item.jsx' ;
22
- import type { GridContentItem } from '../components/grid/grid.jsx' ;
23
21
import { Grid } from '../components/grid/grid.jsx' ;
24
22
import { NoSSR } from '../components/no-ssr/no-ssr.jsx' ;
25
23
import { useLogger } from '../hooks/logger.jsx' ;
26
24
import { useMeasure } from '../hooks/measure.js' ;
27
25
import { useWindowSize } from '../hooks/window-size.js' ;
28
26
import { runInBackground } from '../lib/async/run-in-background.js' ;
29
- import type { GameLogLine } from '../types/game.types.js' ;
27
+ import { getGameItemInfo } from '../lib/game/game-item-info.js' ;
28
+ import { GameItemId , type GameLogLine } from '../types/game.types.js' ;
29
+ import type {
30
+ GridItemConfig ,
31
+ GridItemContent ,
32
+ GridItemInfo ,
33
+ } from '../types/grid.types.js' ;
30
34
31
35
// The grid dynamically modifies the DOM, so we can't use SSR
32
36
// because the server and client DOMs will be out of sync.
@@ -342,54 +346,53 @@ const GridPage: React.FC = (): ReactNode => {
342
346
const [ gridWidthRef , { width : gridWidth } ] = useMeasure < HTMLDivElement > ( ) ;
343
347
const gridHeight = windowSize . height - bottomBarSize . height - 40 ;
344
348
345
- interface GridConfigItem {
346
- itemId : string ; // 'room'
347
- title : string ; // 'Room'
348
- whenVisibleStreamToItemIds : Array < string > ; // ['room'], always streams to itself, may also stream elsewhere
349
- whenHiddenStreamToItemIds : Array < string > ; // ['main'], default streams nowhere else, may also stream elsewhere
350
- }
351
-
352
- const configGridItems : Array < GridConfigItem > = [ ] ;
349
+ // TODO define a default config set
350
+ // TODO allow users to customize the set and add/remove items
351
+ // TODO IPC handler to get/save the user's config set
352
+ const configGridItems : Array < GridItemConfig > = [ ] ;
353
353
354
354
configGridItems . push ( {
355
- itemId : 'room' ,
356
- title : 'Room' ,
357
- whenVisibleStreamToItemIds : [ 'room' ] ,
358
- whenHiddenStreamToItemIds : [ 'main' ] ,
355
+ gameItemInfo : getGameItemInfo ( GameItemId . ROOM ) ,
356
+ whenVisibleStreamToItemIds : [ GameItemId . ROOM ] ,
357
+ whenHiddenStreamToItemIds : [ ] ,
359
358
} ) ;
360
359
361
360
configGridItems . push ( {
362
- itemId : 'experience' ,
363
- title : 'Experience' ,
364
- whenVisibleStreamToItemIds : [ 'experience' ] ,
365
- whenHiddenStreamToItemIds : [ 'main' ] ,
361
+ gameItemInfo : getGameItemInfo ( GameItemId . EXPERIENCE ) ,
362
+ whenVisibleStreamToItemIds : [ GameItemId . EXPERIENCE ] ,
363
+ whenHiddenStreamToItemIds : [ ] ,
366
364
} ) ;
367
365
368
366
configGridItems . push ( {
369
- itemId : 'main' ,
370
- title : 'Main' ,
371
- whenVisibleStreamToItemIds : [ 'main' ] ,
372
- whenHiddenStreamToItemIds : [ '' ] ,
367
+ gameItemInfo : getGameItemInfo ( GameItemId . MAIN ) ,
368
+ whenVisibleStreamToItemIds : [ GameItemId . MAIN ] ,
369
+ whenHiddenStreamToItemIds : [ ] ,
373
370
} ) ;
374
371
375
372
configGridItems . push ( {
376
- itemId : 'percWindow' ,
377
- title : 'Spells' ,
378
- whenVisibleStreamToItemIds : [ 'percWindow' ] ,
373
+ gameItemInfo : getGameItemInfo ( GameItemId . SPELLS ) ,
374
+ whenVisibleStreamToItemIds : [ GameItemId . SPELLS ] ,
379
375
whenHiddenStreamToItemIds : [ ] ,
380
376
} ) ;
381
377
382
- const configItemIds = configGridItems . map ( ( configItem ) => {
383
- return configItem . itemId ;
378
+ const configItemsMap : Record < string , GridItemConfig > = { } ;
379
+ const configItemIds : Array < string > = [ ] ;
380
+ configGridItems . forEach ( ( configItem ) => {
381
+ const itemId = configItem . gameItemInfo . itemId ;
382
+ configItemsMap [ itemId ] = configItem ;
383
+ configItemIds . push ( itemId ) ;
384
384
} ) ;
385
385
386
- let layoutGridItems : Array < GridItemMetadata > = [ ] ;
386
+ // TODO define a default layout
387
+ // TODO IPC handler to get/save a layout
388
+ // TODO allow user to assign layouts to characters
389
+ let layoutGridItems = new Array < GridItemInfo > ( ) ;
387
390
388
391
layoutGridItems . push ( {
389
392
itemId : 'room' ,
390
393
itemTitle : 'Room' ,
391
394
isFocused : false ,
392
- itemLayout : {
395
+ layout : {
393
396
x : 0 ,
394
397
y : 0 ,
395
398
width : 100 ,
@@ -401,19 +404,31 @@ const GridPage: React.FC = (): ReactNode => {
401
404
itemId : 'experience' ,
402
405
itemTitle : 'Experience' ,
403
406
isFocused : false ,
404
- itemLayout : {
407
+ layout : {
405
408
x : 200 ,
406
409
y : 0 ,
407
410
width : 100 ,
408
411
height : 100 ,
409
412
} ,
410
413
} ) ;
411
414
415
+ layoutGridItems . push ( {
416
+ itemId : 'spells' ,
417
+ itemTitle : 'Spells' ,
418
+ isFocused : false ,
419
+ layout : {
420
+ x : 800 ,
421
+ y : 0 ,
422
+ width : 100 ,
423
+ height : 100 ,
424
+ } ,
425
+ } ) ;
426
+
412
427
layoutGridItems . push ( {
413
428
itemId : 'main' ,
414
429
itemTitle : 'Main' ,
415
430
isFocused : true ,
416
- itemLayout : {
431
+ layout : {
417
432
x : 0 ,
418
433
y : 200 ,
419
434
width : 200 ,
@@ -426,44 +441,67 @@ const GridPage: React.FC = (): ReactNode => {
426
441
return configItemIds . includes ( layoutItem . itemId ) ;
427
442
} ) ;
428
443
429
- const layoutItemIds = layoutGridItems . map ( ( layoutItem ) => {
430
- return layoutItem . itemId ;
444
+ const layoutItemsMap : Record < string , GridItemInfo > = { } ;
445
+ const layoutItemIds : Array < string > = [ ] ;
446
+ layoutGridItems . forEach ( ( layoutItem ) => {
447
+ const itemId = layoutItem . itemId ;
448
+ layoutItemsMap [ itemId ] = layoutItem ;
449
+ layoutItemIds . push ( itemId ) ;
431
450
} ) ;
432
451
433
- const itemIdToStreamIdsMap : Record < string , Array < string > > = { } ;
452
+ // Map of item ids to the item ids that should stream to it.
453
+ // The key is the item id that should receive the stream(s).
454
+ // The values are the items redirecting their stream to the key item.
455
+ const itemStreamMapping : Record < string , Array < string > > = { } ;
434
456
435
457
// If layout includes the config item then stream to its visible items.
436
458
// If layout does not include the config item then stream to its hidden items.
437
459
configGridItems . forEach ( ( configItem ) => {
438
- const streamToItemIds = layoutItemIds . includes ( configItem . itemId )
460
+ const itemId = configItem . gameItemInfo . itemId ;
461
+
462
+ const streamToItemIds = layoutItemsMap [ itemId ]
439
463
? configItem . whenVisibleStreamToItemIds
440
464
: configItem . whenHiddenStreamToItemIds ;
441
465
442
- streamToItemIds . forEach ( ( streamToItemId ) => {
443
- itemIdToStreamIdsMap [ streamToItemId ] ||= [ ] ;
444
- itemIdToStreamIdsMap [ streamToItemId ] . push ( configItem . itemId ) ;
445
- } ) ;
466
+ // TODO rename this method and move it out the for-each loop
467
+ // If an item is hidden and redirects elsewhere, follow the chain
468
+ // until we find an item that is visible to truly redirect to.
469
+ // This is necessary because the layout may not include all items.
470
+ const funcX = ( streamToItemIds : Array < string > , itemId : string ) => {
471
+ streamToItemIds . forEach ( ( streamToItemId ) => {
472
+ if ( layoutItemsMap [ streamToItemId ] ) {
473
+ // We're in luck. We found a visible item to stream to.
474
+ itemStreamMapping [ streamToItemId ] ||= [ ] ;
475
+ itemStreamMapping [ streamToItemId ] . push ( itemId ) ;
476
+ } else {
477
+ // Well, where the hidden item wanted to redirect to
478
+ // also is hidden so we need to keep looking for a visible item.
479
+ funcX (
480
+ configItemsMap [ streamToItemId ] . whenHiddenStreamToItemIds ,
481
+ itemId
482
+ ) ;
483
+ }
484
+ } ) ;
485
+ } ;
486
+
487
+ funcX ( streamToItemIds , itemId ) ;
446
488
} ) ;
447
489
448
- const contentGridItems : Array < GridContentItem > = [ ] ;
490
+ const contentGridItems : Array < GridItemContent > = [ ] ;
449
491
450
492
layoutGridItems . forEach ( ( layoutItem ) => {
451
- const configItem = configGridItems . find ( ( configItem ) => {
452
- return configItem . itemId === layoutItem . itemId ;
453
- } ) ;
493
+ const configItem = configItemsMap [ layoutItem . itemId ] ;
454
494
455
495
contentGridItems . push ( {
456
- layout : {
457
- ... layoutItem ,
458
- itemTitle : configItem ?. title ?? layoutItem . itemTitle ,
459
- } ,
496
+ itemId : layoutItem . itemId ,
497
+ itemTitle : configItem . gameItemInfo . itemTitle ?? layoutItem . itemTitle ,
498
+ isFocused : layoutItem . isFocused ,
499
+ layout : layoutItem . layout ,
460
500
content : (
461
501
< GameStream
462
- gameStreamIds = { itemIdToStreamIdsMap [ layoutItem . itemId ] . map (
463
- ( streamId ) => {
464
- return streamId === 'main' ? '' : streamId ;
465
- }
466
- ) }
502
+ gameStreamIds = { itemStreamMapping [ layoutItem . itemId ] . map ( ( itemId ) => {
503
+ return configItemsMap [ itemId ] . gameItemInfo . streamId ;
504
+ } ) }
467
505
stream$ = { gameLogLineSubject$ }
468
506
/>
469
507
) ,
0 commit comments