Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
599778e
Add hamburger menu button for editing Instructions
greenberga Mar 9, 2018
afaedb7
Add state management logic for instructions
greenberga Mar 9, 2018
027f35b
Wire hamburger menu to instructions editing state
greenberga Mar 9, 2018
174a993
Create basic instructions editor
greenberga Mar 9, 2018
3dfba1b
Add a (stubbed) Cancel button
greenberga Mar 9, 2018
2dd3edc
Wire cancel button to instructions state mgmt
greenberga Mar 9, 2018
54487ad
Use i18n functionality for button text
greenberga Mar 9, 2018
f56e959
Add state mgmt logic for updating instructions
greenberga Mar 10, 2018
b07fc88
Wire editor save button to state mgmt logic
greenberga Mar 10, 2018
bb8eb7f
Fix CSS BEM naming violations
greenberga Mar 11, 2018
1c958f7
Toggle instructions hamburger menu item on state
greenberga Mar 11, 2018
9d52744
Add tests for new instructions reducer logic
greenberga Mar 11, 2018
e451ea6
Use uncontrolled textarea for InstructionsEditor
greenberga Mar 12, 2018
fd6dd05
Add a Markdown blurb footer thingy
greenberga Mar 16, 2018
bb99df4
Add _ prefix to this.editor to signify privateness
greenberga Mar 21, 2018
13a90f0
Remove Instructions editing from experimental
greenberga Mar 21, 2018
5ab05fb
Noop MenuItem clicks when isDisabled == true
greenberga Mar 21, 2018
9136733
Show default cursor on Instruct bar when editing
greenberga Mar 21, 2018
5ef4cfb
Rename stopEditingInstructions to cancelEditing...
greenberga Mar 21, 2018
2576d2e
Remove unused CSS variable
greenberga Mar 21, 2018
2a9a2ea
Remove shading of disabled menu item on hover
greenberga Mar 21, 2018
b3c7da8
Fix styling of InstructionsEditor
greenberga Mar 21, 2018
667fd47
Link to Markdown syntax instructions
greenberga Mar 21, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -60,7 +62,11 @@
"css": "CSS",
"javascript": "JS"
},
"output": "Output"
"output": "Output",
"instructions": {
"cancel": "Cancel",
"save": "Save"
}
}
},
"utility": {
Expand Down
6 changes: 6 additions & 0 deletions src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
unhideComponent,
toggleComponent,
updateProjectSource,
updateProjectInstructions,
} from './projects';

import {
Expand All @@ -31,6 +32,8 @@ import {
toggleEditorTextSize,
toggleTopBarMenu,
closeTopBarMenu,
startEditingInstructions,
cancelEditingInstructions,
} from './ui';

import {
Expand Down Expand Up @@ -67,6 +70,7 @@ export {
createSnapshot,
changeCurrentProject,
updateProjectSource,
updateProjectInstructions,
toggleLibrary,
userAuthenticated,
userLoggedOut,
Expand All @@ -92,6 +96,8 @@ export {
toggleEditorTextSize,
toggleTopBarMenu,
closeTopBarMenu,
startEditingInstructions,
cancelEditingInstructions,
logIn,
logOut,
evaluateConsoleEntry,
Expand Down
5 changes: 5 additions & 0 deletions src/actions/projects.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}),
Expand Down
8 changes: 8 additions & 0 deletions src/actions/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
);
31 changes: 26 additions & 5 deletions src/components/Instructions.jsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,45 @@
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;
}

return (
<div
className="layout__instructions"
>
<div className="instructions">
{markdownToReact(instructions)}
</div>
{
isEditing ?
<InstructionsEditor
instructions={instructions}
projectKey={projectKey}
onCancelEditing={onCancelEditing}
onSaveChanges={onSaveChanges}
/> :
<div className="instructions">
{markdownToReact(instructions)}
</div>
}
</div>
);
}

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,
};
69 changes: 69 additions & 0 deletions src/components/InstructionsEditor.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="instructions-editor">
<div className="instructions-editor__menu">
<button
className="instructions-editor__menu-button"
onClick={this._handleSaveChanges}
>
{t('workspace.components.instructions.save')}
</button>
<button
className="instructions-editor__menu-button"
onClick={this._handleCancelEditing}
>
{t('workspace.components.instructions.cancel')}
</button>
</div>
<div className="instructions-editor__input-container">
<textarea
className="instructions-editor__input"
defaultValue={this.props.instructions}
ref={this._ref}
/>
</div>
<div className="instructions-editor__footer">
<a
className="instructions-editor__footer-link"
href="https://guides.github.com/features/mastering-markdown/"
rel="noopener noreferrer"
target="_blank"
>
Styling with Markdown is supported
</a>
</div>
</div>
);
}
}

