mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-10 02:13:58 +01:00
rewrite form controls with react
This commit is contained in:
parent
b7be796a5f
commit
4214715fd6
22 changed files with 243 additions and 66 deletions
|
|
@ -1,7 +1,4 @@
|
|||
.root {
|
||||
color: #eee;
|
||||
font: 11px 'Lucida Grande', sans-serif;
|
||||
background-color: #1a1a1a;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
|
|
|||
15
modules/ui/components/Stack.jsx
Normal file
15
modules/ui/components/Stack.jsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import React from 'react';
|
||||
|
||||
import ls from './Stack.less'
|
||||
|
||||
export default function Stack({children}) {
|
||||
return <div className={ls.root}>{children}</div>
|
||||
}
|
||||
|
||||
Window.defaultProps = {
|
||||
type: 'neutral',
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
9
modules/ui/components/Stack.less
Normal file
9
modules/ui/components/Stack.less
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
@import '../styles/theme';
|
||||
@import '../styles/mixins';
|
||||
|
||||
.root > * {
|
||||
|
||||
border-bottom: 1px solid @border-color;
|
||||
padding: 0.3em 0.5em;
|
||||
|
||||
}
|
||||
|
|
@ -6,21 +6,23 @@ import Fa from "./Fa";
|
|||
|
||||
export default class Window extends React.Component {
|
||||
|
||||
constructor({initWidth}) {
|
||||
constructor({initWidth, initLeft, initTop}) {
|
||||
super();
|
||||
this.state = {
|
||||
width: initWidth
|
||||
width: initWidth,
|
||||
left: initLeft,
|
||||
top: initTop
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let {children, title, minimizable } = this.props;
|
||||
let {children, title, minimizable, onClose} = this.props;
|
||||
return <div className={ls.root} style={this.getStyle()}>
|
||||
<div className={ls.bar}>
|
||||
{title}
|
||||
<div className={ls.bar + ' disable-selection'}>
|
||||
<div><b>{title.toUpperCase()}</b></div>
|
||||
<div className={ls.controlButtons}>
|
||||
{minimizable && <span className={ls.button}>_</span>}
|
||||
<span className={ls.button}><Fa icon='close' /></span>
|
||||
<span className={ls.button} onClick={onClose}><Fa fw icon='close' /></span>
|
||||
</div>
|
||||
</div>
|
||||
{children}
|
||||
|
|
@ -30,10 +32,10 @@ export default class Window extends React.Component {
|
|||
|
||||
getStyle() {
|
||||
return {
|
||||
width: toPx(this.state.width),
|
||||
height: toPx(this.state.height),
|
||||
left: toPx(this.state.left),
|
||||
top: toPx(this.state.top)
|
||||
width: this.state.width,
|
||||
height: this.state.height,
|
||||
left: this.state.left,
|
||||
top: this.state.top
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,7 +44,4 @@ Window.defaultProps = {
|
|||
minimizable: false,
|
||||
};
|
||||
|
||||
function toPx(val) {
|
||||
return val === undefined ? undefined : val + 'px';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,24 @@
|
|||
@import '../styles/theme';
|
||||
@import '../styles/mixins';
|
||||
|
||||
.root {
|
||||
position: absolute;
|
||||
background-color: @bg-color-alt;
|
||||
}
|
||||
|
||||
.bar {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
background-color: @bg-color;
|
||||
line-height: 1;
|
||||
cursor: default;
|
||||
border-bottom: 1px solid @border-color;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 0.5em 0.5em 0.6em 0.5em;
|
||||
.button-behavior(@color-danger);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,16 @@ import React from 'react';
|
|||
|
||||
import ls from './Button.less'
|
||||
|
||||
export default function Button({text}) {
|
||||
export default function Button({text, type}) {
|
||||
|
||||
return <span>{text}</span>
|
||||
return <button className={ls[type]}>{text}</button>
|
||||
|
||||
}
|
||||
|
||||
Button.defaultProps = {
|
||||
type: 'neutral',
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
@import '../../styles/theme';
|
||||
@import '../../styles/mixins';
|
||||
|
||||
.neutral, .accent, .danger {
|
||||
background-color: darken(@color-neutral, 10%);
|
||||
}
|
||||
|
||||
.neutral {
|
||||
.button-behavior(@color-neutral)
|
||||
}
|
||||
|
||||
.accent {
|
||||
.button-behavior(@color-accent)
|
||||
}
|
||||
|
||||
.danger {
|
||||
.button-behavior(@color-danger)
|
||||
}
|
||||
|
|
@ -4,6 +4,6 @@ import ls from './ButtonGroup.less'
|
|||
|
||||
export default function ButtonGroup({children}) {
|
||||
|
||||
return <div>{children}</div>
|
||||
return <div className={ls.root}>{children}</div>
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
.root {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
& > * {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,12 +1,10 @@
|
|||
import React from 'react';
|
||||
|
||||
import ls from './Label.less'
|
||||
import ls from './Field.less'
|
||||
|
||||
export default function Field({children}) {
|
||||
|
||||
|
||||
return <div className={ls.root}>
|
||||
{children[0]} {children[1]}
|
||||
{children}
|
||||
</div>;
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
.root {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
}
|
||||
23
modules/ui/components/controls/InputControl.jsx
Normal file
23
modules/ui/components/controls/InputControl.jsx
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import ls from './InputControl.less'
|
||||
|
||||
export default class InputControl extends React.Component {
|
||||
|
||||
render() {
|
||||
let {type, inputRef, ...props} = this.props;
|
||||
|
||||
return <div className={ls[type]}>
|
||||
<input type='text' ref={inputRef} {...props} spellcheck='false' />
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
InputControl.propTypes = {
|
||||
type: PropTypes.oneOf(['number', 'text']),
|
||||
};
|
||||
|
||||
InputControl.defaultProps = {
|
||||
type: 'text'
|
||||
};
|
||||
20
modules/ui/components/controls/InputControl.less
Normal file
20
modules/ui/components/controls/InputControl.less
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
@import '../../styles/theme';
|
||||
|
||||
.number input {
|
||||
.colorStyling(@control-color-number, @control-bg);
|
||||
}
|
||||
|
||||
.text input {
|
||||
.colorStyling(@control-color-text, @control-bg);
|
||||
}
|
||||
|
||||
.colorStyling(@color, @bg) {
|
||||
color: @color;
|
||||
background: @bg;
|
||||
outline: none;
|
||||
border: @bg 1px solid;
|
||||
padding: 0.2em;
|
||||
&:focus {
|
||||
border: #444 1px solid;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,16 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import InputControl from './InputControl';
|
||||
|
||||
import ls from './NumberControl.less'
|
||||
|
||||
export default class NumberControl extends React.Component{
|
||||
export default class NumberControl extends React.Component {
|
||||
|
||||
render() {
|
||||
let {initValue, } = this.props;
|
||||
|
||||
return <div className={ls.root}>
|
||||
<input type='text' defaultValue={initValue}
|
||||
ref={(input) => this.input = input}
|
||||
onWheel={this.onWheel}
|
||||
onChange={e => onChange(e.target.value)} />
|
||||
</div>;
|
||||
let {onChange, initValue} = this.props;
|
||||
return <InputControl type='number'
|
||||
onWheel={this.onWheel}
|
||||
defaultValue={initValue}
|
||||
onChange={e => onChange(e.target.value)}
|
||||
inputRef={input => this.input = input} />
|
||||
}
|
||||
|
||||
onWheel = (e) => {
|
||||
|
|
|
|||
29
modules/ui/components/controls/TextControl.jsx
Normal file
29
modules/ui/components/controls/TextControl.jsx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import InputControl from './InputControl';
|
||||
|
||||
export default class TextControl extends React.Component {
|
||||
|
||||
render() {
|
||||
let {onChange, initValue} = this.props;
|
||||
return <InputControl type='text'
|
||||
defaultValue={initValue}
|
||||
onChange={e => onChange(e.target.value)} />
|
||||
}
|
||||
}
|
||||
|
||||
TextControl.propTypes = {
|
||||
baseStep: PropTypes.number,
|
||||
round: PropTypes.number,
|
||||
min: PropTypes.number,
|
||||
max: PropTypes.number,
|
||||
accelerator: PropTypes.number,
|
||||
initValue: PropTypes.number.isRequired,
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
TextControl.defaultProps = {
|
||||
baseStep: 1,
|
||||
round: 0,
|
||||
accelerator: 100
|
||||
};
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
@import "../theme";
|
||||
@import "../mixins";
|
||||
|
||||
body {
|
||||
background-color: @bg-color;
|
||||
|
|
@ -15,14 +16,16 @@ iframe {
|
|||
}
|
||||
|
||||
:global(.disable-selection) {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
.no-selection();
|
||||
}
|
||||
|
||||
:global(.compact-font) {
|
||||
font-family: 'Helvetica Neue Light', HelveticaNeue-Light, 'Helvetica Neue', Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
button {
|
||||
border: 0;
|
||||
background-color: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
|
|
|
|||
21
modules/ui/styles/mixins.less
Normal file
21
modules/ui/styles/mixins.less
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
.no-selection() {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
|
||||
.button-behavior(@color) {
|
||||
&:hover {
|
||||
background-color: @color;
|
||||
}
|
||||
&:active {
|
||||
background-color: darken(@color, 20%);
|
||||
}
|
||||
}
|
||||
|
||||
.row() {
|
||||
|
||||
border-bottom: 1px solid @border-color;
|
||||
}
|
||||
|
|
@ -9,12 +9,19 @@
|
|||
|
||||
@border-color: #2c2c2c;
|
||||
|
||||
@control-color-number: #2fa1d6;
|
||||
@control-color-text: #9cdaf7;
|
||||
@control-bg: #303030;
|
||||
|
||||
@work-area-color: #808080;
|
||||
|
||||
@work-area-control-bar-bg-color: rgba(0, 0, 0, 0.5);
|
||||
@work-area-control-bar-bg-color-active: #555;
|
||||
@work-area-control-bar-font-color: @font-color-minor;
|
||||
|
||||
@color-danger: #b00;
|
||||
@color-accent: #2B7D2B;
|
||||
@color-neutral: #66727d;
|
||||
|
||||
//@work-area-toolbar-bg-color: ;
|
||||
//@work-area-toolbar-font-color: ;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
.button {
|
||||
cursor: pointer;
|
||||
padding: 0.4em 0.5em;
|
||||
padding: 0.5em 0.5em 0.35em 0.5em;
|
||||
|
||||
&:hover {
|
||||
background-color: @work-area-control-bar-bg-color-active;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,17 @@ import MenuHolder from "../menu/MenuHolder";
|
|||
import {TOKENS as MENU_TOKENS} from '../menu/menuPlugin';
|
||||
|
||||
|
||||
import WindowSystem from 'ui/WindowSystem';
|
||||
import Window from "ui/components/Window";
|
||||
import Stack from "ui/components/Stack";
|
||||
import Field from "ui/components/controls/Field";
|
||||
import Label from "ui/components/controls/Label";
|
||||
import NumberControl from "ui/components/controls/NumberControl";
|
||||
import ButtonGroup from "ui/components/controls/ButtonGroup";
|
||||
import Button from "ui/components/controls/Button";
|
||||
import TextControl from './../../../../../modules/ui/components/controls/TextControl';
|
||||
|
||||
|
||||
export default class View3d extends React.PureComponent {
|
||||
|
||||
render() {
|
||||
|
|
@ -35,6 +46,25 @@ export default class View3d extends React.PureComponent {
|
|||
<PlugableToolbarRight />
|
||||
</Abs>
|
||||
<PlugableControlBar />
|
||||
|
||||
<WindowSystem />
|
||||
<Window initWidth={250} initLeft={500} title="Test">
|
||||
<Stack >
|
||||
<Field>
|
||||
<Label>Width</Label>
|
||||
<NumberControl initValue={5} onChange={val => console.log(val)}/>
|
||||
</Field>
|
||||
<Field>
|
||||
<Label>Face</Label>
|
||||
<TextControl initValue='face1' onChange={val => console.log(val)}/>
|
||||
</Field>
|
||||
<ButtonGroup>
|
||||
<Button text='Cancel' />
|
||||
<Button text='OK' type='accent' />
|
||||
</ButtonGroup>
|
||||
</Stack>
|
||||
</Window>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,15 +7,6 @@ import '../../../../css/app3d-legacy.less';
|
|||
|
||||
import View3d from './View3d';
|
||||
|
||||
import WindowSystem from 'ui/WindowSystem';
|
||||
import Window from "ui/components/Window";
|
||||
import Folder from "ui/components/Folder";
|
||||
import Field from "ui/components/controls/Field";
|
||||
import Label from "ui/components/controls/Label";
|
||||
import NumberControl from "ui/components/controls/NumberControl";
|
||||
import ButtonGroup from "ui/components/controls/ButtonGroup";
|
||||
import Button from "ui/components/controls/Button";
|
||||
|
||||
import ls from './WebApplication.less';
|
||||
import TabSwitcher, {Tab} from 'ui/components/TabSwticher';
|
||||
import Card from 'ui/components/Card';
|
||||
|
|
@ -54,23 +45,6 @@ export default class WebApplication extends React.Component {
|
|||
onSwitch={this.switchTab} />)}
|
||||
</TabSwitcher>
|
||||
<a id='downloader' style={{display: 'none'}}/>
|
||||
{/*<WindowSystem /> */}
|
||||
{/*<Window initWith={250} >*/}
|
||||
{/*<Folder title="Test">*/}
|
||||
{/*<Field>*/}
|
||||
{/*<Label>Width</Label>*/}
|
||||
{/*<NumberControl initValue={5} onChange={val => console.log(val)}/>*/}
|
||||
{/*</Field>*/}
|
||||
{/*<Field>*/}
|
||||
{/*<Label>Width</Label>*/}
|
||||
{/*<NumberControl initValue={6} onChange={val => console.log(val)}/>*/}
|
||||
{/*</Field>*/}
|
||||
{/*<ButtonGroup>*/}
|
||||
{/*<Button text='Cancel' />*/}
|
||||
{/*<Button text='OK' />*/}
|
||||
{/*</ButtonGroup>*/}
|
||||
{/*</Folder>*/}
|
||||
{/*</Window>*/}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue