Skip to content

Commit 80e17c4

Browse files
authored
Ivh/add/rewrite browser (#1)
* Rewrite logic behind the view * Styling tweaks * Code editor header
1 parent 5fab8ad commit 80e17c4

File tree

22 files changed

+503
-84
lines changed

22 files changed

+503
-84
lines changed

config/webpack.config.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ const config = {
5454

5555
target: 'web',
5656

57-
mainFields: ['browser', 'module', 'jsnext:main', 'main'],
5857

5958
output: getOutput(),
6059

@@ -138,11 +137,16 @@ const config = {
138137
],
139138
},
140139
resolve: {
140+
mainFields: ['browser', 'module', 'jsnext:main', 'main'],
141141
modules: [
142142
'node_modules',
143143
],
144144

145145
extensions: ['.js', '.json'],
146+
147+
alias: {
148+
moment: 'moment/moment.js',
149+
},
146150
},
147151

148152
plugins: [

src/app/components/buttons/Button.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const styles = props => `
66
transition: 0.3s ease all;
77
text-transform: uppercase;
88
text-decoration: none;
9+
line-height: 1;
910
background-color: ${props.disabled ? props.theme.background2.darken(0.1)() : props.theme.secondary()};
1011
color: ${props.disabled ? props.theme.background2.lighten(1.5)() : 'white'};
1112
${(() => {

src/app/pages/SandboxView/Editor/Content/View/EditorPreview.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type { ModuleTab } from '../../../../../store/reducers/views/sandbox';
1313
import CodeEditor from './subviews/CodeEditor';
1414
import Preview from './subviews/Preview';
1515
import { directoriesBySandboxSelector } from '../../../../../store/entities/directories/selector';
16-
import { modulesBySandboxSelector, singleModuleSelector } from '../../../../../store/entities/modules/selector';
16+
import { modulesBySandboxSelector, singleModuleSelector, modulePathSelector } from '../../../../../store/entities/modules/selector';
1717
import { singleSourceSelector } from '../../../../../store/entities/sources/selector';
1818

1919
import type { Sandbox } from '../../../../../store/entities/sandboxes/index';
@@ -33,6 +33,7 @@ type Props = {
3333
sandbox: ?Sandbox;
3434
moduleActions: moduleEntity.actions;
3535
sourceActions: sourceEntity.actions;
36+
modulePath: ?string;
3637
};
3738

3839
type State = {
@@ -51,6 +52,7 @@ const mapStateToProps = (state, props) => ({
5152
boilerplates: boilerplatesBySandboxSelector(state, { id: props.sandbox.id }),
5253
module: singleModuleSelector(state, { id: props.tab ? props.tab.moduleId : null }),
5354
source: singleSourceSelector(state, { id: props.sandbox.source }),
55+
modulePath: modulePathSelector(state, { id: props.tab ? props.tab.moduleId : null }),
5456
});
5557
const mapDispatchToProps = dispatch => ({
5658
moduleActions: bindActionCreators(moduleEntity.actions, dispatch),
@@ -67,9 +69,17 @@ class EditorPreview extends React.PureComponent {
6769
startResizing = () => this.setState({ resizing: true });
6870
stopResizing = () => this.setState({ resizing: false });
6971

72+
saveCode = () => {
73+
const { module, moduleActions } = this.props;
74+
75+
if (module == null) return;
76+
77+
moduleActions.saveCode(module.id);
78+
};
79+
7080
render() {
7181
const { source, modules, directories, boilerplates,
72-
moduleActions, module, sourceActions } = this.props;
82+
moduleActions, module, sourceActions, modulePath } = this.props;
7383

7484
if (module == null || source == null) return null;
7585
return (
@@ -81,15 +91,18 @@ class EditorPreview extends React.PureComponent {
8191
defaultSize="50%"
8292
minSize={360}
8393
primary="second"
84-
paneStyle={{ height: 'calc(100% - 35px)' }}
94+
paneStyle={{ height: '100%' }}
8595
>
8696
<FullSize>
8797
<CodeEditor
8898
changeCode={moduleActions.changeCode}
8999
id={module.id}
90100
error={module.error}
91101
code={module.code}
92-
saveCode={moduleActions.saveCode}
102+
saveCode={this.saveCode}
103+
title={module.title}
104+
modulePath={modulePath}
105+
canSave={module.isNotSynced}
93106
/>
94107
</FullSize>
95108
<FullSize inactive={this.state.resizing}>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
4+
import SaveIcon from 'react-icons/lib/md/save';
5+
import Button from '../../../../../../../components/buttons/Button';
6+
7+
const Container = styled.div`
8+
display: flex;
9+
background-color: ${props => props.theme.background};
10+
box-shadow: 0 3px 3px ${props => props.theme.background2};
11+
color: ${props => props.theme.white};
12+
padding: 0.5rem 1rem;
13+
height: 3rem;
14+
box-sizing: border-box;
15+
justify-content: space-between;
16+
vertical-align: middle;
17+
align-items: center;
18+
`;
19+
20+
const Path = styled.span`
21+
color: ${props => props.theme.background.lighten(1.25)};
22+
padding-right: 0.1rem;
23+
`;
24+
25+
26+
type Props = {
27+
title: string;
28+
path: string;
29+
saveComponent?: () => void;
30+
};
31+
32+
export default ({ path, title, saveComponent }: Props) => (
33+
<Container>
34+
35+
<div>
36+
<Path>{path}</Path>
37+
{title}
38+
</div>
39+
40+
<Button disabled={!saveComponent} onClick={saveComponent} small>
41+
<SaveIcon />
42+
&nbsp;Save
43+
</Button>
44+
</Container>
45+
);

src/app/pages/SandboxView/Editor/Content/View/subviews/CodeEditor.js renamed to src/app/pages/SandboxView/Editor/Content/View/subviews/CodeEditor/index.js

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@ import 'codemirror/addon/fold/foldcode';
1717
import 'codemirror/addon/fold/foldgutter';
1818
import 'codemirror/addon/fold/brace-fold';
1919

20-
import theme from '../../../../../../../common/theme';
20+
import theme from '../../../../../../../../common/theme';
21+
import Header from './Header';
2122

2223
const documentCache = {};
2324

2425
type Props = {
2526
code: ?string;
2627
error: ?Object;
2728
id: string;
29+
title: string;
30+
modulePath: string;
2831
changeCode: (id: string, code: string) => void;
29-
saveCode: (id: string) => void;
32+
saveCode: () => void;
33+
canSave: boolean;
3034
};
3135

3236
const Container = styled.div`
@@ -54,14 +58,6 @@ const ErrorMessage = styled.div`
5458
color: ${props => props.theme.red};
5559
`;
5660

57-
const TopMessage = styled.div`
58-
flex: 0 0 auto;
59-
padding: 0.5rem 1rem;
60-
font-size: 14px;
61-
color: ${props => props.theme.background.lighten(1.5)};
62-
vertical-align: middle;
63-
`;
64-
6561
const handleError = (cm, currentError, nextError, nextCode, nextId) => {
6662
if (currentError || nextError) {
6763
if (currentError && nextError &&
@@ -97,8 +93,7 @@ export default class CodeEditor extends React.PureComponent {
9793
window.addEventListener('keydown', (event: KeyboardEvent) => {
9894
if (event.ctrlKey || event.metaKey) {
9995
if (event.key === 's' || event.keyCode === 83) {
100-
const { id } = this.props;
101-
this.props.saveCode(id);
96+
this.props.saveCode();
10297
event.preventDefault();
10398
return false;
10499
}
@@ -108,7 +103,9 @@ export default class CodeEditor extends React.PureComponent {
108103
}
109104

110105
shouldComponentUpdate(nextProps: Props) {
111-
return nextProps.id !== this.props.id || nextProps.error !== this.props.error;
106+
return nextProps.id !== this.props.id ||
107+
nextProps.error !== this.props.error ||
108+
this.props.canSave !== nextProps.canSave;
112109
}
113110

114111
componentWillReceiveProps(nextProps: Props) {
@@ -170,15 +167,10 @@ export default class CodeEditor extends React.PureComponent {
170167
codemirror: typeof CodeMirror;
171168

172169
render() {
173-
const { error } = this.props;
170+
const { error, title, saveCode, canSave, modulePath } = this.props;
174171
return (
175172
<Container>
176-
<TopMessage>
177-
<SaveIcon />
178-
<span style={{ verticalAlign: 'middle', marginLeft: '0.5rem' }}>
179-
Last update: 5 seconds ago
180-
</span>
181-
</TopMessage>
173+
<Header saveComponent={canSave && saveCode} title={title} path={modulePath} />
182174
<CodeContainer>
183175
<div style={{ height: '100%' }} ref={this.getCodeMirror} />
184176
</CodeContainer>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
import theme from '../../../../../../../../common/theme';
4+
5+
const TEXT_COLOR = theme.gray.darken(0.2)();
6+
7+
const Container = styled.div`
8+
position: relative;
9+
color: ${TEXT_COLOR};
10+
vertical-align: middle;
11+
`;
12+
13+
const Input = styled.input`
14+
padding: 0.2rem 1rem;
15+
color: ${TEXT_COLOR};
16+
width: 100%;
17+
box-sizing: border-box;
18+
`;
19+
20+
const Slash = styled.span`
21+
position: absolute;
22+
padding: 0.3rem 0.75rem;
23+
top: 0;
24+
bottom: 0;
25+
left: 0;
26+
vertical-align: middle;
27+
line-height: 1.15;
28+
`;
29+
30+
type Props = {
31+
url: string;
32+
onChange: (url: string) => void;
33+
onConfirm: () => void;
34+
};
35+
36+
export default class extends React.PureComponent {
37+
props: Props;
38+
39+
onChange = (evt) => {
40+
const { onChange } = this.props;
41+
42+
onChange(evt.target.value);
43+
};
44+
45+
handleKeyDown = (e) => {
46+
const { onConfirm } = this.props;
47+
48+
if (e.keyCode === 13) {
49+
// Enter
50+
onConfirm();
51+
}
52+
}
53+
54+
render() {
55+
const { url = '' } = this.props;
56+
return (
57+
<Container>
58+
<Slash>/</Slash>
59+
<Input onChange={this.onChange} onKeyDown={this.handleKeyDown} value={url} />
60+
</Container>
61+
);
62+
}
63+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
4+
import LeftIcon from 'react-icons/lib/fa/angle-left';
5+
import RightIcon from 'react-icons/lib/fa/angle-right';
6+
import RefreshIcon from 'react-icons/lib/md/refresh';
7+
8+
import AddressBar from './AddressBar';
9+
import Switch from './Switch';
10+
11+
const Container = styled.div`
12+
display: flex;
13+
background-color: #f2f2f2;
14+
padding: 0.5rem;
15+
align-items: center;
16+
line-height: 1;
17+
box-shadow: 0 1px 3px #ddd;
18+
`;
19+
20+
const Icons = styled.div`
21+
display: flex;
22+
`;
23+
24+
const Icon = styled.div`
25+
display: inline-block;
26+
color: ${props => (props.disabled ? props.theme.gray : props.theme.gray.darken(0.3))};
27+
font-size: 1.5rem;
28+
line-height: 0.5;
29+
margin: 0 0.1rem;
30+
vertical-align: middle;
31+
text-align: center;
32+
33+
${props => !props.disabled && `
34+
&:hover {
35+
background-color: #e2e2e2;
36+
cursor: pointer;
37+
}`}
38+
`;
39+
40+
const AddressBarContainer = styled.div`
41+
width: 100%;
42+
box-sizing: border-box;
43+
margin: 0 0.5rem;
44+
`;
45+
46+
type Props = {
47+
url: string,
48+
onChange: (text: string) => void;
49+
onConfirm: () => void;
50+
onBack?: () => void;
51+
onForward?: () => void;
52+
onRefresh?: () => void;
53+
isProjectView: boolean;
54+
toggleProjectView: () => void;
55+
};
56+
57+
export default ({
58+
url,
59+
onChange,
60+
onConfirm,
61+
onBack,
62+
onForward,
63+
onRefresh,
64+
isProjectView,
65+
toggleProjectView,
66+
}: Props) => (
67+
<Container>
68+
<Icons>
69+
<Icon disabled={!onBack} onClick={onBack}><LeftIcon /></Icon>
70+
<Icon disabled={!onForward} onClick={onForward}><RightIcon /></Icon>
71+
<Icon onClick={onRefresh}><RefreshIcon /></Icon>
72+
</Icons>
73+
<AddressBarContainer>
74+
<AddressBar url={url} onChange={onChange} onConfirm={onConfirm} />
75+
</AddressBarContainer>
76+
<Switch right={isProjectView} onClick={toggleProjectView} />
77+
</Container>
78+
);

0 commit comments

Comments
 (0)