diff options
Diffstat (limited to 'gui/packages/components/src')
| -rw-r--r-- | gui/packages/components/src/ConnectionInfo.tsx | 125 | ||||
| -rw-r--r-- | gui/packages/components/src/ConnectionInfoDisclosure.tsx | 89 | ||||
| -rw-r--r-- | gui/packages/components/src/ImageView.tsx | 2 |
3 files changed, 176 insertions, 40 deletions
diff --git a/gui/packages/components/src/ConnectionInfo.tsx b/gui/packages/components/src/ConnectionInfo.tsx index 546d0f9c44..c4aaeef29f 100644 --- a/gui/packages/components/src/ConnectionInfo.tsx +++ b/gui/packages/components/src/ConnectionInfo.tsx @@ -1,21 +1,38 @@ import * as React from 'react'; -import { Component, Styles, Text, View } from 'reactxp'; -import { default as Accordion } from './Accordion'; +import { Component, Styles, Text, Types, View } from 'reactxp'; +import { default as ConnectionInfoDisclosure } from './ConnectionInfoDisclosure'; const styles = { - toggle: Styles.createTextStyle({ + row: Styles.createViewStyle({ + flexDirection: 'row', + marginTop: 3, + }), + caption: Styles.createTextStyle({ fontFamily: 'Open Sans', - fontSize: 14, - fontWeight: '800', - color: 'rgb(255, 255, 255, 0.4)', - paddingBottom: 2, + fontSize: 13, + fontWeight: '600', + color: 'rgb(255, 255, 255)', + flex: 0, + flexBasis: 30, + marginRight: 8, }), - content: Styles.createTextStyle({ + value: Styles.createTextStyle({ + fontFamily: 'Open Sans', + fontSize: 13, + fontWeight: '600', + color: 'rgb(255, 255, 255)', + letterSpacing: -0.2, + }), + header: Styles.createViewStyle({ + flexDirection: 'row', + alignItems: 'center', + }), + hostname: Styles.createTextStyle({ fontFamily: 'Open Sans', fontSize: 16, - fontWeight: '800', + fontWeight: '600', color: 'rgb(255, 255, 255)', - paddingBottom: 2, + flex: 1, }), }; @@ -26,49 +43,79 @@ interface IInAddress { } interface IOutAddress { - ipv4: string | null; - ipv6: string | null; + ipv4?: string; + ipv6?: string; } interface IProps { + hostname?: string; inAddress?: IInAddress; - outAddress: IOutAddress; - isExpanded: boolean; - onToggle?: () => void; + outAddress?: IOutAddress; + defaultOpen?: boolean; + style?: Types.ViewStyleRuleSet | Types.ViewStyleRuleSet[]; + onToggle?: (isOpen: boolean) => void; } -export default class ConnectionInfo extends Component<IProps> { +interface IState { + isOpen: boolean; +} + +export default class ConnectionInfo extends Component<IProps, IState> { + constructor(props: IProps) { + super(props); + + this.state = { + isOpen: props.defaultOpen === true, + }; + } + public render() { const { inAddress, outAddress } = this.props; return ( - <View> - <Accordion height={this.props.isExpanded ? 'auto' : 0}> - {inAddress && ( - <Text style={styles.content}>{`IN: ${inAddress.ip}:${inAddress.port} - ${ - inAddress.protocol - }`}</Text> - )} + <View style={this.props.style}> + <View style={styles.header}> + <Text style={styles.hostname}>{this.props.hostname || ''}</Text> + <ConnectionInfoDisclosure defaultOpen={this.props.defaultOpen} onToggle={this.onToggle}> + {'Connection details'} + </ConnectionInfoDisclosure> + </View> + + {this.state.isOpen && ( + <React.Fragment> + {inAddress && ( + <View style={styles.row}> + <Text style={styles.caption}>{'In'}</Text> + <Text style={styles.value}> + {`${inAddress.ip}:${inAddress.port} ${inAddress.protocol.toUpperCase()}`} + </Text> + </View> + )} - {(outAddress.ipv4 || outAddress.ipv6) && ( - <Text style={styles.content}> - {'OUT: ' + - [outAddress.ipv4, outAddress.ipv6] - .filter((a) => typeof a !== 'undefined') - .join(' / ')} - </Text> - )} - </Accordion> - <Text style={styles.toggle} onPress={this.toggle}> - {this.props.isExpanded ? 'LESS' : 'MORE'} - </Text> + {outAddress && + (outAddress.ipv4 || outAddress.ipv6) && ( + <View style={styles.row}> + <Text style={styles.caption}>{'Out'}</Text> + <View> + {outAddress.ipv4 && <Text style={styles.value}>{outAddress.ipv4}</Text>} + {outAddress.ipv6 && <Text style={styles.value}>{outAddress.ipv6}</Text>} + </View> + </View> + )} + </React.Fragment> + )} </View> ); } - private toggle = () => { - if (this.props.onToggle) { - this.props.onToggle(); - } + private onToggle = (isOpen: boolean) => { + this.setState( + (state) => ({ ...state, isOpen }), + () => { + if (this.props.onToggle) { + this.props.onToggle(isOpen); + } + }, + ); }; } diff --git a/gui/packages/components/src/ConnectionInfoDisclosure.tsx b/gui/packages/components/src/ConnectionInfoDisclosure.tsx new file mode 100644 index 0000000000..93cd17b1d0 --- /dev/null +++ b/gui/packages/components/src/ConnectionInfoDisclosure.tsx @@ -0,0 +1,89 @@ +import * as React from 'react'; +import { Component, Styles, Text, Types, View } from 'reactxp'; +import ImageView from './ImageView'; + +const styles = { + container: Styles.createViewStyle({ + flexDirection: 'row', + alignItems: 'center', + }), + caption: { + base: Styles.createTextStyle({ + fontFamily: 'Open Sans', + fontSize: 13, + fontWeight: '600', + color: 'rgb(255, 255, 255, 0.4)', + }), + hovered: Styles.createTextStyle({ + color: 'rgb(255, 255, 255)', + }), + }, +}; + +interface IProps { + onToggle?: (isOpen: boolean) => void; + defaultOpen?: boolean; + children: string; + style?: Types.ViewStyleRuleSet | Types.ViewStyleRuleSet[]; +} + +interface IState { + isHovered: boolean; + isOpen: boolean; +} + +export default class ConnectionInfoDisclosure extends Component<IProps, IState> { + constructor(props: IProps) { + super(props); + + this.state = { + isHovered: false, + isOpen: props.defaultOpen === true, + }; + } + + public render() { + const tintColor = this.state.isHovered ? 'rgb(255, 255, 255)' : 'rgb(255, 255, 255, 0.4)'; + + return ( + <View + style={[styles.container, this.props.style]} + onMouseEnter={this.onMouseEnter} + onMouseLeave={this.onMouseLeave} + onPress={this.onToggle}> + <Text + style={[styles.caption.base, this.state.isHovered ? styles.caption.hovered : undefined]}> + {this.props.children} + </Text> + <ImageView + source={this.state.isOpen ? 'icon-chevron-up' : 'icon-chevron-down'} + width={24} + height={24} + tintColor={tintColor} + /> + </View> + ); + } + + private onMouseEnter = () => { + this.setState({ isHovered: true }); + }; + + private onMouseLeave = () => { + this.setState({ isHovered: false }); + }; + + private onToggle = () => { + this.setState( + (state) => ({ + ...state, + isOpen: !state.isOpen, + }), + () => { + if (this.props.onToggle) { + this.props.onToggle(this.state.isOpen); + } + }, + ); + }; +} diff --git a/gui/packages/components/src/ImageView.tsx b/gui/packages/components/src/ImageView.tsx index 9602130a63..d05c72dba7 100644 --- a/gui/packages/components/src/ImageView.tsx +++ b/gui/packages/components/src/ImageView.tsx @@ -7,7 +7,7 @@ interface IProps { height?: number; tintColor?: string; tintHoverColor?: string; - style?: Types.ViewStyleRuleSet; + style?: Types.ViewStyleRuleSet | Types.ViewStyleRuleSet[]; disabled?: boolean; } |
