Skip to content

Commit a135fcb

Browse files
tansongyangCompuIves
authored andcommitted
Add dependencies using modal (#254)
* Open a stub search box on "Add Dependency" click * Connect to yarn's npm index * Add click handler to hits * Control InstantSearch * Populate version dropdown on select * Add dependency on confirm * Add search box autofocus * Styled left side of dependency search results * Move pr/108 files to new locations * Format download count * Limit hits per page * Add GitHub link * Add homepage link (and tooltips) * Add version select * Style dependency search box * Make lines between dependencies softer * Include version in DependencyHit onClick * Support "Enter" click on DependencyHit * Restore add dependency functionality * Use codesandbox API key for Algolia search * Use Downshift for hit list * Refactor to remove unnecesary array * Style search box * Focus search box * Add pagination controls * Move pagination under search bar Makes controls always in the same place even when list grows/shrinks * Add to contributors * Fix lint errors * Clean code * Extract formatDownloads into own file. * Reorder SearchDependencies so that the main content comes first. * Re-add to contributors
1 parent 985a713 commit a135fcb

File tree

8 files changed

+346
-61
lines changed

8 files changed

+346
-61
lines changed

.all-contributorsrc

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,8 @@
198198
"bug",
199199
"code"
200200
]
201-
}, {
201+
},
202+
{
202203
"login": "duivvv",
203204
"name": "Geoffrey Dhuyvetters",
204205
"avatar_url": "https://avatars3.githubusercontent.com/u/89046?v=4",
@@ -217,6 +218,15 @@
217218
"code",
218219
"infra"
219220
]
221+
},
222+
{
223+
"login": "tansongyang",
224+
"name": "Frank Tan",
225+
"avatar_url": "https://avatars3.githubusercontent.com/u/9488719?v=4",
226+
"profile": "https://github.com/tansongyang",
227+
"contributions": [
228+
"code"
229+
]
220230
}
221231
]
222232
}

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# [CodeSandbox](https://codesandbox.io) [![Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/KE3TbEZ) [![All Contributors](https://img.shields.io/badge/all_contributors-21-orange.svg?style=flat-square)](#contributors) [![Build Status](https://travis-ci.org/CompuIves/codesandbox-client.svg?branch=master)](https://travis-ci.org/CompuIves/codesandbox-client) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) [![first-timers-only Friendly](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](http://www.firsttimersonly.com/)
1+
# [CodeSandbox](https://codesandbox.io) [![Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/KE3TbEZ) [![All Contributors](https://img.shields.io/badge/all_contributors-22-orange.svg?style=flat-square)](#contributors) [![Build Status](https://travis-ci.org/CompuIves/codesandbox-client.svg?branch=master)](https://travis-ci.org/CompuIves/codesandbox-client) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) [![first-timers-only Friendly](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](http://www.firsttimersonly.com/)
22

33
An online code editor tailored for web applications.
44

