Merge branch 'master' into master
This commit is contained in:
commit
6d998d5f73
23 changed files with 324 additions and 300 deletions
|
@ -55,14 +55,16 @@ class Nav extends React.PureComponent {
|
|||
this.handleFocusForHelp = this.handleFocus.bind(this, 'help');
|
||||
this.toggleDropdownForAccount = this.toggleDropdown.bind(this, 'account');
|
||||
this.handleFocusForAccount = this.handleFocus.bind(this, 'account');
|
||||
this.closeDropDown = this.closeDropDown.bind(this);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
componentDidMount() {
|
||||
document.addEventListener('mousedown', this.handleClick, false);
|
||||
document.addEventListener('keydown', this.closeDropDown, false);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('mousedown', this.handleClick, false);
|
||||
document.removeEventListener('keydown', this.closeDropDown, false);
|
||||
}
|
||||
|
||||
setDropdown(dropdown) {
|
||||
|
@ -71,8 +73,17 @@ class Nav extends React.PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
closeDropDown(e) {
|
||||
if (e.keyCode === 27) {
|
||||
this.setDropdown('none');
|
||||
}
|
||||
}
|
||||
|
||||
handleClick(e) {
|
||||
if (this.node.contains(e.target)) {
|
||||
if (!this.node) {
|
||||
return;
|
||||
}
|
||||
if (this.node && this.node.contains(e.target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -233,25 +244,23 @@ class Nav extends React.PureComponent {
|
|||
<nav className="nav" title="main-navigation" ref={(node) => { this.node = node; }}>
|
||||
<ul className="nav__items-left" title="project-menu">
|
||||
<li className="nav__item-logo">
|
||||
<InlineSVG src={logoUrl} alt="p5.js logo" />
|
||||
<InlineSVG src={logoUrl} alt="p5.js logo" className="svg__logo" />
|
||||
</li>
|
||||
<li className={navDropdownState.file}>
|
||||
<button
|
||||
onClick={this.toggleDropdownForFile}
|
||||
onBlur={this.handleBlur}
|
||||
onFocus={this.clearHideTimeout}
|
||||
onMouseOver={() => {
|
||||
if (this.state.dropdownOpen !== 'none') {
|
||||
this.setDropdown('file');
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span className="nav__item-header">File</span>
|
||||
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
||||
</button>
|
||||
<ul className="nav__dropdown">
|
||||
<button
|
||||
onClick={this.toggleDropdownForFile}
|
||||
className="nav__dropdown-heading"
|
||||
>
|
||||
<span>File</span>
|
||||
<InlineSVG src={triangleUrl} />
|
||||
</button>
|
||||
<li className="nav__dropdown-item">
|
||||
<button
|
||||
onClick={this.handleNew}
|
||||
|
@ -331,18 +340,16 @@ class Nav extends React.PureComponent {
|
|||
onClick={this.toggleDropdownForEdit}
|
||||
onBlur={this.handleBlur}
|
||||
onFocus={this.clearHideTimeout}
|
||||
onMouseOver={() => {
|
||||
if (this.state.dropdownOpen !== 'none') {
|
||||
this.setDropdown('edit');
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span className="nav__item-header">Edit</span>
|
||||
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
||||
</button>
|
||||
<ul className="nav__dropdown">
|
||||
<button
|
||||
onClick={this.toggleDropdownForEdit}
|
||||
className="nav__dropdown-heading"
|
||||
>
|
||||
<span>Edit</span>
|
||||
<InlineSVG src={triangleUrl} />
|
||||
</button>
|
||||
<ul className="nav__dropdown" >
|
||||
<li className="nav__dropdown-item">
|
||||
<button
|
||||
onClick={() => {
|
||||
|
@ -393,18 +400,16 @@ class Nav extends React.PureComponent {
|
|||
onClick={this.toggleDropdownForSketch}
|
||||
onBlur={this.handleBlur}
|
||||
onFocus={this.clearHideTimeout}
|
||||
onMouseOver={() => {
|
||||
if (this.state.dropdownOpen !== 'none') {
|
||||
this.setDropdown('sketch');
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span className="nav__item-header">Sketch</span>
|
||||
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
||||
</button>
|
||||
<ul className="nav__dropdown">
|
||||
<button
|
||||
onClick={this.toggleDropdownForSketch}
|
||||
className="nav__dropdown-heading"
|
||||
>
|
||||
<span>Sketch</span>
|
||||
<InlineSVG src={triangleUrl} />
|
||||
</button>
|
||||
<li className="nav__dropdown-item">
|
||||
<button
|
||||
onClick={this.handleAddFile}
|
||||
|
@ -470,18 +475,16 @@ class Nav extends React.PureComponent {
|
|||
onClick={this.toggleDropdownForHelp}
|
||||
onBlur={this.handleBlur}
|
||||
onFocus={this.clearHideTimeout}
|
||||
onMouseOver={() => {
|
||||
if (this.state.dropdownOpen !== 'none') {
|
||||
this.setDropdown('help');
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span className="nav__item-header">Help & Feedback</span>
|
||||
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
||||
</button>
|
||||
<ul className="nav__dropdown">
|
||||
<button
|
||||
onClick={this.toggleDropdownForHelp}
|
||||
className="nav__dropdown-heading"
|
||||
>
|
||||
<span>Help & Feedback</span>
|
||||
<InlineSVG src={triangleUrl} />
|
||||
</button>
|
||||
<li className="nav__dropdown-item">
|
||||
<button
|
||||
onFocus={this.handleFocusForHelp}
|
||||
|
@ -547,18 +550,16 @@ class Nav extends React.PureComponent {
|
|||
onClick={this.toggleDropdownForAccount}
|
||||
onBlur={this.handleBlur}
|
||||
onFocus={this.clearHideTimeout}
|
||||
onMouseOver={() => {
|
||||
if (this.state.dropdownOpen !== 'none') {
|
||||
this.setDropdown('account');
|
||||
}
|
||||
}}
|
||||
>
|
||||
My Account
|
||||
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
||||
</button>
|
||||
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
||||
<ul className="nav__dropdown">
|
||||
<button
|
||||
onClick={this.toggleDropdown.bind(this, 'account')}
|
||||
className="nav__dropdown-heading"
|
||||
>
|
||||
<span>My Account</span>
|
||||
<InlineSVG src={triangleUrl} />
|
||||
</button>
|
||||
<li className="nav__dropdown-item">
|
||||
<Link
|
||||
to={`/${this.props.user.username}/sketches`}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// TODO Organize this file by reducer type, ot break this apart into
|
||||
// TODO Organize this file by reducer type, to break this apart into
|
||||
// multiple files
|
||||
export const UPDATE_FILE_CONTENT = 'UPDATE_FILE_CONTENT';
|
||||
export const TOGGLE_SKETCH = 'TOGGLE_SKETCH';
|
||||
|
@ -13,14 +13,6 @@ export const OPEN_PREFERENCES = 'OPEN_PREFERENCES';
|
|||
export const CLOSE_PREFERENCES = 'CLOSE_PREFERENCES';
|
||||
export const SET_FONT_SIZE = 'SET_FONT_SIZE';
|
||||
|
||||
export const INCREASE_INDENTATION = 'INCREASE_INDENTATION';
|
||||
export const DECREASE_INDENTATION = 'DECREASE_INDENTATION';
|
||||
export const UPDATE_INDENTATION = 'UPDATE_INDENTATION';
|
||||
export const SET_INDENTATION = 'SET_INDENTATION';
|
||||
|
||||
export const INDENT_WITH_SPACE = 'INDENT_WITH_SPACE';
|
||||
export const INDENT_WITH_TAB = 'INDENT_WITH_TAB';
|
||||
|
||||
export const AUTH_USER = 'AUTH_USER';
|
||||
export const UNAUTH_USER = 'UNAUTH_USER';
|
||||
export const AUTH_ERROR = 'AUTH_ERROR';
|
||||
|
@ -62,6 +54,7 @@ export const UPDATE_FILE_NAME = 'UPDATE_FILE_NAME';
|
|||
export const DELETE_FILE = 'DELETE_FILE';
|
||||
|
||||
export const SET_AUTOSAVE = 'SET_AUTOSAVE';
|
||||
export const SET_LINEWRAP = 'SET_LINEWRAP';
|
||||
export const SET_LINT_WARNING = 'SET_LINT_WARNING';
|
||||
export const SET_PREFERENCES = 'SET_PREFERENCES';
|
||||
export const SET_TEXT_OUTPUT = 'SET_TEXT_OUTPUT';
|
||||
|
|
|
@ -14,6 +14,7 @@ class App extends React.Component {
|
|||
|
||||
componentDidMount() {
|
||||
this.setState({ isMounted: true }); // eslint-disable-line react/no-did-mount-set-state
|
||||
document.body.className = 'light';
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
|
|
|
@ -32,58 +32,6 @@ export function setFontSize(value) {
|
|||
};
|
||||
}
|
||||
|
||||
export function setIndentation(value) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: ActionTypes.SET_INDENTATION,
|
||||
value
|
||||
});
|
||||
const state = getState();
|
||||
if (state.user.authenticated) {
|
||||
const formParams = {
|
||||
preferences: {
|
||||
indentationAmount: value
|
||||
}
|
||||
};
|
||||
updatePreferences(formParams, dispatch);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function indentWithTab() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: ActionTypes.INDENT_WITH_TAB
|
||||
});
|
||||
const state = getState();
|
||||
if (state.user.authenticated) {
|
||||
const formParams = {
|
||||
preferences: {
|
||||
isTabIndent: true
|
||||
}
|
||||
};
|
||||
updatePreferences(formParams, dispatch);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function indentWithSpace() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: ActionTypes.INDENT_WITH_SPACE
|
||||
});
|
||||
const state = getState();
|
||||
if (state.user.authenticated) {
|
||||
const formParams = {
|
||||
preferences: {
|
||||
isTabIndent: false
|
||||
}
|
||||
};
|
||||
updatePreferences(formParams, dispatch);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setAutosave(value) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({
|
||||
|
@ -102,6 +50,24 @@ export function setAutosave(value) {
|
|||
};
|
||||
}
|
||||
|
||||
export function setLinewrap(value) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: ActionTypes.SET_LINEWRAP,
|
||||
value
|
||||
});
|
||||
const state = getState();
|
||||
if (state.user.authenticated) {
|
||||
const formParams = {
|
||||
preferences: {
|
||||
linewrap: value
|
||||
}
|
||||
};
|
||||
updatePreferences(formParams, dispatch);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setLintWarning(value) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({
|
||||
|
|
|
@ -50,6 +50,9 @@ const unsavedChangesDotUrl = require('../../../images/unsaved-changes-dot.svg');
|
|||
const rightArrowUrl = require('../../../images/right-arrow.svg');
|
||||
const leftArrowUrl = require('../../../images/left-arrow.svg');
|
||||
|
||||
const IS_TAB_INDENT = false;
|
||||
const INDENTATION_AMOUNT = 2;
|
||||
|
||||
class Editor extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -80,7 +83,7 @@ class Editor extends React.Component {
|
|||
lineNumbers: true,
|
||||
styleActiveLine: true,
|
||||
inputStyle: 'contenteditable',
|
||||
lineWrapping: false,
|
||||
lineWrapping: this.props.linewrap,
|
||||
fixedGutter: false,
|
||||
foldGutter: true,
|
||||
foldOptions: { widget: '\u2026' },
|
||||
|
@ -105,6 +108,7 @@ class Editor extends React.Component {
|
|||
delete this._cm.options.lint.options.errors;
|
||||
|
||||
this._cm.setOption('extraKeys', {
|
||||
Tab: cm => cm.replaceSelection(' '.repeat(INDENTATION_AMOUNT)),
|
||||
[`${metaKey}-Enter`]: () => null,
|
||||
[`Shift-${metaKey}-Enter`]: () => null,
|
||||
[`${metaKey}-F`]: 'findPersistent',
|
||||
|
@ -137,9 +141,6 @@ class Editor extends React.Component {
|
|||
});
|
||||
|
||||
this._cm.getWrapperElement().style['font-size'] = `${this.props.fontSize}px`;
|
||||
this._cm.setOption('indentWithTabs', this.props.isTabIndent);
|
||||
this._cm.setOption('tabSize', this.props.indentationAmount);
|
||||
this._cm.setOption('indentUnit', this.props.indentationAmount);
|
||||
|
||||
this.props.provideController({
|
||||
tidyCode: this.tidyCode,
|
||||
|
@ -174,12 +175,8 @@ class Editor extends React.Component {
|
|||
if (this.props.fontSize !== prevProps.fontSize) {
|
||||
this._cm.getWrapperElement().style['font-size'] = `${this.props.fontSize}px`;
|
||||
}
|
||||
if (this.props.indentationAmount !== prevProps.indentationAmount) {
|
||||
this._cm.setOption('tabSize', this.props.indentationAmount);
|
||||
this._cm.setOption('indentUnit', this.props.indentationAmount);
|
||||
}
|
||||
if (this.props.isTabIndent !== prevProps.isTabIndent) {
|
||||
this._cm.setOption('indentWithTabs', this.props.isTabIndent);
|
||||
if (this.props.linewrap !== prevProps.linewrap) {
|
||||
this._cm.setOption('lineWrapping', this.props.linewrap);
|
||||
}
|
||||
if (this.props.theme !== prevProps.theme) {
|
||||
this._cm.setOption('theme', `p5-${this.props.theme}`);
|
||||
|
@ -254,8 +251,8 @@ class Editor extends React.Component {
|
|||
|
||||
tidyCode() {
|
||||
const beautifyOptions = {
|
||||
indent_size: this.props.indentationAmount,
|
||||
indent_with_tabs: this.props.isTabIndent
|
||||
indent_size: INDENTATION_AMOUNT,
|
||||
indent_with_tabs: IS_TAB_INDENT
|
||||
};
|
||||
|
||||
const mode = this._cm.getOption('mode');
|
||||
|
@ -339,6 +336,7 @@ class Editor extends React.Component {
|
|||
|
||||
Editor.propTypes = {
|
||||
lintWarning: PropTypes.bool.isRequired,
|
||||
linewrap: PropTypes.bool.isRequired,
|
||||
lintMessages: PropTypes.arrayOf(PropTypes.shape({
|
||||
severity: PropTypes.string.isRequired,
|
||||
line: PropTypes.number.isRequired,
|
||||
|
@ -351,8 +349,6 @@ Editor.propTypes = {
|
|||
})),
|
||||
updateLintMessage: PropTypes.func.isRequired,
|
||||
clearLintMessage: PropTypes.func.isRequired,
|
||||
indentationAmount: PropTypes.number.isRequired,
|
||||
isTabIndent: PropTypes.bool.isRequired,
|
||||
updateFileContent: PropTypes.func.isRequired,
|
||||
fontSize: PropTypes.number.isRequired,
|
||||
file: PropTypes.shape({
|
||||
|
|
|
@ -24,13 +24,29 @@ export class FileNode extends React.Component {
|
|||
this.hideFileOptions = this.hideFileOptions.bind(this);
|
||||
this.showEditFileName = this.showEditFileName.bind(this);
|
||||
this.hideEditFileName = this.hideEditFileName.bind(this);
|
||||
this.onBlurComponent = this.onBlurComponent.bind(this);
|
||||
this.onFocusComponent = this.onFocusComponent.bind(this);
|
||||
|
||||
this.state = {
|
||||
isOptionsOpen: false,
|
||||
isEditingName: false,
|
||||
isFocused: false,
|
||||
};
|
||||
}
|
||||
|
||||
onFocusComponent() {
|
||||
this.setState({ isFocused: true });
|
||||
}
|
||||
|
||||
onBlurComponent() {
|
||||
this.setState({ isFocused: false });
|
||||
setTimeout(() => {
|
||||
if (!this.state.isFocused) {
|
||||
this.hideFileOptions();
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
handleFileClick(e) {
|
||||
e.stopPropagation();
|
||||
if (this.props.name !== 'root' && !this.isDeleting) {
|
||||
|
@ -105,6 +121,7 @@ export class FileNode extends React.Component {
|
|||
'sidebar__file-item--editing': this.state.isEditingName,
|
||||
'sidebar__file-item--closed': this.props.isFolderClosed
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={itemClass}>
|
||||
{(() => { // eslint-disable-line
|
||||
|
@ -156,7 +173,8 @@ export class FileNode extends React.Component {
|
|||
ref={(element) => { this[`fileOptions-${this.props.id}`] = element; }}
|
||||
tabIndex="0"
|
||||
onClick={this.toggleFileOptions}
|
||||
onBlur={() => setTimeout(this.hideFileOptions, 200)}
|
||||
onBlur={this.onBlurComponent}
|
||||
onFocus={this.onFocusComponent}
|
||||
>
|
||||
<InlineSVG src={downArrowUrl} />
|
||||
</button>
|
||||
|
@ -168,7 +186,12 @@ export class FileNode extends React.Component {
|
|||
<li>
|
||||
<button
|
||||
aria-label="add file"
|
||||
onClick={this.props.newFile}
|
||||
onClick={() => {
|
||||
this.props.newFile();
|
||||
setTimeout(() => this.hideFileOptions(), 0);
|
||||
}}
|
||||
onBlur={this.onBlurComponent}
|
||||
onFocus={this.onFocusComponent}
|
||||
className="sidebar__file-item-option"
|
||||
>
|
||||
Add File
|
||||
|
@ -183,7 +206,12 @@ export class FileNode extends React.Component {
|
|||
<li>
|
||||
<button
|
||||
aria-label="add folder"
|
||||
onClick={this.props.newFolder}
|
||||
onClick={() => {
|
||||
this.props.newFolder();
|
||||
setTimeout(() => this.hideFileOptions(), 0);
|
||||
}}
|
||||
onBlur={this.onBlurComponent}
|
||||
onFocus={this.onFocusComponent}
|
||||
className="sidebar__file-item-option"
|
||||
>
|
||||
Add Folder
|
||||
|
@ -198,7 +226,10 @@ export class FileNode extends React.Component {
|
|||
this.originalFileName = this.props.name;
|
||||
this.showEditFileName();
|
||||
setTimeout(() => this.fileNameInput.focus(), 0);
|
||||
setTimeout(() => this.hideFileOptions(), 0);
|
||||
}}
|
||||
onBlur={this.onBlurComponent}
|
||||
onFocus={this.onFocusComponent}
|
||||
className="sidebar__file-item-option"
|
||||
>
|
||||
Rename
|
||||
|
@ -213,6 +244,8 @@ export class FileNode extends React.Component {
|
|||
setTimeout(() => this.props.deleteFile(this.props.id, this.props.parentId), 100);
|
||||
}
|
||||
}}
|
||||
onBlur={this.onBlurComponent}
|
||||
onFocus={this.onFocusComponent}
|
||||
className="sidebar__file-item-option"
|
||||
>
|
||||
Delete
|
||||
|
|
|
@ -15,8 +15,8 @@ class Preferences extends React.Component {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
this.handleUpdateAutosave = this.handleUpdateAutosave.bind(this);
|
||||
this.handleUpdateLinewrap = this.handleUpdateLinewrap.bind(this);
|
||||
this.handleUpdateFont = this.handleUpdateFont.bind(this);
|
||||
this.handleUpdateIndentation = this.handleUpdateIndentation.bind(this);
|
||||
this.handleLintWarning = this.handleLintWarning.bind(this);
|
||||
}
|
||||
|
||||
|
@ -34,25 +34,16 @@ class Preferences extends React.Component {
|
|||
this.props.setFontSize(value);
|
||||
}
|
||||
|
||||
handleUpdateIndentation(event) {
|
||||
let value = parseInt(event.target.value, 10);
|
||||
if (Number.isNaN(value)) {
|
||||
value = 2;
|
||||
}
|
||||
if (value > 6) {
|
||||
value = 6;
|
||||
}
|
||||
if (value < 0) {
|
||||
value = 0;
|
||||
}
|
||||
this.props.setIndentation(value);
|
||||
}
|
||||
|
||||
handleUpdateAutosave(event) {
|
||||
const value = event.target.value === 'true';
|
||||
this.props.setAutosave(value);
|
||||
}
|
||||
|
||||
handleUpdateLinewrap(event) {
|
||||
const value = event.target.value === 'true';
|
||||
this.props.setLinewrap(value);
|
||||
}
|
||||
|
||||
handleLintWarning(event) {
|
||||
const value = event.target.value === 'true';
|
||||
this.props.setLintWarning(value);
|
||||
|
@ -144,65 +135,6 @@ class Preferences extends React.Component {
|
|||
<h6 className="preference__label">Increase</h6>
|
||||
</button>
|
||||
</div>
|
||||
<div className="preference">
|
||||
<h4 className="preference__title">Indentation amount</h4>
|
||||
<button
|
||||
className="preference__minus-button"
|
||||
onClick={() => this.props.setIndentation(this.props.indentationAmount - 2)}
|
||||
aria-label="decrease indentation amount"
|
||||
disabled={this.props.indentationAmount <= 0}
|
||||
>
|
||||
<InlineSVG src={minusUrl} alt="DecreaseIndentation Amount" />
|
||||
<h6 className="preference__label">Decrease</h6>
|
||||
</button>
|
||||
<input
|
||||
className="preference__value"
|
||||
aria-live="polite"
|
||||
aria-atomic="true"
|
||||
value={this.props.indentationAmount}
|
||||
onChange={this.handleUpdateIndentation}
|
||||
ref={(element) => { this.indentationInput = element; }}
|
||||
onClick={() => {
|
||||
this.indentationInput.select();
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
className="preference__plus-button"
|
||||
onClick={() => this.props.setIndentation(this.props.indentationAmount + 2)}
|
||||
aria-label="increase indentation amount"
|
||||
disabled={this.props.indentationAmount >= 6}
|
||||
>
|
||||
<InlineSVG src={plusUrl} alt="IncreaseIndentation Amount" />
|
||||
<h6 className="preference__label">Increase</h6>
|
||||
</button>
|
||||
<input
|
||||
type="radio"
|
||||
onChange={this.props.indentWithSpace}
|
||||
aria-label="indentation with space"
|
||||
name="indentation"
|
||||
id="indentation-space"
|
||||
className="preference__radio-button"
|
||||
value="Spaces"
|
||||
checked={!this.props.isTabIndent}
|
||||
/>
|
||||
<label
|
||||
htmlFor="indentation-space"
|
||||
className="preference__option preference__whitespace-button"
|
||||
>
|
||||
Spaces
|
||||
</label>
|
||||
<input
|
||||
type="radio"
|
||||
onChange={this.props.indentWithTab}
|
||||
aria-label="indentation with tab"
|
||||
name="indentation"
|
||||
id="indentation-tab"
|
||||
className="preference__radio-button"
|
||||
value="Tabs"
|
||||
checked={this.props.isTabIndent}
|
||||
/>
|
||||
<label htmlFor="indentation-tab" className="preference__option preference__whitespace-button">Tabs</label>
|
||||
</div>
|
||||
<div className="preference">
|
||||
<h4 className="preference__title">Autosave</h4>
|
||||
<div className="preference__options">
|
||||
|
@ -230,6 +162,33 @@ class Preferences extends React.Component {
|
|||
<label htmlFor="autosave-off" className="preference__option">Off</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="preference">
|
||||
<h4 className="preference__title">Word Wrap</h4>
|
||||
<div className="preference__options">
|
||||
<input
|
||||
type="radio"
|
||||
onChange={() => this.props.setLinewrap(true)}
|
||||
aria-label="linewrap on"
|
||||
name="linewrap"
|
||||
id="linewrap-on"
|
||||
className="preference__radio-button"
|
||||
value="On"
|
||||
checked={this.props.linewrap}
|
||||
/>
|
||||
<label htmlFor="linewrap-on" className="preference__option">On</label>
|
||||
<input
|
||||
type="radio"
|
||||
onChange={() => this.props.setLinewrap(false)}
|
||||
aria-label="linewrap off"
|
||||
name="linewrap"
|
||||
id="linewrap-off"
|
||||
className="preference__radio-button"
|
||||
value="Off"
|
||||
checked={!this.props.linewrap}
|
||||
/>
|
||||
<label htmlFor="linewrap-off" className="preference__option">Off</label>
|
||||
</div>
|
||||
</div>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<div className="preference">
|
||||
|
@ -318,14 +277,11 @@ class Preferences extends React.Component {
|
|||
|
||||
Preferences.propTypes = {
|
||||
fontSize: PropTypes.number.isRequired,
|
||||
indentationAmount: PropTypes.number.isRequired,
|
||||
setIndentation: PropTypes.func.isRequired,
|
||||
indentWithSpace: PropTypes.func.isRequired,
|
||||
indentWithTab: PropTypes.func.isRequired,
|
||||
isTabIndent: PropTypes.bool.isRequired,
|
||||
setFontSize: PropTypes.func.isRequired,
|
||||
autosave: PropTypes.bool.isRequired,
|
||||
linewrap: PropTypes.bool.isRequired,
|
||||
setAutosave: PropTypes.func.isRequired,
|
||||
setLinewrap: PropTypes.func.isRequired,
|
||||
textOutput: PropTypes.bool.isRequired,
|
||||
gridOutput: PropTypes.bool.isRequired,
|
||||
soundOutput: PropTypes.bool.isRequired,
|
||||
|
|
|
@ -12,6 +12,25 @@ class Sidebar extends React.Component {
|
|||
super(props);
|
||||
this.resetSelectedFile = this.resetSelectedFile.bind(this);
|
||||
this.toggleProjectOptions = this.toggleProjectOptions.bind(this);
|
||||
this.onBlurComponent = this.onBlurComponent.bind(this);
|
||||
this.onFocusComponent = this.onFocusComponent.bind(this);
|
||||
|
||||
this.state = {
|
||||
isFocused: false,
|
||||
};
|
||||
}
|
||||
|
||||
onBlurComponent() {
|
||||
this.setState({ isFocused: false });
|
||||
setTimeout(() => {
|
||||
if (!this.state.isFocused) {
|
||||
this.props.closeProjectOptions();
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
onFocusComponent() {
|
||||
this.setState({ isFocused: true });
|
||||
}
|
||||
|
||||
resetSelectedFile() {
|
||||
|
@ -65,18 +84,35 @@ class Sidebar extends React.Component {
|
|||
tabIndex="0"
|
||||
ref={(element) => { this.sidebarOptions = element; }}
|
||||
onClick={this.toggleProjectOptions}
|
||||
onBlur={() => setTimeout(this.props.closeProjectOptions, 200)}
|
||||
onBlur={this.onBlurComponent}
|
||||
onFocus={this.onFocusComponent}
|
||||
>
|
||||
<InlineSVG src={downArrowUrl} />
|
||||
</button>
|
||||
<ul className="sidebar__project-options">
|
||||
<li>
|
||||
<button aria-label="add folder" onClick={this.props.newFolder} >
|
||||
<button
|
||||
aria-label="add folder"
|
||||
onClick={() => {
|
||||
this.props.newFolder();
|
||||
setTimeout(this.props.closeProjectOptions, 0);
|
||||
}}
|
||||
onBlur={this.onBlurComponent}
|
||||
onFocus={this.onFocusComponent}
|
||||
>
|
||||
Add folder
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button aria-label="add file" onClick={this.props.newFile} >
|
||||
<button
|
||||
aria-label="add file"
|
||||
onClick={() => {
|
||||
this.props.newFile();
|
||||
setTimeout(this.props.closeProjectOptions, 0);
|
||||
}}
|
||||
onBlur={this.onBlurComponent}
|
||||
onFocus={this.onFocusComponent}
|
||||
>
|
||||
Add file
|
||||
</button>
|
||||
</li>
|
||||
|
|
|
@ -124,6 +124,7 @@ class Toolbar extends React.Component {
|
|||
</a>
|
||||
<input
|
||||
type="text"
|
||||
maxLength="256"
|
||||
className="toolbar__project-name-input"
|
||||
value={this.props.project.name}
|
||||
onChange={this.handleProjectNameChange}
|
||||
|
|
|
@ -202,14 +202,11 @@ class IDEView extends React.Component {
|
|||
>
|
||||
<Preferences
|
||||
fontSize={this.props.preferences.fontSize}
|
||||
indentationAmount={this.props.preferences.indentationAmount}
|
||||
setIndentation={this.props.setIndentation}
|
||||
indentWithSpace={this.props.indentWithSpace}
|
||||
indentWithTab={this.props.indentWithTab}
|
||||
isTabIndent={this.props.preferences.isTabIndent}
|
||||
setFontSize={this.props.setFontSize}
|
||||
autosave={this.props.preferences.autosave}
|
||||
linewrap={this.props.preferences.linewrap}
|
||||
setAutosave={this.props.setAutosave}
|
||||
setLinewrap={this.props.setLinewrap}
|
||||
lintWarning={this.props.preferences.lintWarning}
|
||||
setLintWarning={this.props.setLintWarning}
|
||||
textOutput={this.props.preferences.textOutput}
|
||||
|
@ -251,7 +248,9 @@ class IDEView extends React.Component {
|
|||
defaultSize="50%"
|
||||
onChange={() => { this.overlay.style.display = 'block'; }}
|
||||
onDragFinished={() => { this.overlay.style.display = 'none'; }}
|
||||
resizerStyle={{ marginRight: '0', marginLeft: '-10px' }}
|
||||
resizerStyle={{
|
||||
borderLeftWidth: '2px', borderRightWidth: '2px', width: '2px', margin: '0px 0px'
|
||||
}}
|
||||
>
|
||||
<SplitPane
|
||||
split="horizontal"
|
||||
|
@ -264,14 +263,13 @@ class IDEView extends React.Component {
|
|||
>
|
||||
<Editor
|
||||
lintWarning={this.props.preferences.lintWarning}
|
||||
linewrap={this.props.preferences.linewrap}
|
||||
lintMessages={this.props.editorAccessibility.lintMessages}
|
||||
updateLintMessage={this.props.updateLintMessage}
|
||||
clearLintMessage={this.props.clearLintMessage}
|
||||
file={this.props.selectedFile}
|
||||
updateFileContent={this.props.updateFileContent}
|
||||
fontSize={this.props.preferences.fontSize}
|
||||
indentationAmount={this.props.preferences.indentationAmount}
|
||||
isTabIndent={this.props.preferences.isTabIndent}
|
||||
files={this.props.files}
|
||||
editorOptionsVisible={this.props.ide.editorOptionsVisible}
|
||||
showEditorOptions={this.props.showEditorOptions}
|
||||
|
@ -511,9 +509,8 @@ IDEView.propTypes = {
|
|||
clearLintMessage: PropTypes.func.isRequired,
|
||||
preferences: PropTypes.shape({
|
||||
fontSize: PropTypes.number.isRequired,
|
||||
indentationAmount: PropTypes.number.isRequired,
|
||||
isTabIndent: PropTypes.bool.isRequired,
|
||||
autosave: PropTypes.bool.isRequired,
|
||||
linewrap: PropTypes.bool.isRequired,
|
||||
lintWarning: PropTypes.bool.isRequired,
|
||||
textOutput: PropTypes.bool.isRequired,
|
||||
gridOutput: PropTypes.bool.isRequired,
|
||||
|
@ -523,10 +520,8 @@ IDEView.propTypes = {
|
|||
}).isRequired,
|
||||
closePreferences: PropTypes.func.isRequired,
|
||||
setFontSize: PropTypes.func.isRequired,
|
||||
setIndentation: PropTypes.func.isRequired,
|
||||
indentWithTab: PropTypes.func.isRequired,
|
||||
indentWithSpace: PropTypes.func.isRequired,
|
||||
setAutosave: PropTypes.func.isRequired,
|
||||
setLinewrap: PropTypes.func.isRequired,
|
||||
setLintWarning: PropTypes.func.isRequired,
|
||||
setTextOutput: PropTypes.func.isRequired,
|
||||
setGridOutput: PropTypes.func.isRequired,
|
||||
|
|
|
@ -2,9 +2,8 @@ import * as ActionTypes from '../../../constants';
|
|||
|
||||
const initialState = {
|
||||
fontSize: 18,
|
||||
indentationAmount: 2,
|
||||
isTabIndent: true,
|
||||
autosave: true,
|
||||
linewrap: true,
|
||||
lintWarning: false,
|
||||
textOutput: false,
|
||||
gridOutput: false,
|
||||
|
@ -17,18 +16,10 @@ const preferences = (state = initialState, action) => {
|
|||
switch (action.type) {
|
||||
case ActionTypes.SET_FONT_SIZE:
|
||||
return Object.assign({}, state, { fontSize: action.value });
|
||||
case ActionTypes.SET_INDENTATION:
|
||||
return Object.assign({}, state, { indentationAmount: action.value });
|
||||
case ActionTypes.INDENT_WITH_TAB:
|
||||
return Object.assign({}, state, {
|
||||
isTabIndent: true
|
||||
});
|
||||
case ActionTypes.INDENT_WITH_SPACE:
|
||||
return Object.assign({}, state, {
|
||||
isTabIndent: false
|
||||
});
|
||||
case ActionTypes.SET_AUTOSAVE:
|
||||
return Object.assign({}, state, { autosave: action.value });
|
||||
case ActionTypes.SET_LINEWRAP:
|
||||
return Object.assign({}, state, { linewrap: action.value });
|
||||
case ActionTypes.SET_LINT_WARNING:
|
||||
return Object.assign({}, state, { lintWarning: action.value });
|
||||
case ActionTypes.SET_TEXT_OUTPUT:
|
||||
|
|
|
@ -17,6 +17,7 @@ $themes: (
|
|||
light: (
|
||||
logo-color: $p5js-pink,
|
||||
primary-text-color: #333,
|
||||
dropzone-text-color: #333,
|
||||
modal-button-color: #333,
|
||||
heading-text-color: #333,
|
||||
secondary-text-color: #a8a8a8,
|
||||
|
@ -36,7 +37,7 @@ $themes: (
|
|||
modal-background-color: #f4f4f4,
|
||||
modal-button-background-color: #e6e6e6,
|
||||
modal-border-color: rgba(17, 17, 17, 0.3),
|
||||
modal-boder-selected-color: #B9D0E1,
|
||||
modal-border-selected-color: #B9D0E1,
|
||||
icon-color: $icon-color,
|
||||
icon-hover-color: $icon-hover-color,
|
||||
icon-toast-hover-color: $white,
|
||||
|
@ -65,6 +66,7 @@ $themes: (
|
|||
dark: (
|
||||
logo-color: $p5js-pink,
|
||||
primary-text-color: $white,
|
||||
dropzone-text-color: $black,
|
||||
modal-button-color: $white,
|
||||
heading-text-color: $white,
|
||||
secondary-text-color: #DADADA,
|
||||
|
@ -112,6 +114,7 @@ $themes: (
|
|||
contrast: (
|
||||
logo-color: $yellow,
|
||||
primary-text-color: $yellow,
|
||||
dropzone-text-color: $black,
|
||||
modal-button-color: #333,
|
||||
heading-text-color: #e1e1e1,
|
||||
secondary-text-color: #e1e1e1,
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
}
|
||||
|
||||
.tooltipped-n::before,
|
||||
.tooltipped::before,
|
||||
.tooltipped::before
|
||||
{
|
||||
@include themify() {
|
||||
color: getThemifyVariable('button-background-hover-color');
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
.nav {
|
||||
height: #{42 / $base-font-size}rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
@include themify() {
|
||||
border-bottom: 1px dashed map-get($theme-map, 'inactive-text-color');
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
@include themify() {
|
||||
border-bottom: 1px dashed map-get($theme-map, 'inactive-text-color');
|
||||
}
|
||||
|
||||
& button {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.nav__items-left, .nav__items-right {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
.nav__items-left,
|
||||
.nav__items-right {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
@ -29,20 +32,23 @@
|
|||
}
|
||||
|
||||
.nav__item {
|
||||
position: relative;
|
||||
padding: 0 #{10 / $base-font-size}rem;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
|
||||
& button {
|
||||
padding: #{12 / $base-font-size}rem #{10 / $base-font-size}rem;
|
||||
}
|
||||
}
|
||||
|
||||
.nav__item:first-child {
|
||||
padding-left: #{15 / $base-font-size}rem;
|
||||
padding-left: #{15 / $base-font-size}rem;
|
||||
}
|
||||
|
||||
.nav__item:last-child {
|
||||
padding-right: #{15 / $base-font-size}rem;
|
||||
padding-right: #{15 / $base-font-size}rem;
|
||||
}
|
||||
|
||||
.nav__item-header {
|
||||
|
@ -55,50 +61,57 @@
|
|||
color: getThemifyVariable('nav-hover-color');
|
||||
}
|
||||
}
|
||||
|
||||
.nav__item-header-triangle polygon {
|
||||
@include themify() {
|
||||
@include themify() {
|
||||
fill: getThemifyVariable('nav-hover-color');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav__dropdown {
|
||||
@include themify() {
|
||||
background-color: map-get($theme-map, 'modal-background-color');
|
||||
border: 1px solid map-get($theme-map, 'modal-border-color');
|
||||
box-shadow: 0 0 18px 0 getThemifyVariable('shadow-color');
|
||||
@include themify() {
|
||||
background-color: map-get($theme-map, 'modal-background-color');
|
||||
border: 1px solid map-get($theme-map, 'modal-border-color');
|
||||
box-shadow: 0 0 18px 0 getThemifyVariable('shadow-color');
|
||||
color: getThemifyVariable('dropdown-color');
|
||||
}
|
||||
}
|
||||
|
||||
display: none;
|
||||
text-align: left;
|
||||
width: #{180 / $base-font-size}rem;
|
||||
.nav__item--open & {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
flex-direction: column;
|
||||
top: 4px;
|
||||
left: 0;
|
||||
height: auto;
|
||||
}
|
||||
text-align: left;
|
||||
width: #{180 / $base-font-size}rem;
|
||||
|
||||
.nav__item--open & {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
flex-direction: column;
|
||||
top: #{40 / $base-font-size}rem;
|
||||
left: 0;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
z-index: 9999;
|
||||
border-radius: #{6 / $base-font-size}rem;
|
||||
border-top-left-radius: 0px;
|
||||
}
|
||||
|
||||
.nav__items-right {
|
||||
padding-right: #{20 / $base-font-size}rem;
|
||||
|
||||
& .nav__dropdown {
|
||||
width: #{121 / $base-font-size}rem;
|
||||
}
|
||||
}
|
||||
|
||||
.nav__item-spacer {
|
||||
@include themify() {
|
||||
color: map-get($theme-map, 'inactive-text-color');
|
||||
@include themify() {
|
||||
color: map-get($theme-map, 'inactive-text-color');
|
||||
margin: 0 #{8 / $base-font-size}rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav__dropdown a, button {
|
||||
.nav__dropdown a,
|
||||
button {
|
||||
@include themify() {
|
||||
color: getThemifyVariable('secondary-text-color');
|
||||
}
|
||||
|
@ -116,32 +129,37 @@
|
|||
|
||||
.nav__dropdown-heading {
|
||||
@include themify() {
|
||||
border-bottom: 1px dashed map-get($theme-map, 'inactive-text-color');
|
||||
border-bottom: 1px dashed map-get($theme-map, 'inactive-text-color');
|
||||
}
|
||||
|
||||
height: #{(42 - 5) / $base-font-size}rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 0 #{16 / $base-font-size}rem;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
span {
|
||||
@include themify() {
|
||||
color: getThemifyVariable('nav-hover-color');
|
||||
}
|
||||
}
|
||||
|
||||
polygon {
|
||||
@include themify() {
|
||||
@include themify() {
|
||||
fill: getThemifyVariable('nav-hover-color');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav__dropdown-heading a, .nav__dropdown-heading a:hover {
|
||||
.nav__dropdown-heading a,
|
||||
.nav__dropdown-heading a:hover {
|
||||
@include themify() {
|
||||
color: getThemifyVariable('inactive-text-color');
|
||||
}
|
||||
|
||||
cursor: default;
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -158,24 +176,30 @@
|
|||
align-items: center;
|
||||
padding: 0 #{16 / $base-font-size}rem;
|
||||
cursor: pointer;
|
||||
& button, & a {
|
||||
|
||||
& button,
|
||||
& a {
|
||||
@include themify() {
|
||||
color: getThemifyVariable('dropdown-color');
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@include themify() {
|
||||
background-color: getThemifyVariable('button-background-hover-color');
|
||||
color: getThemifyVariable('button-hover-color')
|
||||
}
|
||||
& button, & a {
|
||||
|
||||
& button,
|
||||
& a {
|
||||
@include themify() {
|
||||
color: getThemifyVariable('button-hover-color');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& button, & a {
|
||||
& button,
|
||||
& a {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
|
@ -185,7 +209,10 @@
|
|||
}
|
||||
|
||||
.nav__dropdown-item:last-child {
|
||||
border-radius: 0 0 #{6 / $base-font-size}rem #{6 / $base-font-size}rem;
|
||||
border-radius: 0 0 #{5 / $base-font-size}rem #{5 / $base-font-size}rem;
|
||||
}
|
||||
.nav__dropdown-item:first-child {
|
||||
border-radius: 0 #{5 / $base-font-size}rem 0 0;
|
||||
}
|
||||
|
||||
.nav__announce {
|
||||
|
@ -207,17 +234,28 @@
|
|||
position: relative;
|
||||
height: #{42 / $base-font-size}rem;
|
||||
width: #{56 / $base-font-size}rem;
|
||||
|
||||
& span {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
.svg__logo g > path {
|
||||
@include themify() {
|
||||
fill: getThemifyVariable('logo-color');
|
||||
}
|
||||
}
|
||||
.svg__logo g g:first-of-type path {
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.nav__keyboard-shortcut {
|
||||
font-size: #{12 / $base-font-size}rem;
|
||||
font-family: Inconsololata, monospace;
|
||||
|
||||
@include themify() {
|
||||
color: getThemifyVariable('keyboard-shortcut-color');
|
||||
}
|
||||
|
||||
.nav__dropdown-item:hover & {
|
||||
@include themify() {
|
||||
color: getThemifyVariable('button-hover-color');
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
.dropzone {
|
||||
color: $primary-text-color;
|
||||
@include themify() {
|
||||
color: getThemifyVariable('dropzone-text-color');
|
||||
}
|
||||
}
|
||||
|
||||
.uploader {
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
@import 'components/keyboard-shortcuts';
|
||||
@import 'components/copyable-input';
|
||||
@import 'components/feedback';
|
||||
@import 'components/uploader';
|
||||
|
||||
@import 'layout/ide';
|
||||
@import 'layout/fullscreen';
|
||||
|
|
|
@ -73,8 +73,8 @@ export function validateSignup(formProps) {
|
|||
errors.confirmPassword = 'Please enter a password confirmation';
|
||||
}
|
||||
|
||||
if (formProps.password !== formProps.confirmPassword) {
|
||||
errors.password = 'Passwords must match';
|
||||
if (formProps.password !== formProps.confirmPassword && formProps.confirmPassword) {
|
||||
errors.confirmPassword = 'Passwords must match';
|
||||
}
|
||||
|
||||
return errors;
|
||||
|
|
|
@ -29,6 +29,8 @@ These are the steps that happen when you deploy the application.
|
|||
|
||||
You'll only need to do this if you're testing the production environment locally.
|
||||
|
||||
_Note_: The installation steps assume you are using a Unix-like shell. If you are using Windows, you will need to use `copy` instead of `cp`.
|
||||
|
||||
1. Clone this repository and `cd` into it
|
||||
2. `$ npm install`
|
||||
3. Install MongoDB and make sure it is running
|
||||
|
|
|
@ -4,6 +4,8 @@ Follow these instructions to set up your development environment, which you need
|
|||
|
||||
## Manual Installation
|
||||
|
||||
_Note_: The installation steps assume you are using a Unix-like shell. If you are using Windows, you will need to use `copy` instead of `cp`.
|
||||
|
||||
1. Install [node.js](http://nodejs.org/), which also automatically installs the [npm](https://www.npmjs.org) package manager.
|
||||
2. [Fork](https://help.github.com/articles/fork-a-repo) the [p5.js Web Editor repository](https://github.com/processing/p5.js-web-editor) into your own GitHub account.
|
||||
3. [Clone](https://help.github.com/articles/cloning-a-repository/) your new fork of the repository from GitHub onto your local computer.
|
||||
|
@ -31,6 +33,8 @@ Follow these instructions to set up your development environment, which you need
|
|||
|
||||
## Docker Installation
|
||||
|
||||
_Note_: The installation steps assume you are using a Unix-like shell. If you are using Windows, you will need to use `copy` instead of `cp`.
|
||||
|
||||
Using Docker, you can have a complete, consistent development environment without having to manually install dependencies such as Node, Mongo, etc. It also helps isolate these dependencies and their data from other projects that you may have on the same computer that use different/conflicting versions, etc.
|
||||
|
||||
Note that this takes up a significant amount of space on your machine. Make sure you have at least 5GB free.
|
||||
|
@ -59,7 +63,7 @@ If you don't have the full server environment running, you can launch a one-off
|
|||
|
||||
## S3 Bucket Configuration
|
||||
|
||||
Note that this is optional, unless you are working on the part of the application that allows a user to upload images, videos, etc. Please refer to the folllowing [gist](https://gist.github.com/catarak/70c9301f0fd1ac2d6b58de03f61997e3) to set up an S3 bucket to be used with this project.
|
||||
Note that this is optional, unless you are working on the part of the application that allows a user to upload images, videos, etc. Please refer to the following [gist](https://gist.github.com/catarak/70c9301f0fd1ac2d6b58de03f61997e3) to set up an S3 bucket to be used with this project.
|
||||
|
||||
If your S3 bucket is in the US East (N Virginia) region (us-east-1), you'll
|
||||
need to set a custom URL base for it, because it does not follow the standard
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Preparing a pull request
|
||||
|
||||
Copied from the [p5.js repository](https://github.com/processing/p5.js).
|
||||
Copied and updated from the [p5.js repository](https://github.com/processing/p5.js).
|
||||
|
||||
Pull-requests are easier when your code is up to date! You can use git rebase to update your code to incorporate changes from other contributors. Here's how.
|
||||
|
||||
|
@ -31,17 +31,19 @@ Then ask git about the latest changes.
|
|||
### Apply changes from master branch, adds your changes *after*
|
||||
git rebase upstream/master
|
||||
|
||||
### Switches back to master branch
|
||||
git checkout master
|
||||
|
||||
### Helps other contributors fully understand the changes that you made
|
||||
git commit -m "Fixed documentation typos"
|
||||
|
||||
### Verifies what git will be committing
|
||||
git status
|
||||
|
||||
## CONFLICTS
|
||||
You will probably have some conflicts!
|
||||
If it’s just lib/p5.js and lib/p5.min.js, it’s easy to fix. just build the project again with grunt.
|
||||
|
||||
grunt
|
||||
git add -u
|
||||
git rebase --continue
|
||||
|
||||
If you have conflicts in other files & you're not sure how to resolve them... ask for help! Lauren, David, Kevin, and Kate are familiar with recent changes and can help you figure out what's new.
|
||||
You may have some conflicts! It's okay. Feel free to ask for help. If merging with the latest upstream master causes conflicts, you can always make a pull request with the upstream repository, which makes the merge conflicts public.
|
||||
|
||||
## And finally, for great glory
|
||||
git push origin
|
||||
git push --set-upstream origin your-branch-name-backup
|
||||
|
||||
Here's a good reference on rebasing, in case you're intensely curious about the technical details. https://www.atlassian.com/git/tutorials/merging-vs-rebasing
|
|
@ -110,7 +110,9 @@ export function getProject(req, res) {
|
|||
function deleteFilesFromS3(files) {
|
||||
deleteObjectsFromS3(files.filter((file) => {
|
||||
if (file.url) {
|
||||
if (!process.env.S3_DATE || (process.env.S3_DATE && isBefore(new Date(process.env.S3_DATE), new Date(file.createdAt)))) {
|
||||
if (!process.env.S3_DATE || (
|
||||
process.env.S3_DATE &&
|
||||
isBefore(new Date(process.env.S3_DATE), new Date(file.createdAt)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ objectsResponse.on('end', () => {
|
|||
// // console.log('is selected remains');
|
||||
// // }
|
||||
|
||||
// // if (file.isSelctedFile) {
|
||||
// // if (file.isSelectedFile) {
|
||||
// // console.log('changed to isSelected file');
|
||||
// // }
|
||||
// project.save((err, savedProject) => {
|
||||
|
|
|
@ -27,6 +27,7 @@ const userSchema = new Schema({
|
|||
indentationAmount: { type: Number, default: 2 },
|
||||
isTabIndent: { type: Boolean, default: false },
|
||||
autosave: { type: Boolean, default: true },
|
||||
linewrap: { type: Boolean, default: true },
|
||||
lintWarning: { type: Boolean, default: false },
|
||||
textOutput: { type: Boolean, default: false },
|
||||
gridOutput: { type: Boolean, default: false },
|
||||
|
|
Loading…
Reference in a new issue