Skip to content

Commit d0a49b9

Browse files
authored
Merge branch 'develop' into piyush/fix-edit-rename-using-keyboard
2 parents bf225bf + 99b9463 commit d0a49b9

34 files changed

+381
-167
lines changed

client/components/SkipLink.jsx

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React, { useState } from 'react';
2+
import classNames from 'classnames';
3+
import PropTypes from 'prop-types';
4+
import { useTranslation } from 'react-i18next';
5+
6+
const SkipLink = ({ targetId, text }) => {
7+
const [focus, setFocus] = useState(false);
8+
const { t } = useTranslation();
9+
const handleFocus = () => {
10+
setFocus(true);
11+
};
12+
13+
const handleBlur = () => {
14+
setFocus(false);
15+
};
16+
const linkClasses = classNames('skip_link', { focus });
17+
18+
return (
19+
<a
20+
href={`#${targetId}`}
21+
className={linkClasses}
22+
onFocus={handleFocus}
23+
onBlur={handleBlur}
24+
>
25+
{t(`SkipLink.${text}`)}
26+
</a>
27+
);
28+
};
29+
30+
SkipLink.propTypes = {
31+
targetId: PropTypes.string.isRequired,
32+
text: PropTypes.string.isRequired
33+
};
34+
35+
export default SkipLink;
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,24 @@
1-
import React from 'react';
2-
import { connect } from 'react-redux';
3-
import browserHistory from '../browserHistory';
1+
import { useEffect } from 'react';
2+
import { useSelector } from 'react-redux';
3+
import { useHistory } from 'react-router-dom';
4+
import PropTypes from 'prop-types';
45

