beautified devtools look and removed lodash.assign as dep

This commit is contained in:
dzannotti 2015-08-07 16:20:13 +01:00
parent 669b1be808
commit 50212f88a0
10 changed files with 206 additions and 109 deletions

View File

@ -47,7 +47,6 @@
"redux": "^1.0.0 || 1.0.0-rc"
},
"dependencies": {
"lodash.assign": "^3.2.0",
"react-mixin": "^1.7.0",
"react-redux": "^0.2.2",
"redux": "^1.0.0-rc"

View File

@ -13,9 +13,9 @@ export function getDefaultStyle(props) {
position: 'fixed',
zIndex: 999,
fontSize: 17,
overflow: 'auto',
overflow: 'hidden',
opacity: 0.92,
background: 'black',
background: '#181d20',
color: 'white',
left: left ? 0 : undefined,
right: right ? 0 : undefined,
@ -23,7 +23,9 @@ export function getDefaultStyle(props) {
bottom: bottom ? 0 : undefined,
maxHeight: (bottom && top) ? '100%' : '20%',
maxWidth: (left && right) ? '100%' : '20%',
wordWrap: 'break-word'
minWidth: 260,
wordWrap: 'break-word',
boxSizing: 'border-box'
};
}

View File

@ -3,7 +3,6 @@ import reactMixin from 'react-mixin';
import { ExpandedStateHandlerMixin } from './mixins';
import JSONArrow from './JSONArrow';
import grabNode from './grab-node';
import assign from 'lodash.assign';
const styles = {
base: {
@ -90,8 +89,14 @@ export default class JSONArrayNode extends React.Component {
listStyle: 'none',
display: (this.state.expanded) ? 'block' : 'none'
};
let containerStyle = assign({}, styles.base, styles.parentNode);
let spanStyle = assign({}, styles.span, this.state.expanded ? styles.spanExpanded : {});
let containerStyle = {...styles.base, ...styles.parentNode};
let spanStyle = { ...styles.span };
if (this.state.expanded) {
spanStyle = {
...spanStyle,
...styles.spanExpanded
};
}
return (
<li style={containerStyle} onClick={::this.handleClick}>
<JSONArrow open={this.state.expanded}/>

View File

@ -1,5 +1,4 @@
import React from 'react';
import assign from 'lodash.assign';
const styles = {
base: {
@ -26,7 +25,13 @@ const styles = {
export default class JSONArrow extends React.Component {
render() {
const style = assign({}, styles.base, this.props.open ? styles.open : {});
let style = { ...styles.base };
if (this.props.open) {
style = {
...style,
...styles.open
};
}
return <div style={style}/>;
}
}

View File

@ -2,7 +2,6 @@ import React from 'react';
import reactMixin from 'react-mixin';
import { ExpandedStateHandlerMixin } from './mixins';
import JSONArrow from './JSONArrow';
import assign from 'lodash.assign';
import grabNode from './grab-node';
const styles = {
@ -92,8 +91,14 @@ export default class JSONObjectNode extends React.Component {
listStyle: 'none',
display: (this.state.expanded) ? 'block' : 'none'
};
let containerStyle = assign({}, styles.base, styles.parentNode);
let spanStyle = assign({}, styles.span, this.state.expanded ? styles.spanExpanded : {});
let containerStyle = {...styles.base, ...styles.parentNode};
let spanStyle = { ...styles.span };
if (this.state.expanded) {
spanStyle = {
...spanStyle,
...styles.spanExpanded
};
}
return (
<li style={containerStyle} onClick={::this.handleClick}>
<JSONArrow open={this.state.expanded}/>

View File

@ -13,9 +13,9 @@ const styles = {
border: 0,
padding: 0,
margin: 0,
fontSize: 14,
fontSize: '0.90em',
listStyle: 'none',
fontFamily: '"Helvetica Neue", Helvetica, Arial, freesans, sans-serif',
fontFamily: 'monospace',
MozUserSelect: 'none',
WebkitUserSelect: 'none'
}
@ -36,10 +36,11 @@ export default class JSONTree extends React.Component {
render() {
const nodeType = objectType(this.props.data);
let rootNode = false;
const keyName = this.props.keyName || 'root';
if (nodeType === 'Object') {
rootNode = <JSONObjectNode data={this.props.data} keyName="(root)" initialExpanded={true} />;
rootNode = <JSONObjectNode data={this.props.data} keyName={keyName} initialExpanded={true} />;
} else if (nodeType === 'Array') {
rootNode = <JSONArrayNode data={this.props.data} initialExpanded={true} keyName="(root)" />;
rootNode = <JSONArrayNode data={this.props.data} initialExpanded={true} keyName={keyName} />;
}
return (
<ul style={styles.tree}>

View File

@ -1,5 +1,28 @@
import React, { PropTypes, findDOMNode } from 'react';
import LogMonitorEntry from './LogMonitorEntry';
import LogMonitorButton from './LogMonitorButton';
const styles = {
container: {
fontFamily: 'monospace',
position: 'relative',
overflowY: 'hidden'
},
buttonBarWrapper: {
backgroundColor: '#343c45',
borderBottom: '1px solid #3f464d',
marginBottom: 1
},
buttonBar: {
paddingLeft: 2
},
bordering: {
'float': 'left',
height: 1,
border: '1px solid #20262c',
width: '100%'
}
}
export default class LogMonitor {
constructor() {
@ -24,11 +47,11 @@ export default class LogMonitor {
static defaultProps = {
select: (state) => state,
monitorState: { isVisible: true }
monitorState: { isVisible: true },
};
componentWillReceiveProps(nextProps) {
const node = findDOMNode(this);
const node = findDOMNode(this.refs.elements);
if (!node) {
this.scrollDown = true;
} else if (
@ -46,7 +69,7 @@ export default class LogMonitor {
}
componentDidUpdate() {
const node = findDOMNode(this);
const node = findDOMNode(this.refs.elements);
if (!node) {
return;
}
@ -95,7 +118,6 @@ export default class LogMonitor {
render() {
const elements = [];
const { monitorState, skippedActions, stagedActions, computedStates, select } = this.props;
if (!monitorState.isVisible) {
return null;
}
@ -117,52 +139,26 @@ export default class LogMonitor {
}
return (
<div style={{
fontFamily: 'monospace',
position: 'relative',
padding: '1rem'
}}>
<div>
<div style={{
paddingBottom: '.5rem'
}}>
<small>Press Ctrl+H to hide.</small>
</div>
<div>
<a onClick={::this.handleReset}
style={{ textDecoration: 'underline', cursor: 'hand' }}>
<small>Reset</small>
</a>
<div style={styles.container}>
<div style={styles.buttonBarWrapper}>
<div style={styles.buttonBar}>
<LogMonitorButton onClick={::this.handleReset}>Reset</LogMonitorButton>
{computedStates.length > 1 &&
<LogMonitorButton onClick={::this.handleRollback}>Revert</LogMonitorButton>
}
{Object.keys(skippedActions).some(key => skippedActions[key]) &&
<LogMonitorButton onClick={::this.handleSweep}>Sweep</LogMonitorButton>
}
{computedStates.length > 1 &&
<LogMonitorButton onClick={::this.handleCommit}>Commit</LogMonitorButton>
}
</div>
</div>
{elements}
<div>
{computedStates.length > 1 &&
<a onClick={::this.handleRollback}
style={{ textDecoration: 'underline', cursor: 'pointer' }}>
Rollback
</a>
}
{Object.keys(skippedActions).some(key => skippedActions[key]) &&
<span>
{' • '}
<a onClick={::this.handleSweep}
style={{ textDecoration: 'underline', cursor: 'pointer' }}>
Sweep
</a>
</span>
}
{computedStates.length > 1 &&
<span>
<span>
{' • '}
</span>
<a onClick={::this.handleCommit}
style={{ textDecoration: 'underline', cursor: 'pointer' }}>
Commit
</a>
</span>
}
<div styles={{
overflowX: 'hidden',
overflowY: 'auto'
}} ref="elements">
{elements}
</div>
</div>
);

View File

@ -0,0 +1,63 @@
import React from 'react';
const styles = {
base: {
paddingTop: 3,
paddingBottom: 3,
paddingLeft: 6,
paddingRight: 6,
marginTop: 2,
display: 'inline-block',
fontSize: "0.8em"
},
active: {
backgroundColor: "#252c33"
}
}
export default class LogMonitorButton extends React.Component {
constructor(props) {
super(props);
this.state = {
hovered: false,
active: false
}
}
handleMouseEnter() {
this.setState({ hovered: true });
}
handleMouseLeave() {
this.setState({ hovered: false });
}
handleMouseDown() {
this.setState({ active: true });
}
handleMouseUp() {
this.setState({ active: false });
}
render() {
let style = {
...styles.base,
};
if (this.state.hovered) {
style = {
...style,
...styles.active
};
}
return (
<a onMouseEnter={::this.handleMouseEnter}
onMouseLeave={::this.handleMouseLeave}
onMouseDown={::this.handleMouseDown}
onMouseUp={::this.handleMouseUp}
style={style} onClick={this.props.onClick}>
{this.props.children}
</a>
);
}
}

View File

@ -1,5 +1,6 @@
import React, { PropTypes } from 'react';
import JSONTree from './JSONTree';
import LogMonitorEntryAction from "./LogMonitorEntryAction";
function hsvToRgb(h, s, v) {
const i = Math.floor(h);
@ -35,6 +36,13 @@ function colorFromString(token) {
return hsvToRgb(h, s, v);
}
const styles = {
entry: {
display: 'block',
WebkitUserSelect: 'none'
}
};
export default class LogMonitorEntry {
static propTypes = {
index: PropTypes.number.isRequired,
@ -50,14 +58,14 @@ export default class LogMonitorEntry {
let errorText = error;
if (!errorText) {
try {
return <JSONTree data={this.props.select(state)} />
return <JSONTree keyName={'state'} data={this.props.select(state)} />
} catch (err) {
errorText = 'Error selecting state.';
}
}
return (
<span style={{
paddingLeft: 15,
fontStyle: 'italic'
}}>
({errorText})
@ -73,49 +81,24 @@ export default class LogMonitorEntry {
}
render() {
const { index, error, action, state, collapsed } = this.props;
const { r, g, b } = colorFromString(action.type);
return (
<div style={{
textDecoration: collapsed ? 'line-through' : 'none'
}}>
<a onClick={::this.handleActionClick}
style={{
opacity: collapsed ? 0.5 : 1,
marginTop: '1em',
display: 'block',
paddingBottom: '1em',
paddingTop: '1em',
color: `rgb(${r}, ${g}, ${b})`,
cursor: (index > 0) ? 'pointer' : 'default',
WebkitUserSelect: 'none'
}}>
{JSON.stringify(action)}
</a>
{!collapsed &&
<p style={{
textAlign: 'center',
transform: 'rotate(180deg)'
}}>
</p>
}
{!collapsed &&
<div style={{
paddingBottom: '1em',
paddingTop: '1em',
color: 'lightyellow'
}}>
{this.printState(state, error)}
</div>
}
<hr style={{
marginBottom: '2em'
}} />
const { index, error, action, state, collapsed } = this.props;
const { r, g, b } = colorFromString(action.type);
const styleEntry = {
opacity: collapsed ? 0.5 : 1,
color: `rgb(${r}, ${g}, ${b})`,
cursor: (index > 0) ? 'pointer' : 'default'
};
return (
<div style={{textDecoration: collapsed ? 'line-through' : 'none'}}>
<LogMonitorEntryAction collapsed={collapsed} action={action} onClick={::this.handleActionClick} style={{...styles.entry, ...styleEntry}}/>
{!collapsed &&
<div style={{
borderBottom: '1px solid #20262c',
paddingLeft: 15
}}>
{this.printState(state, error)}
</div>
}
</div>
);
}

View File

@ -0,0 +1,38 @@
import React from "react";
import JSONTree from './JSONTree';
const styles = {
wrapper: {
backgroundColor: '#343c45',
borderTop: '1px solid #3f464d',
borderBottom: '1px solid #3f464d'
},
actionBar: {
paddingTop: 4,
paddingBottom: 4,
paddingLeft: 10,
marginBottom: 1
},
payload: {
backgroundColor: '#252c33',
paddingLeft: 15
}
}
export default class LogMonitorAction extends React.Component {
renderPayload(payload) {
return (
<div style={styles.payload}>
{ Object.keys(payload).length > 0 ? <JSONTree keyName={'payload'} data={payload}/> : "" }
</div>
);
}
render() {
const { type, ...payload } = this.props.action;
return (
<div style={{...styles.wrapper, ...this.props.style}} onClick={this.props.onClick}>
<div style={styles.actionBar}>{type}</div>
{!this.props.collapsed ? '' : ''}
</div>
);
}
}