Files
xrpl-hooks-ide/components/LogBox.tsx
2023-01-11 21:08:17 +05:30

179 lines
4.3 KiB
TypeScript

import { useRef, useLayoutEffect, ReactNode, FC, useState } from 'react'
import { IconProps, Notepad, Prohibit } from 'phosphor-react'
import useStayScrolled from 'react-stay-scrolled'
import NextLink from 'next/link'
import Container from './Container'
import LogText from './LogText'
import { ILog } from '../state'
import { Pre, Link, Heading, Button, Text, Flex, Box } from '.'
interface ILogBox {
title: string
clearLog?: () => void
logs: ILog[]
renderNav?: () => ReactNode
enhanced?: boolean
Icon?: FC<IconProps>
}
const LogBox: FC<ILogBox> = ({
title,
clearLog,
logs,
children,
renderNav,
enhanced,
Icon = Notepad
}) => {
const logRef = useRef<HTMLPreElement>(null)
const { stayScrolled /*, scrollBottom*/ } = useStayScrolled(logRef)
useLayoutEffect(() => {
stayScrolled()
}, [stayScrolled, logs])
return (
<Flex
as="div"
css={{
display: 'flex',
borderTop: '1px solid $mauve6',
background: '$mauve1',
position: 'relative',
flex: 1,
height: '100%'
}}
>
<Container
css={{
px: 0,
height: '100%'
}}
>
<Flex
fluid
css={{
height: '48px',
alignItems: 'center',
fontSize: '$sm',
fontWeight: 300
}}
>
<Heading
as="h3"
css={{
fontWeight: 300,
m: 0,
fontSize: '11px',
color: '$mauve12',
px: '$3',
textTransform: 'uppercase',
alignItems: 'center',
display: 'inline-flex',
gap: '$3'
}}
>
<Icon size="15px" /> <Text css={{ lineHeight: 1 }}>{title}</Text>
</Heading>
<Flex
row
align="center"
// css={{
// maxWidth: "100%", // TODO make it max without breaking layout!
// }}
>
{renderNav?.()}
</Flex>
<Flex css={{ ml: 'auto', gap: '$3', marginRight: '$3' }}>
{clearLog && (
<Button ghost size="xs" onClick={clearLog}>
<Prohibit size="14px" />
</Button>
)}
</Flex>
</Flex>
<Box
as="pre"
ref={logRef}
css={{
margin: 0,
// display: "inline-block",
display: 'flex',
flexDirection: 'column',
width: '100%',
height: 'calc(100% - 48px)', // 100% minus the logbox header height
overflowY: 'auto',
fontSize: '13px',
fontWeight: '$body',
fontFamily: '$monospace',
px: '$3',
pb: '$2',
whiteSpace: 'normal'
}}
>
{logs?.map((log, index) => (
<Box
as="span"
key={log.type + index}
css={{
'@hover': {
'&:hover': {
backgroundColor: enhanced ? '$backgroundAlt' : undefined
}
},
p: enhanced ? '$1' : undefined,
my: enhanced ? '$1' : undefined
}}
>
<Log {...log} />
</Box>
))}
{children}
</Box>
</Container>
</Flex>
)
}
export const Log: FC<ILog> = ({
type,
timestring,
message,
link,
linkText,
defaultCollapsed,
jsonData
}) => {
const [expanded, setExpanded] = useState(!defaultCollapsed)
if (message === undefined) message = <Text muted>{'undefined'}</Text>
else if (message === '') message = <Text muted>{'""'}</Text>
return (
<>
<LogText variant={type}>
{timestring && (
<Text muted monospace>
{timestring}{' '}
</Text>
)}
<Pre>{message}</Pre>
{link && (
<NextLink legacyBehavior href={link} shallow passHref>
<Link as="a">{linkText}</Link>
</NextLink>
)}
{jsonData && (
<Link onClick={() => setExpanded(!expanded)} as="a">
{expanded ? 'Collapse' : 'Expand'}
</Link>
)}
{expanded && jsonData && <Pre block>{jsonData}</Pre>}
</LogText>
</>
)
}
export default LogBox