Skip to content

Commit 80c1bc9

Browse files
authored
Multiple Views (codesandbox#688)
* Allow multiple views * Give embed default views * Clean syntax
1 parent 4e4c30e commit 80c1bc9

File tree

25 files changed

+357
-106
lines changed

25 files changed

+357
-106
lines changed

packages/app/src/app/components/Preview/DevTools/Console/index.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ class Console extends React.Component {
9696
};
9797

9898
addMessage(message, args, type) {
99-
this.props.updateStatus(this.getType(message));
99+
if (this.props.updateStatus) {
100+
this.props.updateStatus(this.getType(message));
101+
}
100102

101103
this.setState({
102104
messages: [
@@ -119,7 +121,9 @@ class Console extends React.Component {
119121
}
120122

121123
clearConsole = () => {
122-
this.props.updateStatus('clear');
124+
if (this.props.updateStatus) {
125+
this.props.updateStatus('clear');
126+
}
123127
this.setState({ messages: [] });
124128
};
125129

packages/app/src/app/components/Preview/DevTools/Tests/index.js

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ export type Status = 'idle' | 'running' | 'pass' | 'fail';
2424
type Props = {
2525
hidden: boolean,
2626
sandboxId: string,
27-
updateStatus: (
27+
standalone?: boolean,
28+
updateStatus?: (
2829
type: 'success' | 'warning' | 'error' | 'info' | 'clear',
2930
count?: number
3031
) => void,
@@ -86,6 +87,10 @@ class Tests extends React.Component<Props, State> {
8687

8788
componentDidMount() {
8889
this.listener = listen(this.handleMessage);
90+
91+
if (this.props.standalone) {
92+
this.runAllTests();
93+
}
8994
}
9095

9196
componentWillUnmount() {
@@ -116,13 +121,17 @@ class Tests extends React.Component<Props, State> {
116121
switch (data.event) {
117122
case 'initialize_tests': {
118123
this.currentDescribeBlocks = [];
119-
this.props.updateStatus('clear');
124+
if (this.props.updateStatus) {
125+
this.props.updateStatus('clear');
126+
}
120127
this.setState(INITIAL_STATE);
121128
break;
122129
}
123130
case 'total_test_start': {
124131
this.currentDescribeBlocks = [];
125-
this.props.updateStatus('clear');
132+
if (this.props.updateStatus) {
133+
this.props.updateStatus('clear');
134+
}
126135
this.setState({
127136
...this.state,
128137
running: true,
@@ -143,13 +152,15 @@ class Tests extends React.Component<Props, State> {
143152
f => this.getStatus(this.state.files[f]) === 'pass'
144153
).length;
145154

146-
if (failingTests > 0) {
147-
this.props.updateStatus('error', failingTests);
148-
} else if (passingTests === files.length) {
149-
this.props.updateStatus('success', passingTests);
150-
} else {
151-
// Not all tests are run
152-
this.props.updateStatus('warning', files.length - passingTests);
155+
if (this.props.updateStatus) {
156+
if (failingTests > 0) {
157+
this.props.updateStatus('error', failingTests);
158+
} else if (passingTests === files.length) {
159+
this.props.updateStatus('success', passingTests);
160+
} else {
161+
// Not all tests are run
162+
this.props.updateStatus('warning', files.length - passingTests);
163+
}
153164
}
154165

155166
break;

packages/app/src/app/components/Preview/DevTools/elements.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ export const Container = styled.div`
44
display: flex;
55
flex-direction: column;
66
width: 100%;
7+
8+
max-height: 100%;
79
z-index: 100;
810
background-color: ${props => props.theme.background4};
911
`;

packages/app/src/app/components/Preview/DevTools/index.js

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ type Props = {
5353
shouldExpandDevTools?: boolean,
5454
devToolsOpen?: boolean,
5555
setDevToolsOpen?: (open: boolean) => void,
56+
view?: 'browser' | 'console' | 'tests',
5657
};
5758
type State = {
5859
status: { [title: string]: ?Status },
@@ -65,18 +66,33 @@ type State = {
6566
};
6667

6768
export default class DevTools extends React.PureComponent<Props, State> {
68-
state = {
69-
status: {},
70-
currentPane: PANES[Object.keys(PANES)[0]].title,
69+
constructor(props: Props) {
70+
super(props);
7171

72-
mouseDown: false,
73-
startY: 0,
74-
startHeight: 0,
72+
const hasView = props.view && props.view !== 'browser';
7573

76-
hidden: true,
74+
let currentPane = PANES[Object.keys(PANES)[0]].title;
75+
if (hasView) {
76+
if (props.view === 'tests') {
77+
currentPane = tests.title;
78+
} else if (props.view === 'console') {
79+
currentPane = console.title;
80+
}
81+
}
7782

78-
height: 2 * 16,
79-
};
83+
this.state = {
84+
status: {},
85+
currentPane,
86+
87+
mouseDown: false,
88+
startY: 0,
89+
startHeight: 0,
90+
91+
hidden: !hasView,
92+
93+
height: hasView ? 5000 : 2 * 16,
94+
};
95+
}
8096

8197
componentWillReceiveProps(nextProps: Props) {
8298
if (nextProps.sandboxId !== this.props.sandboxId) {
@@ -316,7 +332,6 @@ export default class DevTools extends React.PureComponent<Props, State> {
316332
}}
317333
style={{
318334
height,
319-
minHeight: height,
320335
position: 'relative',
321336
display: 'flex',
322337
}}

packages/app/src/app/components/Preview/Navigator/HorizontalAlign.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import React from 'react';
22
import IconBase from 'react-icons/lib/IconBase';
33

4-
export default () => (
4+
export default props => (
55
<IconBase
66
width="1em"
77
height="1em"
88
viewBox="0 0 16 16"
99
version="1.1"
1010
xmlnsXlink="http://www.w3.org/1999/xlink"
11+
{...props}
1112
>
1213
<path
1314
d="M2.25 8.75v-1.5h11.5v1.5H2.25zm1.25-1.5v5.25h9V7.25h-9zM3 2h10a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1z"

packages/app/src/app/components/Preview/Navigator/VerticalAlign.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import React from 'react';
22
import IconBase from 'react-icons/lib/IconBase';
33

4-
export default () => (
4+
export default props => (
55
<IconBase
66
width="1em"
77
height="1em"
88
viewBox="0 0 16 16"
99
version="1.1"
1010
xmlnsXlink="http://www.w3.org/1999/xlink"
11+
{...props}
1112
>
1213
<path
1314
d="M7.25 2.735h1.5V12.75h-1.5V2.735zm0 .765v9h5.25v-9H7.25zM3 2h10a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1z"

packages/app/src/app/components/Preview/Navigator/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ function Navigator({
3434
alignBottom,
3535
}) {
3636
return (
37-
<Container>
37+
<Container className="flying-container-handler" style={{ cursor: 'move' }}>
3838
<Icons>
3939
<Icon disabled={!onBack} onClick={onBack}>
4040
<LeftIcon />

packages/app/src/app/components/Preview/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type Props = {
3232
inactive?: boolean,
3333
dragging?: boolean,
3434
hide: boolean,
35+
noPreview: boolean,
3536
};
3637

3738
type State = {
@@ -317,16 +318,18 @@ class BasePreview extends React.Component<Props, State> {
317318
isInProjectView,
318319
dragging,
319320
hide,
321+
noPreview,
320322
} = this.props;
321323
const { historyPosition, history, urlInAddressBar } = this.state;
322324
const url = urlInAddressBar || frameUrl(sandbox.id);
323325

324-
if (hide) {
326+
if (noPreview) {
327+
// Means that preview is open in another tab definitely
325328
return null;
326329
}
327330

328331
return (
329-
<Container style={{ flex: 1 }}>
332+
<Container style={{ flex: 1, display: hide ? 'none' : undefined }}>
330333
{showNavigation && (
331334
<Navigator
332335
url={decodeURIComponent(url)}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from 'react';
2+
import Console from 'app/components/Preview/DevTools/Console';
3+
4+
import Navigator from './Navigator';
5+
6+
export default ({ alignRight, alignBottom }) => (
7+
<div style={{ height: '100%' }}>
8+
<Navigator
9+
alignRight={alignRight}
10+
alignBottom={alignBottom}
11+
title="Console"
12+
/>
13+
<Console.Content />
14+
</div>
15+
);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
4+
import VerticalAlign from 'app/src/app/components/Preview/Navigator/VerticalAlign';
5+
import HorizontalAlign from 'app/src/app/components/Preview/Navigator/HorizontalAlign';
6+
7+
const Container = styled.div`
8+
display: flex;
9+
align-items: center;
10+
padding: 0.5rem 1rem;
11+
12+
width: 100%;
13+
14+
background-color: ${props => props.theme.background4};
15+
16+
cursor: move;
17+
box-sizing: border-box;
18+
19+
color: rgba(255, 255, 255, 0.7);
20+
font-weight: 600;
21+
`;
22+
23+
const Title = styled.div`
24+
flex: 1;
25+
`;
26+
27+
const Icons = styled.div`
28+
z-index: 20;
29+
svg {
30+
transition: 0.3s ease color;
31+
margin-left: 0.5rem;
32+
cursor: pointer;
33+
34+
&:hover {
35+
color: white;
36+
}
37+
}
38+
`;
39+
40+
export default ({ title, alignBottom, alignRight }) => (
41+
<Container className="flying-container-handler">
42+
<Title>{title}</Title>
43+
<Icons>
44+
<HorizontalAlign onClick={alignBottom} />
45+
<VerticalAlign onClick={alignRight} />
46+
</Icons>
47+
</Container>
48+
);

0 commit comments

Comments
 (0)