diff --git a/client/images/information.svg b/client/images/information.svg new file mode 100644 index 00000000..e3642f56 --- /dev/null +++ b/client/images/information.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/client/modules/IDE/components/Preferences.jsx b/client/modules/IDE/components/Preferences.jsx index 24203322..a55c63cf 100644 --- a/client/modules/IDE/components/Preferences.jsx +++ b/client/modules/IDE/components/Preferences.jsx @@ -1,15 +1,14 @@ import React, { PropTypes } from 'react'; import InlineSVG from 'react-inlinesvg'; -import classNames from 'classnames'; +import { Tab, Tabs, TabList, TabPanel } from 'react-tabs'; // import { bindActionCreators } from 'redux'; // import { connect } from 'react-redux'; // import * as PreferencesActions from '../actions/preferences'; -const exitUrl = require('../../../images/exit.svg'); const plusUrl = require('../../../images/plus.svg'); const minusUrl = require('../../../images/minus.svg'); const beepUrl = require('../../../sounds/audioAlert.mp3'); -// import { debounce } from 'lodash'; +const infoUrl = require('../../../images/information.svg'); class Preferences extends React.Component { constructor(props) { @@ -48,264 +47,289 @@ class Preferences extends React.Component { render() { const beep = new Audio(beepUrl); - const preferencesContainerClass = classNames({ - 'preferences': true, - 'preferences--selected': this.props.isVisible - }); return ( -
-
-

Preferences

- -
+
+ + +
+

General Settings

+

Sketch Settings

+

Accessibility

+
+
+ +
+

Theme

+
+ this.props.setTheme('light')} + aria-label="light theme on" + name="light theme" + id="light-theme-on" + className="preference__radio-button" + value="light" + checked={this.props.theme === 'light'} + /> + + this.props.setTheme('dark')} + aria-label="dark theme on" + name="dark theme" + id="dark-theme-on" + className="preference__radio-button" + value="dark" + checked={this.props.theme === 'dark'} + /> + + this.props.setTheme('contrast')} + aria-label="high contrast theme on" + name="high contrast theme" + id="high-contrast-theme-on" + className="preference__radio-button" + value="contrast" + checked={this.props.theme === 'contrast'} + /> + +
+
+
+

Text size

+ + { this.fontSizeInput = element; }} + onClick={() => { + this.fontSizeInput.select(); + }} + > + + +
+
+

Indentation amount

+ + { this.indentationInput = element; }} + onClick={() => { + this.indentationInput.select(); + }} + > + + + + + + +
+
+

Autosave

+
+ this.props.setAutosave(true)} + aria-label="autosave on" + name="autosave" + id="autosave-on" + className="preference__radio-button" + value="On" + checked={this.props.autosave} + /> + + this.props.setAutosave(false)} + aria-label="autosave off" + name="autosave" + id="autosave-off" + className="preference__radio-button" + value="Off" + checked={!this.props.autosave} + /> + +
+
+
+ + {/*
+

Add a p5.js or an external library

+
*/} +
+

Security Protocol

+
+ { + this.props.setServeSecure(event.target.checked); + }} + /> + + + + +
+
+
+ +
+

Lint warning sound

+
+ this.props.setLintWarning(true)} + aria-label="lint warning on" + name="lint warning" + id="lint-warning-on" + className="preference__radio-button" + value="On" + checked={this.props.lintWarning} + /> + + this.props.setLintWarning(false)} + aria-label="lint warning off" + name="lint warning" + id="lint-warning-off" + className="preference__radio-button" + value="Off" + checked={!this.props.lintWarning} + /> + + +
+
+
+

Accessible text-based canvas

+
Used with screen reader
-
-

Text size

- - { this.fontSizeInput = element; }} - onClick={() => { - this.fontSizeInput.select(); - }} - > - - -
- -
-

Indentation amount

- - { this.indentationInput = element; }} - onClick={() => { - this.indentationInput.select(); - }} - > - - -
- - - - -
-
-
-

Autosave

-
- this.props.setAutosave(true)} - aria-label="autosave on" - name="autosave" - id="autosave-on" - className="preference__radio-button" - value="On" - checked={this.props.autosave} - /> - - this.props.setAutosave(false)} - aria-label="autosave off" - name="autosave" - id="autosave-off" - className="preference__radio-button" - value="Off" - checked={!this.props.autosave} - /> - -
-
-
-

