Skip to content

Commit dc4b3ac

Browse files
committed
feat: use game content component
1 parent a53b7e7 commit dc4b3ac

File tree

1 file changed

+35
-166
lines changed

1 file changed

+35
-166
lines changed

electron/renderer/pages/grid.tsx

+35-166
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import { EuiText, useEuiTheme } from '@elastic/eui';
2-
import type { SerializedStyles } from '@emotion/react';
1+
import { useEuiTheme } from '@elastic/eui';
32
import { css } from '@emotion/react';
43
import { isEmpty } from 'lodash';
54
import dynamic from 'next/dynamic';
65
import { useObservable, useSubscription } from 'observable-hooks';
76
import type { ReactNode } from 'react';
8-
import { useCallback, useEffect, useRef, useState } from 'react';
7+
import { useCallback, useEffect, useState } from 'react';
98
import * as rxjs from 'rxjs';
109
import { v4 as uuid } from 'uuid';
1110
import { GameEventType } from '../../common/game';
@@ -14,136 +13,16 @@ import type {
1413
GameEvent,
1514
RoomGameEvent,
1615
} from '../../common/game';
16+
import { GameContent } from '../components/game';
17+
import type { GameLogLine } from '../components/game';
1718
import { Grid } from '../components/grid';
18-
import { useLogger } from '../components/logger';
19+
import { useLogger } from '../hooks/logger';
1920

2021
// The grid dynamically modifies the DOM, so we can't use SSR
2122
// because the server and client DOMs will be out of sync.
2223
// https://nextjs.org/docs/messages/react-hydration-error
2324
const GridNoSSR = dynamic(async () => Grid, { ssr: false });
2425

