diff --git a/client/modules/IDE/components/ProjectName.jsx b/client/modules/IDE/components/ProjectName.jsx
new file mode 100644
index 0000000000..542fdbdc6e
--- /dev/null
+++ b/client/modules/IDE/components/ProjectName.jsx
@@ -0,0 +1,166 @@
+import React, { useState, useRef } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import styled from 'styled-components';
+import { Link } from 'react-router';
+
+import { prop, remSize } from '../../../theme';
+
+import EditProjectNameIcon from '../../../images/pencil.svg';
+
+const Container = styled.div`
+ margin-left: ${remSize(10)};
+ padding-left: ${remSize(10)};
+ height: 70%;
+ display: flex;
+ align-items: center;
+ border-color: ${prop('inactiveTextColor')};
+`;
+
+const EditNameButton = styled(EditProjectNameIcon)`
+ display: inline-block;
+ vertical-align: top;
+ width: ${remSize(18)};
+ height: ${remSize(18)};
+ & path {
+ fill: ${prop('secondaryTextColor')};
+ }
+`;
+
+const Name = styled.button`
+ &&& {
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ color: ${prop('secondaryTextColor')};
+ &:hover {
+ color: ${prop('logoColor')};
+ & ${EditNameButton} path {
+ fill: ${prop('logoColor')};
+ }
+ }
+
+ ${({ isEditingName }) => isEditingName && `display: none;`}
+ }
+`;
+
+const Input = styled.input`
+ display: none;
+ border: 0px;
+ ${({ isEditingName }) => isEditingName && `display: block;`}
+`;
+
+const Owner = styled.p`
+ margin-left: ${remSize(5)};
+ color: ${prop('secondaryTextColor')};
+`;
+
+const ProjectName = (props) => {
+ const {
+ owner,
+ currentUser,
+ project,
+ showEditProjectName,
+ setProjectName,
+ hideEditProjectName,
+ saveProject
+ } = props;
+
+ const { t } = useTranslation();
+
+ const [projectNameInputValue, setProjectNameInputValue] = useState(
+ project.name
+ );
+
+ const projectNameInputRef = useRef(null);
+
+ const canEditProjectName =
+ (owner && owner.username && owner.username === currentUser) ||
+ !owner ||
+ !owner.username;
+
+ const handleProjectNameChange = (event) => {
+ setProjectNameInputValue(event.target.value);
+ };
+
+ const handleProjectNameSave = () => {
+ const newProjectName = projectNameInputValue.trim();
+ if (newProjectName.length === 0) {
+ setProjectNameInputValue(project.name);
+ } else {
+ setProjectName(newProjectName);
+ hideEditProjectName();
+ if (project.id) {
+ saveProject();
+ }
+ }
+ };
+
+ const handleKeyPress = (event) => {
+ if (event.key === 'Enter') {
+ hideEditProjectName();
+ projectNameInputRef.current.blur();
+ }
+ };
+
+ return (
+
+ {
+ if (canEditProjectName) {
+ showEditProjectName();
+ setTimeout(() => projectNameInputRef.current.focus(), 0);
+ }
+ }}
+ disabled={!canEditProjectName}
+ aria-label={t('Toolbar.EditSketchARIA')}
+ isEditingName={project.isEditingName}
+ >
+ {project.name}
+ {canEditProjectName && (
+
+ )}
+
+
+ {owner && (
+
+ {t('Toolbar.By')}
+ {owner.username}
+
+ )}
+
+ );
+};
+
+ProjectName.propTypes = {
+ setProjectName: PropTypes.func.isRequired,
+ currentUser: PropTypes.string,
+ owner: PropTypes.shape({
+ username: PropTypes.string
+ }),
+ project: PropTypes.shape({
+ name: PropTypes.string.isRequired,
+ isEditingName: PropTypes.bool,
+ id: PropTypes.string
+ }).isRequired,
+ showEditProjectName: PropTypes.func.isRequired,
+ hideEditProjectName: PropTypes.func.isRequired,
+ saveProject: PropTypes.func.isRequired
+};
+
+ProjectName.defaultProps = {
+ owner: undefined,
+ currentUser: undefined
+};
+
+export default ProjectName;
diff --git a/client/modules/IDE/components/Toolbar.jsx b/client/modules/IDE/components/Toolbar.jsx
index f87d80bf34..768fe1d840 100644
--- a/client/modules/IDE/components/Toolbar.jsx
+++ b/client/modules/IDE/components/Toolbar.jsx
@@ -1,188 +1,94 @@
import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
-import { Link } from 'react-router';
import classNames from 'classnames';
import { withTranslation } from 'react-i18next';
import * as IDEActions from '../actions/ide';
import * as preferenceActions from '../actions/preferences';
import * as projectActions from '../actions/project';
+import ProjectName from '../components/ProjectName';
+
import PlayIcon from '../../../images/play.svg';
import StopIcon from '../../../images/stop.svg';
import PreferencesIcon from '../../../images/preferences.svg';
-import EditProjectNameIcon from '../../../images/pencil.svg';
-
-class Toolbar extends React.Component {
- constructor(props) {
- super(props);
- this.handleKeyPress = this.handleKeyPress.bind(this);
- this.handleProjectNameChange = this.handleProjectNameChange.bind(this);
- this.handleProjectNameSave = this.handleProjectNameSave.bind(this);
-
- this.state = {
- projectNameInputValue: props.project.name
- };
- }
-
- handleKeyPress(event) {
- if (event.key === 'Enter') {
- this.props.hideEditProjectName();
- this.projectNameInput.blur();
- }
- }
-
- handleProjectNameChange(event) {
- this.setState({ projectNameInputValue: event.target.value });
- }
- handleProjectNameSave() {
- const newProjectName = this.state.projectNameInputValue.trim();
- if (newProjectName.length === 0) {
- this.setState({
- projectNameInputValue: this.props.project.name
- });
- } else {
- this.props.setProjectName(newProjectName);
- this.props.hideEditProjectName();
- if (this.props.project.id) {
- this.props.saveProject();
- }
- }
- }
+const Toolbar = (props) => {
+ const playButtonClass = classNames({
+ 'toolbar__play-button': true,
+ 'toolbar__play-button--selected': props.isPlaying
+ });
+ const stopButtonClass = classNames({
+ 'toolbar__stop-button': true,
+ 'toolbar__stop-button--selected': !props.isPlaying
+ });
+ const preferencesButtonClass = classNames({
+ 'toolbar__preferences-button': true,
+ 'toolbar__preferences-button--selected': props.preferencesIsVisible
+ });
- canEditProjectName() {
- return (
- (this.props.owner &&
- this.props.owner.username &&
- this.props.owner.username === this.props.currentUser) ||
- !this.props.owner ||
- !this.props.owner.username
- );
- }
-
- render() {
- const playButtonClass = classNames({
- 'toolbar__play-button': true,
- 'toolbar__play-button--selected': this.props.isPlaying
- });
- const stopButtonClass = classNames({
- 'toolbar__stop-button': true,
- 'toolbar__stop-button--selected': !this.props.isPlaying
- });
- const preferencesButtonClass = classNames({
- 'toolbar__preferences-button': true,
- 'toolbar__preferences-button--selected': this.props.preferencesIsVisible
- });
- const nameContainerClass = classNames({
- 'toolbar__project-name-container': true,
- 'toolbar__project-name-container--editing': this.props.project
- .isEditingName
- });
-
- const canEditProjectName = this.canEditProjectName();
-
- return (
-
-