Theme

-
- this.props.setTheme('light')} - aria-label="light theme on" - name="light theme" - id="light-theme-on" - className="preference__radio-button" - value="light" - checked={this.props.theme === 'light'} - /> - - this.props.setTheme('dark')} - aria-label="dark theme on" - name="dark theme" - id="dark-theme-on" - className="preference__radio-button" - value="dark" - checked={this.props.theme === 'dark'} - /> - - this.props.setTheme('contrast')} - aria-label="contrast theme on" - name="contrast theme" - id="contrast-theme-on" - className="preference__radio-button" - value="contrast" - checked={this.props.theme === 'contrast'} - /> - -
-
-
-

Lint warning sound

-
- this.props.setLintWarning(true)} - aria-label="lint warning on" - name="lint warning" - id="lint-warning-on" - className="preference__radio-button" - value="On" - checked={this.props.lintWarning} - /> - - this.props.setLintWarning(false)} - aria-label="lint warning off" - name="lint warning" - id="lint-warning-off" - className="preference__radio-button" - value="Off" - checked={!this.props.lintWarning} - /> - - -
-
-
-

Accessible text-based canvas

-
Used with screen reader
- -
- { - this.props.setTextOutput(event.target.checked); - }} - aria-label="text output on" - name="text output" - id="text-output-on" - value="On" - checked={(this.props.textOutput)} - /> - - { - this.props.setGridOutput(event.target.checked); - }} - aria-label="table output on" - name="table output" - id="table-output-on" - value="On" - checked={(this.props.gridOutput)} - /> - - { - this.props.setSoundOutput(event.target.checked); - }} - aria-label="sound output on" - name="sound output" - id="sound-output-on" - value="On" - checked={(this.props.soundOutput)} - /> - -
-
+
+ { + this.props.setTextOutput(event.target.checked); + }} + aria-label="text output on" + name="text output" + id="text-output-on" + value="On" + checked={(this.props.textOutput)} + /> + + { + this.props.setGridOutput(event.target.checked); + }} + aria-label="table output on" + name="table output" + id="table-output-on" + value="On" + checked={(this.props.gridOutput)} + /> + + { + this.props.setSoundOutput(event.target.checked); + }} + aria-label="sound output on" + name="sound output" + id="sound-output-on" + value="On" + checked={(this.props.soundOutput)} + /> + +
+
+
+
); } } Preferences.propTypes = { - isVisible: PropTypes.bool.isRequired, - closePreferences: PropTypes.func.isRequired, fontSize: PropTypes.number.isRequired, indentationAmount: PropTypes.number.isRequired, setIndentation: PropTypes.func.isRequired, @@ -324,7 +348,13 @@ Preferences.propTypes = { lintWarning: PropTypes.bool.isRequired, setLintWarning: PropTypes.func.isRequired, theme: PropTypes.string.isRequired, + serveSecure: PropTypes.bool.isRequired, + setServeSecure: PropTypes.func.isRequired, setTheme: PropTypes.func.isRequired }; +Preferences.defaultProps = { + currentUser: undefined +}; + export default Preferences; diff --git a/client/modules/IDE/pages/IDEView.jsx b/client/modules/IDE/pages/IDEView.jsx index 3d5baa71..a9dac23c 100644 --- a/client/modules/IDE/pages/IDEView.jsx +++ b/client/modules/IDE/pages/IDEView.jsx @@ -246,29 +246,37 @@ class IDEView extends React.Component { currentUser={this.props.user.username} showHelpModal={this.props.showHelpModal} /> - + {this.props.ide.preferencesIsVisible && + + + + }
{ this.overlay = element; }}>
- {(() => { - if ( + {( ( (this.props.preferences.textOutput || - this.props.preferences.gridOutput || - this.props.preferences.soundOutput - ) && this.props.ide.isPlaying - ) || this.props.ide.isAccessibleOutputPlaying) { - return ( - - ); - } - return ''; - })()} + this.props.preferences.gridOutput || + this.props.preferences.soundOutput + ) && + this.props.ide.isPlaying + ) || + this.props.ide.isAccessibleOutputPlaying + ) && + + }
- {(() => { - if (this.props.ide.modalIsVisible) { - return ( - - ); - } - return ''; - })()} - {(() => { - if (this.props.ide.newFolderModalVisible) { - return ( - - ); - } - return ''; - })()} - {(() => { // eslint-disable-line - if (this.props.location.pathname.match(/sketches$/)) { - return ( - - - - ); - } - })()} - {(() => { // eslint-disable-line - if (this.props.location.pathname.match(/assets$/)) { - return ( - - - - ); - } - })()} - {(() => { // eslint-disable-line - if (this.props.location.pathname === '/about') { - return ( - - - - ); - } - })()} - {(() => { // eslint-disable-line - if (this.props.ide.shareModalVisible) { - return ( - - - - ); - } - })()} - {(() => { // eslint-disable-line - if (this.props.ide.keyboardShortcutVisible) { - return ( - - - - ); - } - })()} - {(() => { // eslint-disable-line - if (this.props.ide.errorType) { - return ( - - - - ); - } - })()} - {(() => { // eslint-disable-line - if (this.props.ide.helpType) { - return ( - - - - ); - } - })()} + { this.props.ide.modalIsVisible && + + } + { this.props.ide.newFolderModalVisible && + + } + { this.props.location.pathname.match(/sketches$/) && + + + + } + { this.props.location.pathname.match(/assets$/) && + + + + } + { this.props.location.pathname === '/about' && + + + + } + { this.props.ide.shareModalVisible && + + + + } + { this.props.ide.keyboardShortcutVisible && + + + + } + { this.props.ide.errorType && + + + + } + { this.props.ide.helpType && + + + + } ); } diff --git a/client/styles/components/_copyable-input.scss b/client/styles/components/_copyable-input.scss index f19bfe61..35b36db7 100644 --- a/client/styles/components/_copyable-input.scss +++ b/client/styles/components/_copyable-input.scss @@ -40,7 +40,7 @@ color: getThemifyVariable('button-hover-color'); } font-family: Montserrat, sans-serif; - font-size: #{14 / $base-font-size}rem; + font-size: #{12 / $base-font-size}rem; } .tooltipped-n::before, diff --git a/client/styles/components/_overlay.scss b/client/styles/components/_overlay.scss index de02a35f..6932b4ae 100644 --- a/client/styles/components/_overlay.scss +++ b/client/styles/components/_overlay.scss @@ -29,7 +29,7 @@ .overlay__header { display: flex; justify-content: space-between; - padding: #{30 / $base-font-size}rem #{20 / $base-font-size}rem #{30 / $base-font-size}rem #{20 / $base-font-size}rem; + padding: #{20 / $base-font-size}rem; flex: 1 0 auto; } diff --git a/client/styles/components/_preferences.scss b/client/styles/components/_preferences.scss index d45adebb..3f77e40a 100644 --- a/client/styles/components/_preferences.scss +++ b/client/styles/components/_preferences.scss @@ -1,153 +1,264 @@ .preferences { - @extend %modal; - position: absolute; - top: #{51 / $base-font-size}rem; - right: #{29 / $base-font-size}rem; - width: #{288 / $base-font-size}rem; - display: none; - padding: #{14 / $base-font-size}rem #{20 / $base-font-size}rem #{2 / $base-font-size}rem #{20 / $base-font-size}rem ; - &--selected { - display: flex; - flex-direction: column; - } - @include themify() { - background-color: getThemifyVariable('editor-gutter-color'); - } - outline: none; + width: 100%; + width: #{640 / $base-font-size}rem; + max-width: 100%; + min-height: #{460 / $base-font-size}rem; + max-height: 100%; + z-index: 9999; + padding: 0 #{20 / $base-font-size}rem #{2 / $base-font-size}rem #{20 / $base-font-size}rem ; + display: flex; + flex-direction: column; + outline: none; } .preferences__exit-button { - @include icon(); - padding-top: #{5 / $base-font-size}rem; - margin-right: #{-6 / $base-font-size}rem; + @include icon(); + padding-top: #{5 / $base-font-size}rem; + margin-right: #{-6 / $base-font-size}rem; } .preference__minus-button, .preference__plus-button { - @include themify() { - @extend %preferences-button; - width: #{32 / $base-font-size}rem; - height: #{32 / $base-font-size}rem; - margin-left: #{6 / $base-font-size}rem; - line-height: #{40 / $base-font-size}rem; - & svg { - width: #{10 / $base-font-size}rem; - } - } + @include themify() { + @extend %preferences-button; + width: #{32 / $base-font-size}rem; + height: #{32 / $base-font-size}rem; + margin-left: #{6 / $base-font-size}rem; + margin-right: #{10 / $base-font-size}rem; + line-height: #{40 / $base-font-size}rem; + & svg { + width: #{10 / $base-font-size}rem; + } + } +} + +.serve__over__https { + text-align: center; + margin-left: #{9 / $base-font-size}rem; + font-width: #{108 / $base-font-size}rem; + font-height: #{15 / $base-font-size}rem; + font-family: Montserrat; + font-size: #{12 / $base-font-size}rem; + margin-top: #{2 / $base-font-size}rem; } .preferences__heading { - display: flex; - flex-direction: row; - justify-content: space-between; - margin-bottom: #{20 / $base-font-size}rem; - @include themify() { - color: getThemifyVariable('heading-text-color'); - } + display: flex; + flex-direction: row; + justify-content: space-between; + @include themify() { + color: getThemifyVariable('heading-text-color'); + } +} + +.preferences__title{ + width: #{90 / $base-font-size}rem; + height: #{25 / $base-font-size}rem; + font-family: Montserrat; + font-size: #{21 / $base-font-size}rem; + font-weight: bold; + text-align: left; +} + +.preference__subheadings { + display: flex; + flex-wrap: wrap; + padding-bottom: #{0.1 / $base-font-size}rem; + @include themify() { + border-bottom: 1px solid getThemifyVariable('button-border-color'); + } } .preference { - display: flex; - flex-wrap: wrap; - padding-bottom: #{12 / $base-font-size}rem; - & + & { - @include themify() { - border-top: 1px dashed getThemifyVariable('button-border-color'); - } - } + display: flex; + flex-wrap: wrap; + padding-bottom: #{12 / $base-font-size}rem; + & + & { + @include themify() { + border-top: 1px dashed getThemifyVariable('button-border-color'); + } + } } .preference__title { - width: 100%; - font-size: #{16 / $base-font-size}rem; - margin-top: #{13 / $base-font-size}rem; - margin-bottom: #{7 / $base-font-size}rem; - @include themify() { - color: getThemifyVariable('heading-text-color'); - } + width: 100%; + font-size: #{16 / $base-font-size}rem; + margin-top: #{13 / $base-font-size}rem; + margin-bottom: #{7 / $base-font-size}rem; + @include themify() { + color: getThemifyVariable('heading-text-color'); + } } .preference__subtitle { - @include themify() { - color: getThemifyVariable('inactive-text-color'); - } - width: 100%; - margin-bottom: #{10 / $base-font-size}rem; - margin-top: 0; + @include themify() { + color: getThemifyVariable('inactive-text-color'); + } + width: 100%; + margin-bottom: #{10 / $base-font-size}rem; + margin-top: 0; } .preference__value { - @include themify() { - border: #{1 / $base-font-size}rem solid getThemifyVariable('button-border-color'); - background-color: getThemifyVariable('button-background-color'); - color: getThemifyVariable('input-text-color'); - } - text-align: center; - border-radius: 0%; - outline: none; - width: #{44 / $base-font-size}rem; - height: #{40 / $base-font-size}rem; - margin: 0 #{26 / $base-font-size}rem; - padding: 0; - font-size: #{16 / $base-font-size}rem; - font-family: Inconsolata; + @include themify() { + border: #{1 / $base-font-size}rem solid getThemifyVariable('button-border-color'); + background-color: getThemifyVariable('button-background-color'); + color: getThemifyVariable('input-text-color'); + } + text-align: center; + border-radius: 0%; + outline: none; + width: #{44 / $base-font-size}rem; + height: #{40 / $base-font-size}rem; + margin: 0 #{20 / $base-font-size}rem; + padding: 0; + font-size: #{16 / $base-font-size}rem; + font-family: Inconsolata; } .preference__label { - @include themify() { - color: getThemifyVariable('inactive-text-color'); - &:hover { - color: getThemifyVariable('primary-text-color'); - } - } - margin: #{-15 / $base-font-size}rem 0 0 #{-5 / $base-font-size}rem; - font-size: #{9 / $base-font-size}rem; - width: #{44 / $base-font-size}rem; + @include themify() { + color: getThemifyVariable('inactive-text-color'); + &:hover { + color: getThemifyVariable('primary-text-color'); + } + + } + margin: #{-15 / $base-font-size}rem 0 0 #{-5 / $base-font-size}rem; + font-size: #{9 / $base-font-size}rem; + width: #{44 / $base-font-size}rem; +} + +.react-tabs__tab--selected { + @include themify() { + border-bottom: #{4 / $base-font-size}rem solid getThemifyVariable('button-background-hover-color'); + } +} + +.react-tabs__tab--selected .preference__subheading { + @include themify() { + color: getThemifyVariable('primary-text-color'); + } +} + +.react-tabs__tab { + text-align: center; + color: black; + display: flex; + align-items: center; + border-bottom: #{4 / $base-font-size}rem solid transparent; + & + & { + margin-left: #{45 / $base-font-size}rem; + } +} + +.preference__subheading { + @include themify() { + color: getThemifyVariable('inactive-text-color'); + &:hover, &:focus{ + color: getThemifyVariable('primary-text-color'); + cursor: pointer; + } + &:focus { + color: getThemifyVariable('primary-text-color'); + cursor: pointer; + } + } + font-size: #{12 / $base-font-size}rem; + height: #{20 / $base-font-size}rem; + width: 100%; + margin: 0; + padding: 0 #{5 /$base-font-size}rem; } .preference__vertical-list { - display: flex; - flex-direction: column; - width: #{44 / $base-font-size}rem; - padding-left: #{25 / $base-font-size}rem; + display: flex; + flex-direction: column; + width: #{44 / $base-font-size}rem; + padding-left: #{25 / $base-font-size}rem; +} + +.preference__add__resource { + font-size: #{14 / $base-font-size}rem; + line-height: 1.43; + text-align: left; + margin-left: #{5 / $base-font-size}rem; + margin-top: #{40 / $base-font-size}rem; + margin-bottom: #{10 / $base-font-size}rem; + @include themify() { + color: getThemifyVariable('inactive-text-color'); + border-bottom: 1px dashed getThemifyVariable('button-border-color'); + } } .preference__radio-button { - @extend %hidden-element; + @extend %hidden-element; } .preference__option { - @include themify() { - @extend %preference-option; - padding-right: #{44 / $base-font-size}rem; - } + @include themify() { + @extend %preference-option; + margin-right: #{25 / $base-font-size}rem; + } + display: flex; + flex-wrap: wrap; + flex-direction: row; } .preference__option:last-child { - padding-right: 0; + margin-right: 0; } .preference__preview-button { - @include themify() { - @extend %preference-option; - } + @include themify() { + @extend %preference-option; + &:hover { + color: getThemifyVariable('button-background-hover-color'); + } + } + margin-left: #{30 / $base-font-size}rem; +} + +.preference__option.preference__whitespace-button { + padding-top: #{8 / $base-font-size}rem; + margin-right: 0; + margin-left: #{25 / $base-font-size}rem; } .preference__options { - display: flex; + display: flex; + justify-content: center; } .preference__radio-button:checked + .preference__option { - @include themify() { - //for some reason this won't work for getThemifyVariable - color: map-get($theme-map, 'primary-text-color'); - } + @include themify() { + //for some reason this won't work for getThemifyVariable + color: map-get($theme-map, 'primary-text-color'); + } } .preference--hidden { - @extend %hidden-element; + @extend %hidden-element; } .preference__option.preference__canvas:not(:last-child) { - padding-right: #{14 / $base-font-size}rem; + padding-right: #{14 / $base-font-size}rem; +} + +.preference__serve-secure { + display: flex; + align-items: center; +} + +.serve-secure__icon { + @include icon(); + & svg { + height: #{24 / $base-font-size}rem; + width: #{24 / $base-font-size}rem; + } +} + +.serve-secture__tooltip:after { + text-align: left; + font-size: #{12 / $base-font-size}rem; } diff --git a/package.json b/package.json index fb3338c9..afebb2c6 100644 --- a/package.json +++ b/package.json @@ -111,6 +111,7 @@ "react-redux": "^4.4.5", "react-router": "^2.6.0", "react-split-pane": "^0.1.44", + "react-tabs": "^1.1.0", "redux": "^3.5.2", "redux-devtools": "^3.3.1", "redux-devtools-dock-monitor": "^1.1.1",