@@ -36,9 +36,9 @@ Thanks goes to these wonderful people
3636
([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):
3737

3838
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
39-
<!-- prettier-ignore -->
4039
| [<img src="https://avatars0.githubusercontent.com/u/587016?v=3" width="100px;"/><br /><sub><b>Ives van Hoorne</b></sub>](http://ivesvh.com)<br />[💬](#question-CompuIves "Answering Questions") [📝](#blog-CompuIves "Blogposts") [🐛](https://github.com/CompuIves/codesandbox-client/issues?q=author%3ACompuIves "Bug reports") [💻](https://github.com/CompuIves/codesandbox-client/commits?author=CompuIves "Code") [🎨](#design-CompuIves "Design") [📖](https://github.com/CompuIves/codesandbox-client/commits?author=CompuIves "Documentation") [💡](#example-CompuIves "Examples") [🚇](#infra-CompuIves "Infrastructure (Hosting, Build-Tools, etc)") [👀](#review-CompuIves "Reviewed Pull Requests") [⚠️](https://github.com/CompuIves/codesandbox-client/commits?author=CompuIves "Tests") [🔧](#tool-CompuIves "Tools") | [<img src="https://avatars0.githubusercontent.com/u/887639?v=3" width="100px;"/><br /><sub><b>Donavon West</b></sub>](http://donavon.com)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=donavon "Code") | [<img src="https://avatars0.githubusercontent.com/u/5266810?v=3" width="100px;"/><br /><sub><b>Jeff Allen</b></sub>](http://www.jeffallen.io/)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=vueu "Code") | [<img src="https://avatars0.githubusercontent.com/u/1089897?v=3" width="100px;"/><br /><sub><b>Ben Gummer</b></sub>](https://github.com/bengummer)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=bengummer "Code") | [<img src="https://avatars3.githubusercontent.com/u/154732?v=3" width="100px;"/><br /><sub><b>James Gillmore</b></sub>](http://twitter.com/faceyspacey)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=faceyspacey "Code") [🐛](https://github.com/CompuIves/codesandbox-client/issues?q=author%3Afaceyspacey "Bug reports") | [<img src="https://avatars1.githubusercontent.com/u/9636410?v=4" width="100px;"/><br /><sub><b>Ade Viankakrisna Fadlil</b></sub>](https://github.com/viankakrisna)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=viankakrisna "Code") | [<img src="https://avatars1.githubusercontent.com/u/1854763?v=4" width="100px;"/><br /><sub><b>Tushar Sonawane</b></sub>](https://twitter.com/tushkiz)<br />[💬](#question-Tushkiz "Answering Questions") [💻](https://github.com/CompuIves/codesandbox-client/commits?author=Tushkiz "Code") [📖](https://github.com/CompuIves/codesandbox-client/commits?author=Tushkiz "Documentation") [🤔](#ideas-Tushkiz "Ideas, Planning, & Feedback") |
4140
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
4241
| [<img src="https://avatars3.githubusercontent.com/u/1239401?v=4" width="100px;"/><br /><sub><b>Johann Hubert Sonntagbauer</b></sub>](https://github.com/johann-sonntagbauer)<br />[🐛](https://github.com/CompuIves/codesandbox-client/issues?q=author%3Ajohann-sonntagbauer "Bug reports") [💻](https://github.com/CompuIves/codesandbox-client/commits?author=johann-sonntagbauer "Code") | [<img src="https://avatars2.githubusercontent.com/u/9586897?v=4" width="100px;"/><br /><sub><b>Joachim Seminck</b></sub>](https://github.com/jseminck)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=jseminck "Code") | [<img src="https://avatars3.githubusercontent.com/u/5210019?v=4" width="100px;"/><br /><sub><b>Subramanya Chakravarthy</b></sub>](http://chakrihacker.github.io)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=chakrihacker "Code") | [<img src="https://avatars3.githubusercontent.com/u/23088?v=4" width="100px;"/><br /><sub><b>Robert (Robby) O'Connor</b></sub>](http://robby.oconnor.ninja)<br />[🚇](#infra-robbyoconnor "Infrastructure (Hosting, Build-Tools, etc)") | [<img src="https://avatars0.githubusercontent.com/u/2083930?v=4" width="100px;"/><br /><sub><b>Bogdan Luca</b></sub>](https://github.com/lbogdan)<br />[🐛](https://github.com/CompuIves/codesandbox-client/issues?q=author%3Albogdan "Bug reports") [💻](https://github.com/CompuIves/codesandbox-client/commits?author=lbogdan "Code") | [<img src="https://avatars3.githubusercontent.com/u/6177621?v=4" width="100px;"/><br /><sub><b>Divjot Singh</b></sub>](http://bogas04.github.io)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=bogas04 "Code") | [<img src="https://avatars3.githubusercontent.com/u/5249539?v=4" width="100px;"/><br /><sub><b>Jason Nall</b></sub>](http://www.jsonnull.com)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=jsonnull "Code") |
4342
| [<img src="https://avatars3.githubusercontent.com/u/784056?v=4" width="100px;"/><br /><sub><b>Lionel</b></sub>](https://elrumordelaluz.com)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=elrumordelaluz "Code") [🎨](#design-elrumordelaluz "Design") | [<img src="https://avatars3.githubusercontent.com/u/170500?v=4" width="100px;"/><br /><sub><b>Philipp Brumm</b></sub>](https://github.com/brumm)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=brumm "Code") | [<img src="https://avatars2.githubusercontent.com/u/2678610?v=4" width="100px;"/><br /><sub><b>Valentin Hervieu</b></sub>](http://valentin-hervieu.fr)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=ValentinH "Code") [🐛](https://github.com/CompuIves/codesandbox-client/issues?q=author%3AValentinH "Bug reports") | [<img src="https://avatars0.githubusercontent.com/u/1499218?v=4" width="100px;"/><br /><sub><b>Anenth</b></sub>](http://anenth.js.org)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=Anenth "Code") [🎨](#design-Anenth "Design") [🤔](#ideas-Anenth "Ideas, Planning, & Feedback") | [<img src="https://avatars0.githubusercontent.com/u/410792?v=4" width="100px;"/><br /><sub><b>Dony Sukardi</b></sub>](http://dsds.io)<br />[🐛](https://github.com/CompuIves/codesandbox-client/issues?q=author%3Adonysukardi "Bug reports") [💻](https://github.com/CompuIves/codesandbox-client/commits?author=donysukardi "Code") | [<img src="https://avatars3.githubusercontent.com/u/89046?v=4" width="100px;"/><br /><sub><b>Geoffrey Dhuyvetters</b></sub>](https://github.com/duivvv)<br />[🎨](#design-duivvv "Design") [💻](https://github.com/CompuIves/codesandbox-client/commits?author=duivvv "Code") | [<img src="https://avatars3.githubusercontent.com/u/3381746?v=4" width="100px;"/><br /><sub><b>Eswar Yaganti</b></sub>](http://nyaganti.com)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=nagamalli9999 "Code") [🚇](#infra-nagamalli9999 "Infrastructure (Hosting, Build-Tools, etc)") |
43+
| [<img src="https://avatars3.githubusercontent.com/u/9488719?v=4" width="100px;"/><br /><sub><b>Frank Tan</b></sub>](https://github.com/tansongyang)<br />[💻](https://github.com/CompuIves/codesandbox-client/commits?author=tansongyang "Code") |
4444
<!-- ALL-CONTRIBUTORS-LIST:END -->
Lines changed: 32 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,64 @@
11
import React from 'react';
2+
import { bindActionCreators } from 'redux';
3+
import { connect } from 'react-redux';
24
import styled from 'styled-components';
35

46
import Button from 'app/components/buttons/Button';
5-
import WorkspaceInputContainer from '../WorkspaceInputContainer';
7+
import modalActionCreators from 'app/store/modal/actions';
68

7-
const ButtonContainer = styled.div`margin: 0.5rem 1rem;`;
9+
import SearchDependencies from './SearchDependencies';
810

9-
type State = {
10-
name: string,
11-
version: string,
12-
};
11+
const ButtonContainer = styled.div`margin: 0.5rem 1rem;`;
1312

1413
type Props = {
1514
addDependency: (dependency: string, version: string) => Promise<boolean>,
16-
existingDependencies: Array<string>,
15+
modalActions: typeof modalActionCreators,
16+
};
17+
18+
type State = {
1719
processing: boolean,
1820
};
1921

20-
const initialState = {
21-
name: '',
22-
version: '',
22+
const initialState: State = {
23+
processing: false,
2324
};
2425

25-
export default class AddVersion extends React.PureComponent {
26-
state = initialState;
26+
const mapDispatchToProps = dispatch => ({
27+
modalActions: bindActionCreators(modalActionCreators, dispatch),
28+
});
2729

28-
state: State;
30+
class AddVersion extends React.PureComponent {
2931
props: Props;
32+
state = initialState;
3033

31-
setName = (e: KeyboardEvent) => {
32-
const { existingDependencies } = this.props;
33-
const name = e.target.value;
34-
this.setState({ name, replacing: existingDependencies.includes(name) });
35-
};
36-
37-
setVersion = (e: KeyboardEvent) => {
38-
this.setState({ version: e.target.value });
39-
};
40-
41-
addDependency = async () => {
42-
if (this.state.name) {
43-
await this.props.addDependency(this.state.name, this.state.version);
44-
this.setState(initialState);
34+
addDependency = async (name, version) => {
35+
if (name) {
36+
this.props.modalActions.closeModal();
37+
this.setState({ processing: true });
38+
await this.props.addDependency(name, version);
39+
this.setState({ processing: false });
4540
}
4641
};
4742

48-
handleKeyUp = (e: KeyboardEvent) => {
49-
if (e.keyCode === 13) {
50-
// Enter
51-
this.addDependency();
52-
}
43+
openModal = () => {
44+
this.props.modalActions.openModal({
45+
width: 600,
46+
Body: <SearchDependencies onConfirm={this.addDependency} />,
47+
});
5348
};
5449

5550
render() {
56-
const { name, version, replacing } = this.state;
57-
const { processing } = this.props;
58-
const isValid = name !== '';
51+
const { processing } = this.state;
5952
return (
6053
<div style={{ position: 'relative' }}>
61-
<WorkspaceInputContainer>
62-
<input
63-
style={{ flex: 3 }}
64-
placeholder="package name"
65-
value={name}
66-
onChange={this.setName}
67-
onKeyUp={this.handleKeyUp}
68-
/>
69-
<input
70-
style={{ flex: 1 }}
71-
placeholder="version"
72-
value={version}
73-
onChange={this.setVersion}
74-
onKeyUp={this.handleKeyUp}
75-
/>
76-
</WorkspaceInputContainer>
7754
<ButtonContainer>
78-
<Button
79-
disabled={!isValid || processing}
80-
block
81-
small
82-
onClick={this.addDependency}
83-
>
84-
{replacing ? 'Replace' : 'Add'} Package
55+
<Button disabled={processing} block small onClick={this.openModal}>
56+
Add Package
8557
</Button>
8658
</ButtonContainer>
8759
</div>
8860
);
8961
}
9062
}
63+
64+
export default connect(null, mapDispatchToProps)(AddVersion);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.ReactModal__Content div[class^='Modal__ModalBody'] {
2+
/*
3+
* app/src/app/containers/Modal.js sets ModalBody background to white.
4+
* We don't want to risk messing up something else, so we fix that here.
5+
*/
6+
background: transparent;
7+
}
8+
9+
.ais-Pagination__root {
10+
border-radius: 0;
11+
display: flex;
12+
justify-content: center;
13+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import React from 'react';
2+
import HomeIcon from 'react-icons/lib/io/home';
3+
import { Highlight } from 'react-instantsearch/dom';
4+
import styled from 'styled-components';
5+
6+
import Select from 'app/components/Select';
7+
import Tooltip from 'common/components/Tooltip';
8+
9+
import GitHubLogo from '../Git/modals/GitHubLogo';
10+
import formatDownloads from './formatDownloads';
11+
12+
const Container = styled.div`
13+
display: flex;
14+
background: ${props =>
15+
props.highlighted ? props.theme.background3 : props.theme.background2};
16+
color: ${props => props.theme.white};
17+
cursor: pointer;
18+
&:not(:last-child) {
19+
border-bottom: 1px solid ${props => props.theme.background3};
20+
}
21+
`;
22+
23+
const Left = styled.div`
24+
flex: 1;
25+
`;
26+
27+
const Right = styled.div`
28+
display: flex;
29+
align-items: center;
30+
`;
31+
32+
const Row = styled.div`
33+
margin: 10px;
34+
& > * {
35+
margin-right: 10px;
36+
}
37+
`;
38+
39+
const Downloads = styled.span`
40+
color: ${props => props.theme.gray};
41+
font-size: 12px;
42+
`;
43+
44+
const License = styled.span`
45+
border: 1px solid ${props => props.theme.gray};
46+
border-radius: 3px;
47+
padding: 1px 3px;
48+
color: ${props => props.theme.gray};
49+
font-size: 12px;
50+
`;
51+
52+
const IconLink = styled.a`
53+
font-size: 1rem;
54+
color: rgba(255, 255, 255, 0.8);
55+
`;
56+
57+
type Props = {
58+
highlighted: boolean,
59+
hit: Object,
60+
onClick: Function,
61+
onVersionChange: Function,
62+
};
63+
64+
type State = {
65+
selectedVersion: string,
66+
};
67+
68+
const initialState: State = {
69+
selectedVersion: '',
70+
};
71+
72+
export default class DependencyHit extends React.PureComponent {
73+
props: Props;
74+
state = initialState;
75+
76+
makeGitHubRepoUrl(repo) {
77+
return `https://github.com/${repo.user}/${repo.project}`;
78+
}
79+
80+
stopPropagation(e) {
81+
e.stopPropagation();
82+
}
83+
84+
handleVersionChange = e => {
85+
const selectedVersion = e.target.value;
86+
this.setState({ selectedVersion });
87+
this.props.onVersionChange(selectedVersion);
88+
};
89+
90+
render() {
91+
const { highlighted, hit, onClick } = this.props;
92+
const versions = Object.keys(hit.versions);
93+
versions.reverse();
94+
return (
95+
<Container highlighted={highlighted} onClick={onClick}>
96+
<Left>
97+
<Row>
98+
<Highlight attributeName="name" hit={hit} />
99+
<Downloads>{formatDownloads(hit.downloadsLast30Days)}</Downloads>
100+
{hit.license && <License>{hit.license}</License>}
101+
</Row>
102+
<Row>{hit.description}</Row>
103+
</Left>
104+
<Right>
105+
<Row>
106+
{hit.githubRepo && (
107+
<Tooltip title={`GitHub repository of ${hit.name}`}>
108+
<IconLink
109+
href={this.makeGitHubRepoUrl(hit.githubRepo)}
110+
target="_blank"
111+
rel="noreferrer noopener"
112+
onClick={this.stopPropagation}
113+
>
114+
<GitHubLogo />
115+
</IconLink>
116+
</Tooltip>
117+
)}
118+
{hit.homepage && (
119+
<Tooltip title={`Homepage of ${hit.name}`}>
120+
<IconLink
121+
href={hit.homepage}
122+
target="_blank"
123+
rel="noreferrer noopener"
124+
onClick={this.stopPropagation}
125+
>
126+
<HomeIcon />
127+
</IconLink>
128+
</Tooltip>
129+
)}
130+
<Select
131+
onClick={this.stopPropagation}
132+
onChange={this.handleVersionChange}
133+
value={this.state.selectedVersion}
134+
>
135+
{versions.map(v => <option key={v}>{v}</option>)}
136+
</Select>
137+
</Row>
138+
</Right>
139+
</Container>
140+
);
141+
}
142+
}

0 commit comments

Comments
 (0)