5-
const RedirectToUser = ({ username, url = '/:username/sketches' }) => {
6-
React.useEffect(() => {
7-
if (username == null) {
8-
return;
6+
const RedirectToUser = ({ url = '/:username/sketches' }) => {
7+
const history = useHistory();
8+
const username = useSelector((state) =>
9+
state.user ? state.user.username : null
10+
);
11+
useEffect(() => {
12+
if (username) {
13+
history.replace(url.replace(':username', username));
914
}
10-
11-
browserHistory.replace(url.replace(':username', username));
12-
}, [username]);
15+
}, [history, url, username]);
1316

1417
return null;
1518
};
1619

17-
function mapStateToProps(state) {
18-
return {
19-
username: state.user ? state.user.username : null
20-
};
21-
}
22-
23-
const ConnectedRedirectToUser = connect(mapStateToProps)(RedirectToUser);
24-
25-
const createRedirectWithUsername = (url) => (props) => (
26-
<ConnectedRedirectToUser {...props} url={url} />
27-
);
20+
RedirectToUser.propTypes = {
21+
url: PropTypes.string.isRequired
22+
};
2823

29-
export default createRedirectWithUsername;
24+
export default RedirectToUser;

client/constants.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ export const SET_BLOB_URL = 'SET_BLOB_URL';
5252
export const EXPAND_SIDEBAR = 'EXPAND_SIDEBAR';
5353
export const COLLAPSE_SIDEBAR = 'COLLAPSE_SIDEBAR';
5454

55-
export const CONSOLE_EVENT = 'CONSOLE_EVENT';
56-
export const CLEAR_CONSOLE = 'CLEAR_CONSOLE';
5755
export const EXPAND_CONSOLE = 'EXPAND_CONSOLE';
5856
export const COLLAPSE_CONSOLE = 'COLLAPSE_CONSOLE';
5957

@@ -140,3 +138,6 @@ export const START_SAVING_PROJECT = 'START_SAVING_PROJECT';
140138
export const END_SAVING_PROJECT = 'END_SAVING_PROJECT';
141139

142140
export const SET_COOKIE_CONSENT = 'SET_COOKIE_CONSENT';
141+
142+
export const CONSOLE_EVENT = 'CONSOLE_EVENT';
143+
export const CLEAR_CONSOLE = 'CLEAR_CONSOLE';

client/index.jsx

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Routing from './routes';
99
import ThemeProvider from './modules/App/components/ThemeProvider';
1010
import Loader from './modules/App/components/loader';
1111
import './i18n';
12+
import SkipLink from './components/SkipLink';
1213

1314
require('./styles/main.scss');
1415

@@ -23,6 +24,7 @@ const App = () => (
2324
<Provider store={store}>
2425
<ThemeProvider>
2526
<Router history={browserHistory}>
27+
<SkipLink targetId="play-sketch" text="PlaySketch" />
2628
<Routing />
2729
</Router>
2830
</ThemeProvider>

client/modules/IDE/actions/console.js

+1-14
Original file line numberDiff line numberDiff line change
@@ -1,14 +1 @@
1-
import * as ActionTypes from '../../../constants';
2-
3-
export function clearConsole() {
4-
return {
5-
type: ActionTypes.CLEAR_CONSOLE
6-
};
7-
}
8-
9-
export function dispatchConsoleEvent(messages) {
10-
return {
11-
type: ActionTypes.CONSOLE_EVENT,
12-
event: messages
13-
};
14-
}
1+
export { dispatchConsoleEvent, clearConsole } from '../reducers/console';

client/modules/IDE/components/CollectionList/CollectionListRow.jsx

+78-4
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,88 @@ import { connect } from 'react-redux';
44
import { Link } from 'react-router-dom';
55
import { bindActionCreators } from 'redux';
66
import { withTranslation } from 'react-i18next';
7+
import styled from 'styled-components';
78
import MenuItem from '../../../../components/Dropdown/MenuItem';
89
import TableDropdown from '../../../../components/Dropdown/TableDropdown';
910
import * as ProjectActions from '../../actions/project';
1011
import * as CollectionsActions from '../../actions/collections';
1112
import * as IdeActions from '../../actions/ide';
1213
import * as ToastActions from '../../actions/toast';
1314
import dates from '../../../../utils/formatDate';
15+
import { remSize, prop } from '../../../../theme';
1416

17+
const SketchsTableRow = styled.tr`
18+
&&& {
19+
margin: ${remSize(10)};
20+
height: ${remSize(72)};
21+
font-size: ${remSize(16)};
22+
}
23+
&:nth-child(odd) {
24+
background: ${prop('tableRowStripeColor')};
25+
}
26+
27+
> th:nth-child(1) {
28+
padding-left: ${remSize(12)};
29+
}
30+
31+
> td {
32+
padding-left: ${remSize(8)};
33+
}
34+
35+
a {
36+
color: ${prop('primaryTextColor')};
37+
}
38+
39+
&.is-deleted > * {
40+
font-style: italic;
41+
}
42+
@media (max-width: 770px) {
43+
&&& {
44+
margin: 0;
45+
position: relative;
46+
display: flex;
47+
flex-wrap: wrap;
48+
padding: ${remSize(15)};
49+
height: fit-content;
50+
gap: ${remSize(8)};
51+
border: 1px solid ${prop('modalBorderColor')};
52+
background-color: ${prop('searchBackgroundColor')};
53+
> th {
54+
padding-left: 0;
55+
width: 100%;
56+
font-weight: bold;
57+
margin-bottom: ${remSize(6)};
58+
}
59+
> td {
60+
padding-left: 0;
61+
width: 30%;
62+
font-size: ${remSize(14)};
63+
color: ${prop('modalBorderColor')};
64+
}
65+
}
66+
}
67+
`;
68+
const SketchesTableName = styled.span`
69+
&&& {
70+
display: flex;
71+
align-items: center;
72+
}
73+
`;
74+
const SketchlistDropdownColumn = styled.td`
75+
&&& {
76+
position: relative;
77+
width: ${remSize(60)};
78+
}
79+
@media (max-width: 770px) {
80+
&&& {
81+
position: absolute;
82+
top: 0;
83+
right: ${remSize(4)};
84+
width: auto !important;
85+
margin: ${remSize(8)};
86+
}
87+
}
88+
`;
1589
const formatDateCell = (date, mobile = false) =>
1690
dates.format(date, { showTime: !mobile });
1791

@@ -127,18 +201,18 @@ const CollectionListRowBase = (props) => {
127201
const { collection, mobile } = props;
128202

129203
return (
130-
<tr className="sketches-table__row" key={collection.id}>
204+
<SketchsTableRow key={collection.id}>
131205
<th scope="row">
132-
<span className="sketches-table__name">{renderCollectionName()}</span>
206+
<SketchesTableName>{renderCollectionName()}</SketchesTableName>
133207
</th>
134208
<td>{formatDateCell(collection.createdAt, mobile)}</td>
135209
<td>{formatDateCell(collection.updatedAt, mobile)}</td>
136210
<td>
137211
{mobile && 'sketches: '}
138212
{(collection.items || []).length}
139213
</td>
140-
<td className="sketch-list__dropdown-column">{renderActions()}</td>
141-
</tr>
214+
<SketchlistDropdownColumn>{renderActions()}</SketchlistDropdownColumn>
215+
</SketchsTableRow>
142216
);
143217
};
144218

client/modules/IDE/components/Header/Toolbar.jsx

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const Toolbar = (props) => {
6161
</button>
6262
<button
6363
className={playButtonClass}
64+
id="play-sketch"
6465
onClick={() => {
6566
props.syncFileContent();
6667
dispatch(startSketch());

client/modules/IDE/components/Searchbar/Searchbar.jsx

+47-53
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,65 @@
1+
import React, { useState, useCallback, useEffect } from 'react';
12
import PropTypes from 'prop-types';
2-
import React from 'react';
33
import { throttle } from 'lodash';
44
import { withTranslation } from 'react-i18next';
55
import i18next from 'i18next';
66
import SearchIcon from '../../../../images/magnifyingglass.svg';
77

8-
class Searchbar extends React.Component {
9-
constructor(props) {
10-
super(props);
11-
this.state = {
12-
searchValue: this.props.searchTerm
13-
};
14-
this.throttledSearchChange = throttle(this.searchChange, 500);
15-
}
8+
const Searchbar = ({
9+
searchTerm,
10+
setSearchTerm,
11+
resetSearchTerm,
12+
searchLabel,
13+
t
14+
}) => {
15+
const [searchValue, setSearchValue] = useState(searchTerm);
1616

17-
componentWillUnmount() {
18-
this.props.resetSearchTerm();
19-
}
17+
const throttledSearchChange = useCallback(
18+
throttle((value) => {
19+
setSearchTerm(value.trim());
20+
}, 500),
21+
[]
22+
);
2023

21-
handleResetSearch = () => {
22-
this.setState({ searchValue: '' }, () => {
23-
this.props.resetSearchTerm();
24-
});
24+
const handleResetSearch = () => {
25+
setSearchValue('');
26+
resetSearchTerm();
2527
};
2628

27-
searchChange = () => {
28-
this.props.setSearchTerm(this.state.searchValue.trim());
29+
const handleSearchChange = (e) => {
30+
const { value } = e.target;
31+
setSearchValue(value);
32+
throttledSearchChange(value.trim());
2933
};
3034

31-
handleSearchChange = (e) => {
32-
this.setState({ searchValue: e.target.value }, () => {
33-
this.throttledSearchChange(this.state.searchValue.trim());
34-
});
35-
};
35+
useEffect(() => {
36+
setSearchValue(searchTerm);
37+
}, [searchTerm]);
3638

37-
render() {
38-
const { searchValue } = this.state;
39-
return (
40-
<div
41-
className={`searchbar ${
42-
searchValue === '' ? 'searchbar--is-empty' : ''
43-
}`}
44-
>
45-
<div className="searchbar__button">
46-
<SearchIcon
47-
className="searchbar__icon"
48-
focusable="false"
49-
aria-hidden="true"
50-
/>
51-
</div>
52-
<input
53-
className="searchbar__input"
54-
type="text"
55-
value={searchValue}
56-
placeholder={this.props.searchLabel}
57-
onChange={this.handleSearchChange}
39+
return (
40+
<div
41+
className={`searchbar ${searchValue === '' ? 'searchbar--is-empty' : ''}`}
42+
>
43+
<div className="searchbar__button">
44+
<SearchIcon
45+
className="searchbar__icon"
46+
focusable="false"
47+
aria-hidden="true"
5848
/>
59-
<button
60-
className="searchbar__clear-button"
61-
onClick={this.handleResetSearch}
62-
>
63-
{this.props.t('Searchbar.ClearTerm')}
64-
</button>
6549
</div>
66-
);
67-
}
68-
}
50+
<input
51+
className="searchbar__input"
52+
type="text"
53+
value={searchValue}
54+
placeholder={searchLabel}
55+
onChange={handleSearchChange}
56+
/>
57+
<button className="searchbar__clear-button" onClick={handleResetSearch}>
58+
{t('Searchbar.ClearTerm')}
59+
</button>
60+
</div>
61+
);
62+
};
6963

7064
Searchbar.propTypes = {
7165
searchTerm: PropTypes.string.isRequired,

0 commit comments

Comments
 (0)