InstructionsEditor.propTypes = {
instructions: PropTypes.string.isRequired,
projectKey: PropTypes.string.isRequired,
onCancelEditing: PropTypes.func.isRequired,
onSaveChanges: PropTypes.func.isRequired,
};
20 changes: 20 additions & 0 deletions src/components/TopBar/HamburgerMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const HamburgerMenu = createMenu({
name: 'hamburger',

renderItems({
hasInstructions,
isEditingInstructions,
isExperimental,
isGistExportInProgress,
isRepoExportInProgress,
Expand All @@ -20,6 +22,7 @@ const HamburgerMenu = createMenu({
onExportGist,
onExportRepo,
onExportToClassroom,
onStartEditingInstructions,
}) {
return tap([], (items) => {
items.push(
Expand All @@ -31,6 +34,20 @@ const HamburgerMenu = createMenu({
</MenuItem>,
);

items.push(
<MenuItem
isDisabled={isEditingInstructions}
key="addOrEditInstructions"
onClick={onStartEditingInstructions}
>
{
hasInstructions ?
t('top-bar.edit-instructions') :
t('top-bar.add-instructions')
}
</MenuItem>,
);

if (isUserAuthenticated) {
items.push(
<MenuItem
Expand Down Expand Up @@ -96,7 +113,9 @@ const HamburgerMenu = createMenu({


HamburgerMenu.propTypes = {
hasInstructions: PropTypes.bool.isRequired,
isClassroomExportInProgress: PropTypes.bool.isRequired,
isEditingInstructions: PropTypes.bool.isRequired,
isExperimental: PropTypes.bool.isRequired,
isGistExportInProgress: PropTypes.bool.isRequired,
isOpen: PropTypes.bool.isRequired,
Expand All @@ -105,6 +124,7 @@ HamburgerMenu.propTypes = {
onExportGist: PropTypes.func.isRequired,
onExportRepo: PropTypes.func.isRequired,
onExportToClassroom: PropTypes.func.isRequired,
onStartEditingInstructions: PropTypes.func.isRequired,
};

export default HamburgerMenu;
14 changes: 9 additions & 5 deletions src/components/TopBar/createMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import classnames from 'classnames';
import {connect} from 'react-redux';
import constant from 'lodash/constant';
import noop from 'lodash/noop';
import onClickOutside from 'react-onclickoutside';
import preventClickthrough from 'react-prevent-clickthrough';
import property from 'lodash/property';
Expand All @@ -11,13 +12,14 @@ import React from 'react';
import {closeTopBarMenu, toggleTopBarMenu} from '../../actions';
import {getOpenTopBarMenu} from '../../selectors';

export function MenuItem({children, isEnabled, onClick}) {
export function MenuItem({children, isDisabled, isEnabled, onClick}) {
return (
<div
className={classnames('top-bar__menu-item',
{'top-bar__menu-item_active': isEnabled},
)}
onClick={onClick}
className={classnames('top-bar__menu-item', {
'top-bar__menu-item_active': isEnabled,
'top-bar__menu-item_disabled': isDisabled,
})}
onClick={isDisabled ? noop : onClick}
>
{children}
</div>
Expand All @@ -26,11 +28,13 @@ export function MenuItem({children, isEnabled, onClick}) {

MenuItem.propTypes = {
children: PropTypes.node.isRequired,
isDisabled: PropTypes.bool,
isEnabled: PropTypes.bool,
onClick: PropTypes.func.isRequired,
};

MenuItem.defaultProps = {
isDisabled: false,
isEnabled: false,
};

Expand Down
9 changes: 9 additions & 0 deletions src/components/TopBar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export default function TopBar({
currentProjectKey,
currentUser,
enabledLibraries,
hasInstructions,
isEditingInstructions,
isExperimental,
isGistExportInProgress,
isRepoExportInProgress,
Expand All @@ -49,6 +51,7 @@ export default function TopBar({
onExportRepo,
onExportToClassroom,
onLogOut,
onStartEditingInstructions,
onStartLogIn,
onToggleLibrary,
onToggleTextSize,
Expand Down Expand Up @@ -92,7 +95,9 @@ export default function TopBar({
onStartLogIn={onStartLogIn}
/>
<HamburgerMenu
hasInstructions={hasInstructions}
isClassroomExportInProgress={isClassroomExportInProgress}
isEditingInstructions={isEditingInstructions}
isExperimental={isExperimental}
isGistExportInProgress={isGistExportInProgress}
isOpen={openMenu === 'hamburger'}
Expand All @@ -102,6 +107,7 @@ export default function TopBar({
onExportGist={onExportGist}
onExportRepo={onExportRepo}
onExportToClassroom={onExportToClassroom}
onStartEditingInstructions={onStartEditingInstructions}
/>
</header>
);
Expand All @@ -111,7 +117,9 @@ TopBar.propTypes = {
currentProjectKey: PropTypes.string,
currentUser: PropTypes.object.isRequired,
enabledLibraries: PropTypes.arrayOf(PropTypes.string).isRequired,
hasInstructions: PropTypes.bool.isRequired,
isClassroomExportInProgress: PropTypes.bool.isRequired,
isEditingInstructions: PropTypes.bool.isRequired,
isExperimental: PropTypes.bool.isRequired,
isGistExportInProgress: PropTypes.bool.isRequired,
isRepoExportInProgress: PropTypes.bool.isRequired,
Expand All @@ -131,6 +139,7 @@ TopBar.propTypes = {
onExportRepo: PropTypes.func.isRequired,
onExportToClassroom: PropTypes.func.isRequired,
onLogOut: PropTypes.func.isRequired,
onStartEditingInstructions: PropTypes.func.isRequired,
onStartLogIn: PropTypes.func.isRequired,
onToggleLibrary: PropTypes.func.isRequired,
onToggleTextSize: PropTypes.func.isRequired,
Expand Down
Loading