diff --git a/locales/en/translation.json b/locales/en/translation.json index bb5f633d1a..a0a8393b4b 100644 --- a/locales/en/translation.json +++ b/locales/en/translation.json @@ -4,6 +4,8 @@ "export-gist": "Export Gist", "export-repo": "Export Repo", "share-to-classroom": "Share To Classroom", + "add-instructions": "Add Instructions", + "edit-instructions": "Edit Instructions", "libraries": "Libraries", "load-project": "Your Projects", "new-project": "New Project", @@ -60,7 +62,11 @@ "css": "CSS", "javascript": "JS" }, - "output": "Output" + "output": "Output", + "instructions": { + "cancel": "Cancel", + "save": "Save" + } } }, "utility": { diff --git a/src/actions/index.js b/src/actions/index.js index 61efc20fe1..3998f368b8 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -15,6 +15,7 @@ import { unhideComponent, toggleComponent, updateProjectSource, + updateProjectInstructions, } from './projects'; import { @@ -31,6 +32,8 @@ import { toggleEditorTextSize, toggleTopBarMenu, closeTopBarMenu, + startEditingInstructions, + cancelEditingInstructions, } from './ui'; import { @@ -67,6 +70,7 @@ export { createSnapshot, changeCurrentProject, updateProjectSource, + updateProjectInstructions, toggleLibrary, userAuthenticated, userLoggedOut, @@ -92,6 +96,8 @@ export { toggleEditorTextSize, toggleTopBarMenu, closeTopBarMenu, + startEditingInstructions, + cancelEditingInstructions, logIn, logOut, evaluateConsoleEntry, diff --git a/src/actions/projects.js b/src/actions/projects.js index e9a662bbc0..0fc760e053 100644 --- a/src/actions/projects.js +++ b/src/actions/projects.js @@ -18,6 +18,11 @@ export const updateProjectSource = createAction( (_projectKey, _language, _newValue, timestamp = Date.now()) => ({timestamp}), ); +export const updateProjectInstructions = createAction( + 'UPDATE_PROJECT_INSTRUCTIONS', + (projectKey, newValue) => ({projectKey, newValue}), +); + export const toggleLibrary = createAction( 'TOGGLE_LIBRARY', (projectKey, libraryKey) => ({projectKey, libraryKey}), diff --git a/src/actions/ui.js b/src/actions/ui.js index 9a39434445..09cbb179ff 100644 --- a/src/actions/ui.js +++ b/src/actions/ui.js @@ -58,3 +58,11 @@ export const toggleTopBarMenu = createAction( export const closeTopBarMenu = createAction( 'CLOSE_TOP_BAR_MENU', ); + +export const startEditingInstructions = createAction( + 'START_EDITING_INSTRUCTIONS', +); + +export const cancelEditingInstructions = createAction( + 'CANCEL_EDITING_INSTRUCTIONS', +); diff --git a/src/components/Instructions.jsx b/src/components/Instructions.jsx index 32068f8e30..050416f68c 100644 --- a/src/components/Instructions.jsx +++ b/src/components/Instructions.jsx @@ -1,9 +1,17 @@ import React from 'react'; import PropTypes from 'prop-types'; import {toReact as markdownToReact} from '../util/markdown'; +import InstructionsEditor from './InstructionsEditor'; -export default function Instructions({instructions, isOpen}) { - if (!instructions || !isOpen) { +export default function Instructions({ + instructions, + isEditing, + isOpen, + projectKey, + onCancelEditing, + onSaveChanges, +}) { + if (!isEditing && !instructions || !isOpen) { return null; } @@ -11,14 +19,27 @@ export default function Instructions({instructions, isOpen}) {
-
- {markdownToReact(instructions)} -
+ { + isEditing ? + : +
+ {markdownToReact(instructions)} +
+ }
); } Instructions.propTypes = { instructions: PropTypes.string.isRequired, + isEditing: PropTypes.bool.isRequired, isOpen: PropTypes.bool.isRequired, + projectKey: PropTypes.string.isRequired, + onCancelEditing: PropTypes.func.isRequired, + onSaveChanges: PropTypes.func.isRequired, }; diff --git a/src/components/InstructionsEditor.jsx b/src/components/InstructionsEditor.jsx new file mode 100644 index 0000000000..7a678449bd --- /dev/null +++ b/src/components/InstructionsEditor.jsx @@ -0,0 +1,69 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {t} from 'i18next'; +import bindAll from 'lodash/bindAll'; + +export default class InstructionsEditor extends React.Component { + constructor() { + super(); + bindAll(this, '_handleCancelEditing', '_handleSaveChanges', '_ref'); + } + + _handleCancelEditing() { + this.props.onCancelEditing(); + } + + _handleSaveChanges() { + const newValue = this._editor.value.trim(); + this.props.onSaveChanges(this.props.projectKey, newValue); + } + + _ref(editorElement) { + this._editor = editorElement; + } + + render() { + return ( +
+
+ + +
+
+