25-
interface GameLogLine {
26-
/**
27-
* A unique id for this log line.
28-
* Primarily used for React keys.
29-
* https://react.dev/learn/rendering-lists
30-
*/
31-
eventId: string;
32-
/**
33-
* The game stream id that this line is destined for.
34-
*/
35-
streamId: string;
36-
/**
37-
* The text formatting to apply to this line.
38-
*/
39-
styles: SerializedStyles;
40-
/**
41-
* The text to display.
42-
*/
43-
text: string;
44-
}
45-
46-
interface DougCmpProps {
47-
/**
48-
* The stream of game text to display.
49-
* The stream is additive, so each new line will be appended to the end.
50-
* The special log line text '__CLEAR_STREAM__' will clear all prior lines.
51-
*/
52-
stream$: rxjs.Observable<GameLogLine>;
53-
/**
54-
* Enable to automatically scroll to the bottom of the game stream window
55-
* as new log lines are added. This effect only occurs if the user
56-
* is already scrolled to the bottom to ensure they see latest content.
57-
*/
58-
enableScrollToNewLogLines: boolean;
59-
}
60-
61-
const DougCmp: React.FC<DougCmpProps> = (props: DougCmpProps): ReactNode => {
62-
const { stream$, enableScrollToNewLogLines } = props;
63-
64-
useSubscription(stream$, (logLine) => {
65-
if (logLine.text === '__CLEAR_STREAM__') {
66-
setGameLogLines([]);
67-
} else {
68-
appendGameLogLine(logLine);
69-
}
70-
});
71-
72-
const scrollableRef = useRef<HTMLDivElement>(null);
73-
const scrollBottomRef = useRef<HTMLSpanElement>(null);
74-
75-
const [autoScrollEnabled, setAutoScrollEnabled] = useState<boolean>(
76-
enableScrollToNewLogLines
77-
);
78-
79-
const [gameLogLines, setGameLogLines] = useState<Array<GameLogLine>>([]);
80-
81-
const appendGameLogLine = useCallback((newLogLine: GameLogLine) => {
82-
// Max number of most recent lines to keep.
83-
const scrollbackBuffer = 500;
84-
setGameLogLines((oldLogLines) => {
85-
// Append new log line to the list.
86-
let newLogLines = oldLogLines.concat(newLogLine);
87-
// Trim the back of the list to keep it within the scrollback buffer.
88-
newLogLines = newLogLines.slice(scrollbackBuffer * -1);
89-
return newLogLines;
90-
});
91-
}, []);
92-
93-
useEffect(() => {
94-
if (!enableScrollToNewLogLines) {
95-
return;
96-
}
97-
98-
let scrollableElmt = scrollableRef.current;
99-
100-
const onScroll = () => {
101-
scrollableElmt = scrollableRef.current;
102-
103-
if (!scrollableElmt) {
104-
return;
105-
}
106-
107-
const { scrollTop, scrollHeight, clientHeight } = scrollableElmt;
108-
const difference = scrollHeight - clientHeight - scrollTop;
109-
const enableAutoScroll = difference <= clientHeight;
110-
111-
setAutoScrollEnabled(enableAutoScroll);
112-
};
113-
114-
scrollableElmt?.addEventListener('scroll', onScroll);
115-
116-
return () => {
117-
scrollableElmt?.removeEventListener('scroll', onScroll);
118-
};
119-
}, [enableScrollToNewLogLines]);
120-
121-
if (autoScrollEnabled) {
122-
scrollBottomRef.current?.scrollIntoView({
123-
behavior: 'instant',
124-
block: 'end',
125-
inline: 'nearest',
126-
});
127-
}
128-
129-
return (
130-
<div
131-
ref={scrollableRef}
132-
className={'eui-yScroll'}
133-
style={{ height: '100%', overflowY: 'scroll' }}
134-
>
135-
{gameLogLines.map((logLine) => {
136-
return (
137-
<EuiText key={logLine.eventId} css={logLine.styles}>
138-
{logLine.text}
139-
</EuiText>
140-
);
141-
})}
142-
<span ref={scrollBottomRef} />
143-
</div>
144-
);
145-
};
146-
14726
// I started tracking this via `useState` but when calling it's setter
14827
// the value did not update fast enough before a text game event
14928
// was received, resulting in text routing to the wrong stream window.
@@ -394,119 +273,109 @@ const GridPage: React.FC = (): ReactNode => {
394273
itemId: 'room',
395274
title: 'Room',
396275
content: (
397-
<DougCmp
276+
<GameContent
277+
gameStreamIds={['room']}
278+
stream$={gameLogLineSubject$}
398279
enableScrollToNewLogLines={false}
399-
stream$={gameLogLineSubject$.pipe(
400-
rxjs.filter((m) => m.streamId === 'room')
401-
)}
402280
/>
403281
),
404282
},
405283
{
406284
itemId: 'experience',
407285
title: 'Experience',
408286
content: (
409-
<DougCmp
287+
<GameContent
288+
gameStreamIds={['experience']}
289+
stream$={gameLogLineSubject$}
410290
enableScrollToNewLogLines={false}
411-
stream$={gameLogLineSubject$.pipe(
412-
rxjs.filter((m) => m.streamId === 'experience')
413-
)}
414291
/>
415292
),
416293
},
417294
{
418295
itemId: 'percWindow',
419296
title: 'Spells',
420297
content: (
421-
<DougCmp
298+
<GameContent
299+
gameStreamIds={['percWindow']}
300+
stream$={gameLogLineSubject$}
422301
enableScrollToNewLogLines={false}
423-
stream$={gameLogLineSubject$.pipe(
424-
rxjs.filter((m) => m.streamId === 'percWindow')
425-
)}
426302
/>
427303
),
428304
},
429305
{
430306
itemId: 'inv',
431307
title: 'Inventory',
432308
content: (
433-
<DougCmp
309+
<GameContent
310+
gameStreamIds={['inv']}
311+
stream$={gameLogLineSubject$}
434312
enableScrollToNewLogLines={false}
435-
stream$={gameLogLineSubject$.pipe(
436-
rxjs.filter((m) => m.streamId === 'inv')
437-
)}
438313
/>
439314
),
440315
},
441316
{
442317
itemId: 'familiar',
443318
title: 'Familiar',
444319
content: (
445-
<DougCmp
320+
<GameContent
321+
gameStreamIds={['familiar']}
322+
stream$={gameLogLineSubject$}
446323
enableScrollToNewLogLines={true}
447-
stream$={gameLogLineSubject$.pipe(
448-
rxjs.filter((m) => m.streamId === 'familiar')
449-
)}
450324
/>
451325
),
452326
},
453327
{
454328
itemId: 'thoughts',
455329
title: 'Thoughts',
456330
content: (
457-
<DougCmp
331+
<GameContent
332+
gameStreamIds={['thoughts']}
333+
stream$={gameLogLineSubject$}
458334
enableScrollToNewLogLines={true}
459-
stream$={gameLogLineSubject$.pipe(
460-
rxjs.filter((m) => m.streamId === 'thoughts')
461-
)}
462335
/>
463336
),
464337
},
465338
{
466339
itemId: 'combat',
467340
title: 'Combat',
468341
content: (
469-
<DougCmp
342+
<GameContent
343+
gameStreamIds={['combat']}
344+
stream$={gameLogLineSubject$}
470345
enableScrollToNewLogLines={true}
471-
stream$={gameLogLineSubject$.pipe(
472-
rxjs.filter((m) => m.streamId === 'combat')
473-
)}
474346
/>
475347
),
476348
},
477349
{
478350
itemId: 'logons',
479351
title: 'Logons',
480352
content: (
481-
<DougCmp
353+
<GameContent
354+
gameStreamIds={['logons']}
355+
stream$={gameLogLineSubject$}
482356
enableScrollToNewLogLines={true}
483-
stream$={gameLogLineSubject$.pipe(
484-
rxjs.filter((m) => m.streamId === 'logons')
485-
)}
486357
/>
487358
),
488359
},
489360
{
490361
itemId: 'death',
491362
title: 'Deaths',
492363
content: (
493-
<DougCmp
364+
<GameContent
365+
gameStreamIds={['death']}
366+
stream$={gameLogLineSubject$}
494367
enableScrollToNewLogLines={true}
495-
stream$={gameLogLineSubject$.pipe(
496-
rxjs.filter((m) => m.streamId === 'death')
497-
)}
498368
/>
499369
),
500370
},
501371
{
502372
itemId: 'main',
503373
title: 'Main',
504374
content: (
505-
<DougCmp
375+
<GameContent
376+
gameStreamIds={['']}
377+
stream$={gameLogLineSubject$}
506378
enableScrollToNewLogLines={true}
507-
stream$={gameLogLineSubject$.pipe(
508-
rxjs.filter((m) => m.streamId === '')
509-
)}
510379
/>
511380
),
512381
},

0 commit comments

Comments
 (0)