diff --git a/src/components/Settings.jsx b/src/components/Settings.jsx index 6286448..31e3658 100644 --- a/src/components/Settings.jsx +++ b/src/components/Settings.jsx @@ -1,32 +1,21 @@ import { h, Component } from 'preact'; import { editorThemes } from '../editorThemes'; +import Switch from './Switch'; +import Tabs, { TabPanel } from './Tabs'; +import { Divider } from './common'; -function CheckboxSetting({ - title, - label, - onChange, - pref, - name, - showWhenExtension -}) { +function CheckboxSetting({ label, onChange, pref }) { return ( - + ); } export default class Settings extends Component { - updateSetting(e) { - this.props.onChange(e); + updateSetting(e, settingName) { + const value = + e.target.type === 'checkbox' ? e.target.checked : e.target.value; + this.props.onChange(settingName, value); } shouldComponentUpdate() { // TODO: add check on prefs @@ -38,304 +27,335 @@ export default class Settings extends Component {

Settings

-

Indentation

-
- - -
- - -
- -

Editor

-
-
- -
- - - -
- - - -
- Key bindings - - -
-
-
+ + - - - - - this.updateSetting(e, 'preserveLastCode')} /> +

+ Loads the last open creation when app starts +

+ - - this.updateSetting(e, 'lightVersion')} /> -
-
+

+ Switch to lighter version for better performance. Removes things + like blur etc. +

+ + this.updateSetting(e, 'autoPreview')} + /> +

+ Refreshes the preview as you code. Otherwise use the 'Run' button +

+ + this.updateSetting(e, 'autoSave')} + /> +

+ Auto-save keeps saving your code at regular intervals after you + hit save manually the first time +

+ + this.updateSetting(e, 'refreshOnResize')} + /> +

+ Preview will refresh when you resize the preview pane +

+
+ + this.updateSetting(e, 'replaceNewTab')} + showWhenExtension + /> +

+ Turning this on will start showing Web Maker in every new tab + you open +

+
+ + this.updateSetting(e, 'preserveConsoleLogs')} + /> +

+ Preserves the console logs across your preview refreshes +

+ + +
+
+ + +
+
+ +
+ +
+
+
+ Default Preprocessors +
+ + + +
+
+ + + -
+ + -

Fun

-

- +

+ this.updateSetting(e, 'fontSize')} + />{' '} + px +
+ + - -

+
+ Key bindings +
+ + +
+
+
+ -
+
+ this.updateSetting(e, 'lineWrap')} + /> + -

Advanced

-

- -

- If any loop iteration takes more than the defined time, it is - detected as a potential infinite loop and further iterations are - stopped. -
-

+ this.updateSetting(e, 'autoComplete')} + /> +
+
+
+ + this.updateSetting(e, 'isCodeBlastOn')} + /> +

+ Enjoy wonderful particle blasts while you type +

+ + this.updateSetting(e, 'isJs13kModeOn')} + /> +

+ Make the app ready to build some games for{' '} + + Js13kGames + . +

+
+ +
+ +

+ If any loop iteration takes more than the defined time, it is + detected as a potential infinite loop and further iterations are + stopped. +

+
+ -

- -

