1
0
Fork 0
taleweave-ai/client/src/status.tsx

112 lines
3.8 KiB
TypeScript

import { Edit, Save } from '@mui/icons-material';
import { Alert, AlertColor, FormControlLabel, FormGroup, IconButton, Stack, Switch, TextField, Typography } from '@mui/material';
import React from 'react';
import { ReadyState } from 'react-use-websocket';
import { useStore } from 'zustand';
import { StoreState, store } from './store.js';
const statusStrings: Record<ReadyState, string> = {
[ReadyState.CONNECTING]: 'Connecting',
[ReadyState.OPEN]: 'Running',
[ReadyState.CLOSING]: 'Closing',
[ReadyState.CLOSED]: 'Closed',
[ReadyState.UNINSTANTIATED]: 'Unready',
};
const statusColors: Record<ReadyState, AlertColor> = {
[ReadyState.CONNECTING]: 'info',
[ReadyState.OPEN]: 'success',
[ReadyState.CLOSING]: 'warning',
[ReadyState.CLOSED]: 'warning',
[ReadyState.UNINSTANTIATED]: 'warning',
};
function download(filename: string, text: string) {
const element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
export function statusbarStateSelector(s: StoreState) {
return {
autoScroll: s.autoScroll,
clientName: s.clientName,
layoutMode: s.layoutMode,
readyState: s.readyState,
themeMode: s.themeMode,
setAutoScroll: s.setAutoScroll,
setClientName: s.setClientName,
setLayoutMode: s.setLayoutMode,
setThemeMode: s.setThemeMode,
eventHistory: s.eventHistory,
};
}
export interface StatusbarProps {
setName: (name: string) => void;
}
export function Statusbar(props: StatusbarProps) {
const { setName } = props;
const state = useStore(store, statusbarStateSelector);
const { autoScroll, clientName, layoutMode, readyState, themeMode, setAutoScroll, setClientName, setLayoutMode, setThemeMode, eventHistory } = state;
const connectionStatus = statusStrings[readyState as ReadyState];
return <Alert icon={false} severity={statusColors[readyState as ReadyState]}>
<Stack direction="row" alignItems="center" gap={4}>
<Typography>
Status: {connectionStatus}
</Typography>
<FormGroup row>
<FormControlLabel control={<Switch
checked={themeMode === 'dark'}
onChange={() => setThemeMode(themeMode === 'dark' ? 'light' : 'dark')}
inputProps={{ 'aria-label': 'controlled' }}
sx={{ marginLeft: 'auto' }}
/>} label="Dark Mode" />
<FormControlLabel control={<Switch
checked={autoScroll}
onChange={() => setAutoScroll(autoScroll === false)}
inputProps={{ 'aria-label': 'controlled' }}
sx={{ marginLeft: 'auto' }}
/>} label="Auto Scroll" />
<FormControlLabel control={<Switch
checked={layoutMode === 'vertical'}
onChange={() => setLayoutMode(layoutMode === 'vertical' ? 'horizontal' : 'vertical')}
inputProps={{ 'aria-label': 'controlled' }}
sx={{ marginLeft: 'auto' }}
/>} label="Vertical Layout" />
</FormGroup>
<FormGroup row>
<TextField
label="Player Name"
value={clientName}
onChange={(e) => setClientName(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
setName(clientName);
}
}}
sx={{ marginLeft: 'auto' }}
/>
<IconButton onClick={() => setName(clientName)}>
<Edit />
</IconButton>
</FormGroup>
<FormGroup row>
<FormControlLabel control={<IconButton onClick={() => download('events.json', JSON.stringify(eventHistory, undefined, 2))}>
<Save />
</IconButton>} label="Download History" />
</FormGroup>
</Stack>
</Alert>;
}