+
+ +
+
+
); } diff --git a/src/components/Switch.jsx b/src/components/Switch.jsx new file mode 100644 index 0000000..b56c282 --- /dev/null +++ b/src/components/Switch.jsx @@ -0,0 +1,35 @@ +import { h, Component } from 'preact'; + +export default class Switch extends Component { + render() { + return ( + + ); + } +} diff --git a/src/components/Tabs.jsx b/src/components/Tabs.jsx new file mode 100644 index 0000000..db792b4 --- /dev/null +++ b/src/components/Tabs.jsx @@ -0,0 +1,89 @@ +import { h, Component } from 'preact'; + +function hyphenate(text) { + return text.replace(/\s/g, '-'); +} +const ID_PREFIX = 'tab-panel-'; + +export function TabPanel({ label }) { + return ( +
+ {this.props.children} +
+ ); +} +function Tab({ label, isSelected, onKeyUp, onClick }) { + return ( + + ); +} +export default class Tabs extends Component { + constructor(props) { + super(props); + this.state = { + selectedTab: 0 + }; + } + isSelected(index) { + return this.state.selectedTab === index; + } + switchTab(selectedTab) { + this.setState({ selectedTab: selectedTab }); + this.tabListEl.querySelectorAll('[role=tab]')[selectedTab].focus(); + } + keyUpHandler(e) { + let { selectedTab } = this.state; + if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') { + selectedTab--; + selectedTab = + selectedTab < 0 ? this.props.children.length - 1 : selectedTab; + this.switchTab(selectedTab); + e.preventDefault(); + } else if (e.key === 'ArrowRight' || e.key === 'ArrowDown') { + selectedTab++; + selectedTab %= this.props.children.length; + this.switchTab(selectedTab); + e.preventDefault(); + } + } + render() { + const tabs = this.props.children; + return ( +
+
(this.tabListEl = el)} + > + {tabs.map((child, index) => ( + this.setState({ selectedTab: index })} + /> + ))} +
+
+ {tabs.map( + (child, index) => (this.state.selectedTab === index ? child : null) + )} +
+
+ ); + } +} diff --git a/src/components/app.jsx b/src/components/app.jsx index 82b38b8..7c192fd 100644 --- a/src/components/app.jsx +++ b/src/components/app.jsx @@ -887,15 +887,14 @@ export default class App extends Component { /** * Handles all user triggered preference changes in the UI. */ - updateSetting(e) { + updateSetting(settingName, value) { // If this was triggered from user interaction, save the setting - if (e) { - var settingName = e.target.dataset.setting; + if (settingName) { + // var settingName = e.target.dataset.setting; var obj = {}; - var el = e.target; - log(settingName, el.type === 'checkbox' ? el.checked : el.value); + log(settingName, value); const prefs = { ...this.state.prefs }; - prefs[settingName] = el.type === 'checkbox' ? el.checked : el.value; + prefs[settingName] = value; obj[settingName] = prefs[settingName]; this.setState({ prefs }); diff --git a/src/components/common.jsx b/src/components/common.jsx index 4c53f63..90e7b31 100644 --- a/src/components/common.jsx +++ b/src/components/common.jsx @@ -32,3 +32,7 @@ export function AutoFocusInput(props) { el && setTimeout(() => el.focus(), 100)} {...props} /> ); } + +export function Divider(props) { + return
; +} diff --git a/src/style.css b/src/style.css index c8cc02e..fc7b3c5 100644 --- a/src/style.css +++ b/src/style.css @@ -212,6 +212,11 @@ hr { label { cursor: pointer; } +.divider { + margin: 10px 0; + height: 1px; + background: rgba(255, 255, 255, 0.1); +} [class*='hint--']:after { text-transform: none; @@ -221,8 +226,10 @@ label { } .line { - display: block; + /* display: block; */ margin-bottom: 1em; + display: flex; + justify-content: space-between; } .caret { @@ -249,6 +256,86 @@ a > svg { bottom: 0; } +.check-switch { + display: block; + overflow: hidden; + position: relative; + + /* breathing space for outline */ + padding: 2px 0; +} + +.check-switch:hover { + background: rgba(0, 0, 0, 0.1); +} + +.check-switch .check-switch__toggle { + position: relative; + margin: 0 5px; +} +.check-switch .check-switch__toggle:after { + background: #fff; + position: absolute; + border-radius: 100%; + width: 1.1em; + height: 1.1em; + top: 3px; + right: 1.5em; + box-shadow: 0 2px 3px rgba(0, 0, 0, 0.5); + transition: right 0.1825s ease-in-out; +} + +.check-switch .check-switch__toggle:before, +.check-switch .check-switch__toggle:after { + content: ''; + display: block; +} + +.check-switch .check-switch__toggle:before { + background: rgba(255, 255, 255, 0.2); + border-radius: 1.75em; + width: 2.75em; + height: 1.45em; + right: 0.25em; + transition: background 0.2s ease-in-out; +} + +.check-switch input:not([role='button']) { + pointer-events: none; +} + +.check-switch input { + top: 0; + left: 0; + opacity: 0.0001; + position: absolute; +} + +.check-switch__status { + text-transform: uppercase; + font-size: 14px; + font-weight: 600; +} + +.check-switch input:focus + * .check-switch__toggle:before { + outline: 2px solid; + outline-color: var(--color-focus-outline); +} + +.check-switch input:checked + * .check-switch__toggle:after { + right: 0.15em; + left: auto; +} + +.check-switch input:checked + * .check-switch__toggle:before { + background: #61ad1c; +} +.check-switch__toggle-wrap { + float: right; + display: flex; + align-items: center; +} + .btn { display: inline-block; color: var(--color-button); @@ -907,10 +994,9 @@ body > #demo-frame { /* Make settings modal smaller */ -@media screen and (min-width: 600px) { - .modal--settings { - /* width: 600px; */ - /* margin-lef.t: -300px; */ +@media screen and (min-width: 850px) { + .modal--settings > .modal__content { + width: 850px; } } @@ -1577,6 +1663,7 @@ body:not(.is-app) .show-when-app { .help-text { font-size: 0.9em; color: rgba(255, 255, 255, 0.5); + margin: 5px 0; } .social-login-btn:after, @@ -1822,6 +1909,29 @@ while the theme CSS file is loading */ padding: 5px; z-index: 1; } +.tabs { + display: flex; +} +.tabs__tablist { + margin-right: 40px; + flex-shrink: 0; +} +.tabs__tab { + display: block; + margin-bottom: 10px; + background: transparent; + border: 0; + text-align: left; + width: 100%; + color: inherit; +} +.tabs__tab--selected { + background-color: rgba(0, 0, 0, 0.5); +} +.tabs__tabpanel-wrap { + flex: 1; +} + @media screen and (max-width: 600px) { body { font-size: 70%;