Restructuring folders [ Broken ]
This commit is contained in:
129
public/objects/animation/fade/ElementScrollFader.jsx
Normal file
129
public/objects/animation/fade/ElementScrollFader.jsx
Normal file
@ -0,0 +1,129 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
class ElementScrollFader extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
waiting: true,
|
||||
visible: false
|
||||
};
|
||||
this.onScrollBound = this.onScroll.bind(this);
|
||||
this.updateRectangleBound = this.updateRectangle.bind(this);
|
||||
this.checkEffectBound = this.checkEffect.bind(this);
|
||||
|
||||
this.rect = null;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
//Update rectangle
|
||||
if(this.rectTimer) clearInterval(this.rectTimer);
|
||||
this.rectTimer = setInterval(this.updateRectangleBound, 100);
|
||||
|
||||
if(!this.initialCheckFunction) {
|
||||
this.initialCheckFunction = setTimeout(this.checkEffectBound, 300);
|
||||
}
|
||||
|
||||
document.addEventListener('scroll', this.onScrollBound, true);
|
||||
document.addEventListener("DOMContentLoaded", this.updateRectangleBound);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.detachListener();
|
||||
}
|
||||
|
||||
//Used for rect calculation
|
||||
updateRectangle() {
|
||||
if(!this.refs || !this.refs.fader) return;
|
||||
this.rect = this.refs.fader.getBoundingClientRect();
|
||||
}
|
||||
|
||||
onScroll(e) {
|
||||
this.checkEffect();
|
||||
}
|
||||
|
||||
//Common functions
|
||||
detachListener() {
|
||||
document.removeEventListener('scroll', this.onScrollBound);
|
||||
document.removeEventListener("DOMContentLoaded", this.updateRectangleBound);
|
||||
|
||||
if(this.rectTimer) clearInterval(this.rectTimer);
|
||||
if(this.initialCheckFunction) clearTimeout(this.initialCheckFunction);
|
||||
}
|
||||
|
||||
checkEffect() {
|
||||
if(typeof window === typeof undefined) return;
|
||||
if(!this.refs || !this.refs.fader) return;
|
||||
if(this.state.waiting) {
|
||||
this.setState({
|
||||
waiting: false
|
||||
});
|
||||
}
|
||||
if(this.state.visible) return this.detachListener();
|
||||
|
||||
if(!this.rect) this.updateRectangle();
|
||||
|
||||
//Get bounds
|
||||
var rect = this.rect;
|
||||
|
||||
//If our top is at least half way UP the page, show
|
||||
if(rect.top > window.innerHeight / 1.5) return;
|
||||
|
||||
this.setState({
|
||||
visible: true
|
||||
});
|
||||
|
||||
this.detachListener();//stop Listening
|
||||
|
||||
if(this.props.onVisible) {
|
||||
this.props.onVisible(this.refs.fader);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
render() {
|
||||
let clazz = "o-element-scroll-fader";
|
||||
|
||||
if(this.props.from) {
|
||||
clazz += " from-" + this.props.from
|
||||
} else {
|
||||
clazz += " from-top";
|
||||
}
|
||||
if(this.state.visible || this.state.waiting) {
|
||||
clazz += " is-visible";
|
||||
}
|
||||
|
||||
if(this.props.className) clazz += " " + this.props.className;
|
||||
|
||||
return (
|
||||
<div className={ clazz } ref="fader">
|
||||
{ this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ElementScrollFader;
|
38
public/objects/background/Background.jsx
Normal file
38
public/objects/background/Background.jsx
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default function(props) {
|
||||
let style = props.style || "test";
|
||||
let styleClassPrefix = "o-background--style-"+style;
|
||||
let inners = [];
|
||||
|
||||
return (
|
||||
<div className={"o-background "+styleClassPrefix}>
|
||||
<div className={"o-background__inner " + styleClassPrefix + "__inner" }>
|
||||
{ inners }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
37
public/objects/content/ContentBox.jsx
Normal file
37
public/objects/content/ContentBox.jsx
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default (props) => {
|
||||
let clazz = "o-content-box";
|
||||
|
||||
if(props.box) clazz += " is-box"
|
||||
if(props.className) clazz += " " + props.className;
|
||||
|
||||
return (
|
||||
<div className={clazz}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
};
|
50
public/objects/content/FloatingContentBox.jsx
Normal file
50
public/objects/content/FloatingContentBox.jsx
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
import ContentBox from './ContentBox';
|
||||
|
||||
export default function(props) {
|
||||
let clazzes = "o-floating-content-box";
|
||||
|
||||
//Positions
|
||||
let position = "middle center";
|
||||
if(props.position) position = props.position;
|
||||
clazzes += " " + position.split(" ").map(i => 'is-'+i).join(" ");
|
||||
|
||||
//Sizes`
|
||||
let size = "medium";
|
||||
if(props.size) size = props.size;
|
||||
clazzes += " is-"+size;
|
||||
|
||||
//Custom Classes
|
||||
if(props.className) clazzes += " " + props.className;
|
||||
|
||||
return (
|
||||
<ContentBox {...props} className={ clazzes }>
|
||||
<div className="o-floating-content-box__inner">
|
||||
{ props.children }
|
||||
</div>
|
||||
</ContentBox>
|
||||
);
|
||||
}
|
143
public/objects/image/Image.jsx
Normal file
143
public/objects/image/Image.jsx
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
import LoadableImage from './LoadableImage';
|
||||
|
||||
export default class Image extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
onLoad(e) {
|
||||
if(this.props.onLoad) this.props.onLoad(e);
|
||||
}
|
||||
|
||||
onError() {
|
||||
if(this.props.onError) this.props.onErorr(e);
|
||||
}
|
||||
|
||||
render() {
|
||||
if(this.props.loadable) {
|
||||
return <LoadableImage {...this.props} />;
|
||||
}
|
||||
|
||||
let sourceProps = Object.assign({}, this.props);
|
||||
|
||||
//Prop Manipulation
|
||||
if(sourceProps.image) {
|
||||
if(Array.isArray(sourceProps.image)) {
|
||||
sourceProps.sources = sourceProps.image;
|
||||
} else {
|
||||
sourceProps.src = sourceProps.image;
|
||||
}
|
||||
}
|
||||
|
||||
if(sourceProps.src) {
|
||||
if(sourceProps.src.images) sourceProps.sources = sourceProps.src.images;
|
||||
if(sourceProps.src.width) sourceProps.width = sourceProps.src.width;
|
||||
if(sourceProps.src.height) sourceProps.height = sourceProps.src.height;
|
||||
}
|
||||
|
||||
//Image
|
||||
let sourceElements = [];
|
||||
let sources = {};
|
||||
|
||||
let defaultSrc = sourceProps.src;
|
||||
let defaultAlt = sourceProps.alt;
|
||||
let defaultWidth = sourceProps.width;
|
||||
let defaultHeight = sourceProps.height;
|
||||
|
||||
if(sourceProps.sources) {
|
||||
//Iterate over supplied sources
|
||||
for(let i = 0; i < sourceProps.sources.length; i++) {
|
||||
let x = sourceProps.sources[i];
|
||||
let width = x.size || x.width;
|
||||
let isLast = (i+1) === sourceProps.sources.length;
|
||||
|
||||
for(let scale = 1; scale <= 4; scale++) {
|
||||
let scaledWidth = Math.round(width / scale);
|
||||
let o = Object.assign({}, x);
|
||||
o.scale = scale;
|
||||
o.isLast = isLast;
|
||||
sources[scaledWidth] = sources[scaledWidth] || [];
|
||||
sources[scaledWidth].push(o);
|
||||
}
|
||||
}
|
||||
|
||||
let keys = Object.keys(sources);
|
||||
keys.sort((l, r) => {
|
||||
return parseInt(l) - parseInt(r);
|
||||
});
|
||||
let breakNext = false;
|
||||
for(let i = 0; i < keys.length; i++) {
|
||||
if(breakNext) break;
|
||||
let k = keys[i];//The pixel size
|
||||
|
||||
let ss = sources[k];//Sources at this pixel resolution
|
||||
let mediaQuery = '(max-width:'+k+'px)';
|
||||
let sss = [];
|
||||
|
||||
let isNextBreak = false;
|
||||
if(this.props.maxWidth && (i+1 < keys.length)) {
|
||||
if(keys[i+1] > parseInt(this.props.maxWidth)) isNextBreak = true;
|
||||
}
|
||||
if(isNextBreak) {
|
||||
breakNext = true;
|
||||
mediaQuery = '(min-width:'+k+'px)';
|
||||
}
|
||||
|
||||
if(ss.length && ss[0].isLast) {
|
||||
let prev = i > 0 ? keys[i-1] : 0;
|
||||
mediaQuery = '(min-width:'+prev+'px)';
|
||||
}
|
||||
|
||||
for(let x = 0; x < ss.length; x++) {
|
||||
let scale = ss[x];
|
||||
let source = scale.src || scale.path;
|
||||
sss.push( source + (scale.scale && scale.scale!=1 ? " "+scale.scale+"x" : "") );
|
||||
}
|
||||
|
||||
sourceElements.push(
|
||||
<source media={mediaQuery} srcSet={ sss.join(", ") } key={i} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<picture>
|
||||
{ sourceElements }
|
||||
<img
|
||||
onLoad={ this.onLoad.bind(this) }
|
||||
onError={ this.onError.bind(this) }
|
||||
src={ defaultSrc }
|
||||
alt={ defaultAlt }
|
||||
className={ sourceProps.className }
|
||||
width={ defaultWidth }
|
||||
height={ defaultHeight }
|
||||
title={sourceProps.title}
|
||||
/>
|
||||
</picture>
|
||||
);
|
||||
}
|
||||
}
|
81
public/objects/image/LoadableImage.jsx
Normal file
81
public/objects/image/LoadableImage.jsx
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
import Image from './Image';
|
||||
import Loader from './../loading/Loader';
|
||||
import BoxSizer from './../layout/BoxSizer';
|
||||
|
||||
class LoadableImage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
loading: true
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {}
|
||||
componentWillUnmount() {}
|
||||
|
||||
onLoad() {
|
||||
this.setState({
|
||||
loading: false
|
||||
});
|
||||
}
|
||||
|
||||
onError() {
|
||||
this.setState({
|
||||
loading: false
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let p = Object.assign({}, this.props);
|
||||
p.loadable = false;
|
||||
p.onLoad = this.onLoad.bind(this);
|
||||
let image = <Image {...p} />;
|
||||
|
||||
let loader,imageSizerDuringLoad;
|
||||
|
||||
if(this.state.loading) {
|
||||
loader = <Loader />;
|
||||
if(p.width && p.height) {
|
||||
imageSizerDuringLoad = <BoxSizer ratioWidth={p.width} ratioHeight={p.height} />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={"o-loadable-image " + (this.state.loading ? "is-loading" : "is-loaded")}>
|
||||
{ loader }
|
||||
{ imageSizerDuringLoad }
|
||||
|
||||
<div className="o-loadable-image__image-container">
|
||||
{ image }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default LoadableImage;
|
185
public/objects/input/Input.jsx
Normal file
185
public/objects/input/Input.jsx
Normal file
@ -0,0 +1,185 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import Button from './button/Button';
|
||||
import ButtonGroup from './button/ButtonGroup';
|
||||
import Form, { FormManager } from './form/Form';
|
||||
import InputGroup from './group/InputGroup';
|
||||
import Label from './label/Label';
|
||||
import Keyboard from './../keyboard/Keyboard';
|
||||
|
||||
export default class Input extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: props.value,
|
||||
focused: false
|
||||
};
|
||||
}
|
||||
|
||||
isFocused() {
|
||||
return this.state && this.state.focused === true;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if(this.props.manager) this.props.manager.addInput(this);
|
||||
Keyboard.addListener(this);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if(this.props.manager) this.props.manager.removeInput(this);
|
||||
Keyboard.removeListener(this);
|
||||
}
|
||||
|
||||
onKeyUp(e, k) {
|
||||
if(!this.props.manager) return;
|
||||
if(!this.isFocused()) return;
|
||||
if(!k.isSubmit()) return;
|
||||
this.props.manager.submit();
|
||||
}
|
||||
|
||||
onChange(e, a, b) {
|
||||
//Try my props
|
||||
if(this.props.onChange && this.props.onChange(e) === false) return false;
|
||||
|
||||
//Try the form manager
|
||||
if(this.props.manager && this.props.manager.onChange(this, e) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Try something else?
|
||||
this.setState({
|
||||
value: e.target.value
|
||||
});
|
||||
}
|
||||
|
||||
onFocus() {
|
||||
this.setState({ focused: true });
|
||||
}
|
||||
|
||||
onBlur() {
|
||||
this.setState({ focused: false });
|
||||
}
|
||||
|
||||
render() {
|
||||
let ElementType = "input";
|
||||
let type = "text";
|
||||
let value;
|
||||
let clazzes = "o-input";
|
||||
let innerClazzes = "o-input__inner";
|
||||
let style;
|
||||
let props = Object.assign({}, this.props);
|
||||
|
||||
//Determining
|
||||
if(props.type) type = props.type;
|
||||
|
||||
//Values
|
||||
if(props.value) {
|
||||
value = props.value;
|
||||
} else {
|
||||
value = props.children;
|
||||
}
|
||||
|
||||
//Style
|
||||
if(props.style) {
|
||||
style = props.style;
|
||||
} else if(props.error || props.danger) {
|
||||
style = "danger";
|
||||
} else if(props.warning) {
|
||||
style = "warning";
|
||||
} else if(props.primary) {
|
||||
style = "primary";
|
||||
}
|
||||
|
||||
//Classes
|
||||
clazzes += " is-"+type;
|
||||
|
||||
if(style) {
|
||||
clazzes += " o-input--style-"+style;
|
||||
innerClazzes += " o-input--style-"+style+"__inner";
|
||||
}
|
||||
if(props.className) {
|
||||
clazzes += " " + props.className;
|
||||
innerClazzes += " " + props.className + "-element";
|
||||
}
|
||||
|
||||
//Clear junk props
|
||||
delete props.manager;
|
||||
|
||||
//Now create the element
|
||||
let element;
|
||||
|
||||
//First we need to switch things like submit and reset
|
||||
if(type == "submit" || type == "reset" || type == "button") {
|
||||
return (<Button
|
||||
{...props}
|
||||
className={props.className}
|
||||
value={this.state.value}
|
||||
/>);
|
||||
|
||||
} else if(type == "textarea") {
|
||||
element = (<textarea
|
||||
{...props}
|
||||
className={innerClazzes}
|
||||
onChange={this.onChange.bind(this)}
|
||||
onFocus={this.onFocus.bind(this)}
|
||||
onBlur={this.onBlur.bind(this)}
|
||||
>{ this.state.value }</textarea>
|
||||
);
|
||||
|
||||
} else {
|
||||
element = (<ElementType
|
||||
{...props}
|
||||
onChange={this.onChange.bind(this)}
|
||||
onFocus={this.onFocus.bind(this)}
|
||||
onBlur={this.onBlur.bind(this)}
|
||||
type={type}
|
||||
value={ this.state.value }
|
||||
className={innerClazzes}
|
||||
/>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={clazzes}>
|
||||
{ element }
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const TextArea = props => {
|
||||
return <Input {...props} type="textarea" />
|
||||
}
|
||||
|
||||
export {
|
||||
Button,
|
||||
ButtonGroup,
|
||||
Form,
|
||||
FormManager,
|
||||
InputGroup,
|
||||
TextArea,
|
||||
Label
|
||||
};
|
104
public/objects/input/button/Button.jsx
Normal file
104
public/objects/input/button/Button.jsx
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
export default class Button extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let ElementType = "button";//Upper Camel-Case because of react requriements
|
||||
let clazzes = "o-btn";
|
||||
let type = "button";
|
||||
let contents;
|
||||
let href;
|
||||
let to;
|
||||
let activeClassName;
|
||||
let style;
|
||||
|
||||
//Basic Element Determining
|
||||
if(this.props.type) {
|
||||
//Buttons and Input Buttons
|
||||
type = this.props.type;
|
||||
clazzes += " is-button";
|
||||
} else if(this.props.href) {
|
||||
//Anchor Tags1
|
||||
ElementType = "a";
|
||||
href = this.props.href;
|
||||
clazzes += " is-link is-anchor";
|
||||
} else if(this.props.to) {
|
||||
//React NavLink/Link
|
||||
to = this.props.to;
|
||||
ElementType = NavLink;
|
||||
clazzes += " is-link is-nav-link";
|
||||
activeClassName = "is-active";
|
||||
} else {
|
||||
//Everything Else (button without a type);
|
||||
clazzes += " is-not-button";
|
||||
}
|
||||
|
||||
if(this.props.value) {
|
||||
contents = this.props.value;
|
||||
} else {
|
||||
contents = this.props.children;
|
||||
}
|
||||
|
||||
//Determine Style
|
||||
if(this.props.primary) {
|
||||
style = "primary"
|
||||
} else if(this.props.secondary) {
|
||||
style = "secondary";
|
||||
} else if(this.props.danger) {
|
||||
style = "danger";
|
||||
} else if(this.props.warning) {
|
||||
style = "warning";
|
||||
} else if(this.props.style) {
|
||||
style = this.props.style;
|
||||
}
|
||||
|
||||
//Style Clazzes
|
||||
if(style) {
|
||||
clazzes += " o-btn--style-"+style;
|
||||
}
|
||||
|
||||
//Determine extra clazzes
|
||||
if(this.props.className) this.clazzes += " "+this.props.className;
|
||||
|
||||
return (
|
||||
<ElementType
|
||||
{...this.props}
|
||||
type={type}
|
||||
className={clazzes}
|
||||
href={href}
|
||||
to={to}
|
||||
>
|
||||
<span className={ "o-btn__inner" + (style ? " o-btn--style-" + style + "__inner" : "") }>
|
||||
{contents}
|
||||
</span>
|
||||
</ElementType>
|
||||
);
|
||||
}
|
||||
}
|
32
public/objects/input/button/ButtonGroup.jsx
Normal file
32
public/objects/input/button/ButtonGroup.jsx
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default function(props) {
|
||||
return (
|
||||
<div {...props} className={"o-btn-group" + (props.className ? " "+props.className : "")}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
239
public/objects/input/form/Form.jsx
Normal file
239
public/objects/input/form/Form.jsx
Normal file
@ -0,0 +1,239 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
import Loader, { LoaderBackdrop } from './../../loading/Loader';
|
||||
import Input, { InputGroup, TextArea } from './../Input';
|
||||
|
||||
export default class Form extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
//Prepare our initial state
|
||||
let s = {
|
||||
ajax: props.ajax || false,
|
||||
loader: props.loader || false,
|
||||
loading: false,
|
||||
onSubmit: props.onSubmit,
|
||||
contentType: props.contentType || props.encType || "application/x-www-form-urlencoded",
|
||||
manager: props.manager
|
||||
};
|
||||
|
||||
//Determine action and method based off the internals
|
||||
if(props.action) s.action = props.action;
|
||||
if(props.method) s.method = props.method;
|
||||
|
||||
if(props.get) {
|
||||
s.action = props.get;
|
||||
s.method = "GET";
|
||||
}
|
||||
|
||||
if(props.post) {
|
||||
s.action = props.post;
|
||||
s.method = "POST";
|
||||
}
|
||||
|
||||
//Write our state to the component
|
||||
this.state = s;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if(this.props.manager) this.props.manager.addForm(this);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if(this.props.manager) this.props.manager.removeForm(this);
|
||||
}
|
||||
|
||||
submit() {
|
||||
this.onSubmit();
|
||||
}
|
||||
|
||||
onSubmit(e) {
|
||||
//Is Ajax?
|
||||
if(!this.state.ajax) {
|
||||
return this.state.onSubmit ? this.state.onSubmit(e) : true;
|
||||
}
|
||||
|
||||
if(e) e.preventDefault();
|
||||
if(!this.state.action) return console.warning("This form has no action.");
|
||||
if(this.state.submitting) return false;//Already submitting?
|
||||
|
||||
//Start submitting!
|
||||
this.setState({
|
||||
loading: true,
|
||||
submitting: true
|
||||
});
|
||||
|
||||
//Prepare our data
|
||||
let data;
|
||||
if(this.props.manager) {
|
||||
data = this.props.manager.getFormData();
|
||||
}
|
||||
|
||||
if(this.state.contentType == "application/json") {
|
||||
let dataJson = {};
|
||||
data.forEach(function(value, key) {
|
||||
dataJson[key] = value;
|
||||
});
|
||||
data = JSON.stringify(dataJson);
|
||||
}
|
||||
|
||||
//Prepare our request.
|
||||
fetch(this.state.action, {
|
||||
method: this.state.method,
|
||||
mode: this.state.mode,
|
||||
body: data,
|
||||
headers: {
|
||||
"Content-Type": this.state.contentType
|
||||
}
|
||||
})
|
||||
.then(this.onSubmitted.bind(this))
|
||||
.catch(this.onError.bind(this))
|
||||
;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
onSubmitted(response) {
|
||||
let method = 'text';
|
||||
let isJson = response.headers.get("Content-Type").toLowerCase().indexOf("application/json") !== -1;
|
||||
if(isJson) method = 'json';
|
||||
|
||||
if(!response.ok) {
|
||||
let is4xx = Math.floor(response.status / 400) === 1;
|
||||
if(is4xx) {
|
||||
return response[method]()
|
||||
.then(this.onErrorText.bind(this))
|
||||
.catch(this.onError.bind(this))
|
||||
;
|
||||
} else {
|
||||
throw Error(response.statusText);
|
||||
}
|
||||
}
|
||||
|
||||
if(this.props.onData) return this.props.onData(response);
|
||||
|
||||
//Handle the old fashioned way (expect json)
|
||||
response[method]()
|
||||
.then(this.onData.bind(this))
|
||||
.catch(this.onError.bind(this))
|
||||
;
|
||||
}
|
||||
|
||||
onData(response) {
|
||||
if(this.props.onSuccess) return this.props.onSuccess(response);
|
||||
console.log(response);
|
||||
}
|
||||
|
||||
onErrorText(e,a,b) {
|
||||
this.onError(e,a,b);
|
||||
}
|
||||
|
||||
onError(e, a, b) {
|
||||
this.setState({
|
||||
loading: false,
|
||||
submitting: false
|
||||
});
|
||||
if(this.props.onError) return this.props.onError(e, a, b);
|
||||
|
||||
if(e) console.error(e);
|
||||
if(a) console.error(a);
|
||||
if(b) console.error(b);
|
||||
}
|
||||
|
||||
render() {
|
||||
let clazz = "o-form";
|
||||
if(this.props.className) clazz += " " + this.props.className;
|
||||
|
||||
//Do I need a loader?
|
||||
let loader;
|
||||
if(this.state.loader && this.state.loading) {
|
||||
loader = (
|
||||
<LoaderBackdrop className="o-form__loader">
|
||||
<Loader className="o-form__loader-spinner" />
|
||||
</LoaderBackdrop>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<form
|
||||
ref="formDOM"
|
||||
className={clazz}
|
||||
method={ this.state.method }
|
||||
autoComplete={ this.props.autoComplete }
|
||||
target={ this.props.target }
|
||||
onSubmit={ this.onSubmit.bind(this) }
|
||||
>
|
||||
{ this.props.children }
|
||||
{ loader }
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//FormManager
|
||||
class FormManager {
|
||||
constructor() {
|
||||
this.forms = [];
|
||||
this.inputs = [];
|
||||
}
|
||||
|
||||
addForm(form) { this.forms.push(form); }
|
||||
addInput(input) { this.inputs.push(input); }
|
||||
|
||||
removeForm(form) {
|
||||
let i = this.forms.indexOf(form);
|
||||
if(i === -1) return;
|
||||
this.forms.splice(i, 1);
|
||||
}
|
||||
|
||||
removeInput(input) {
|
||||
let i = this.inputs.indexOf(input);
|
||||
if(i === -1) return;
|
||||
this.inputs.splice(i, 1);
|
||||
}
|
||||
|
||||
onChange(input, event) {}
|
||||
|
||||
submit() {
|
||||
for(let i = 0; i < this.forms.length; i++) {
|
||||
this.forms[i].submit();
|
||||
}
|
||||
}
|
||||
|
||||
getFormData() {
|
||||
let data = new FormData();
|
||||
|
||||
for(let i = 0; i < this.inputs.length; i++) {
|
||||
let input = this.inputs[i];
|
||||
data.append(input.props.name, input.state.value);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
FormManager
|
||||
};
|
36
public/objects/input/group/InputGroup.jsx
Normal file
36
public/objects/input/group/InputGroup.jsx
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default function(props) {
|
||||
let clazzes = "o-form__group";
|
||||
|
||||
if(props.className) clazzes += " " + props.className;
|
||||
|
||||
return (
|
||||
<div className={clazzes}>
|
||||
{ props.children }
|
||||
</div>
|
||||
);
|
||||
}
|
35
public/objects/input/label/Label.jsx
Normal file
35
public/objects/input/label/Label.jsx
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default function(props) {
|
||||
let clazz = "o-label";
|
||||
if(props.className) clazz += " " + props.className;
|
||||
|
||||
return (
|
||||
<label htmlFor={ props.htmlFor } className={clazz}>
|
||||
{ props.children }
|
||||
</label>
|
||||
);
|
||||
}
|
17
public/objects/layout/BoxSizer.jsx
Normal file
17
public/objects/layout/BoxSizer.jsx
Normal file
@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
|
||||
export default (props) => {
|
||||
let height = 100;/* Percentage of width */
|
||||
|
||||
//TODO: Add more methods of resizing this box.
|
||||
if(props.ratioWidth && props.ratioHeight) {
|
||||
height = 100 / props.ratioWidth * props.ratioHeight;
|
||||
}
|
||||
|
||||
//Box Sizer
|
||||
return (
|
||||
<div className="o-box-sizer" style={{
|
||||
paddingBottom: height + '%'
|
||||
}} />
|
||||
);
|
||||
};
|
53
public/objects/loading/Loader.jsx
Normal file
53
public/objects/loading/Loader.jsx
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
const Loader = function(props) {
|
||||
return (
|
||||
<span className={"o-loader"+(props.className?" "+props.className:"")}>
|
||||
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg" className="o-loader__image">
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<g transform="translate(1 1)" strokeWidth="2">
|
||||
<circle strokeOpacity=".5" cx="18" cy="18" r="18" />
|
||||
<path id="test" d="M36 18c0-9.94-8.06-18-18-18">
|
||||
</path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
const LoaderBackdrop = function(props) {
|
||||
return (
|
||||
<div className={"o-loader__backdrop"+(props.className?" "+props.className:"")}>
|
||||
{ props.children }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Loader;
|
||||
export {
|
||||
LoaderBackdrop
|
||||
};
|
154
public/objects/modal/Modal.jsx
Normal file
154
public/objects/modal/Modal.jsx
Normal file
@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { CSSTransition, TransitionGroup } from 'react-transition-group';
|
||||
import { Button } from './../input/Input';
|
||||
import Language from './../language/Language';
|
||||
import { openModal, closeModal } from './../actions/ModalActions';
|
||||
import { Heading4 } from './../typography/Typography';
|
||||
import Keyboard from './../keyboard/Keyboard';
|
||||
|
||||
class Modal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
Keyboard.addListener(this);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
Keyboard.removeListener(this);
|
||||
}
|
||||
|
||||
onKeyUp(e) {
|
||||
if(!Keyboard.isEscape()) return;
|
||||
this.props.closeModal();
|
||||
}
|
||||
|
||||
render() {
|
||||
//Add necessary buttons
|
||||
let buttons = [];
|
||||
if(this.props.buttons) {
|
||||
if(Array.isArray(buttons)) {
|
||||
buttons.concat(this.props.buttons);
|
||||
} else {
|
||||
buttons.push(this.props.buttons);
|
||||
}
|
||||
}
|
||||
|
||||
if(this.props.close) {
|
||||
buttons.push(<Button key="close" onClick={this.props.closeModal}>{ Language.get("modal.close") }</Button>);
|
||||
}
|
||||
|
||||
//Inner divs
|
||||
let heading,body,footer;
|
||||
if(this.props.title) {
|
||||
heading = (
|
||||
<div className="o-modal__box-heading">
|
||||
<Heading4 className="o-modal__title">
|
||||
{ this.props.title }
|
||||
</Heading4>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if(this.props.children) {
|
||||
body = (
|
||||
<div className="o-modal__box-body">
|
||||
{ this.props.children }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if(buttons) {
|
||||
footer = (
|
||||
<div className="o-modal__box-footer">
|
||||
{ buttons }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
//Create our modal contents
|
||||
let contents = (
|
||||
<div className="o-modal">
|
||||
<div className="o-modal__inner">
|
||||
{/* Provides both a good overlay, and a nice clickable area */}
|
||||
<div className="o-modal__backdrop" onClick={this.props.closeModal}>
|
||||
</div>
|
||||
|
||||
{/* Box itself, has a background and a shadow */}
|
||||
<div className={"o-modal__box" + (this.props.large ? " is-large":"")}>
|
||||
{ heading }
|
||||
{ body }
|
||||
{ footer }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
//Display?
|
||||
let displayedContents = <div></div>;
|
||||
|
||||
if(this.props.modal.open) {
|
||||
displayedContents = (
|
||||
<CSSTransition
|
||||
appear={true}
|
||||
timeout={200}
|
||||
classNames="o-modal__transition"
|
||||
mountOnEnter={ true }
|
||||
unmountOnExit={ true }
|
||||
key="modal"
|
||||
>
|
||||
{ contents }
|
||||
</CSSTransition>
|
||||
);
|
||||
}
|
||||
|
||||
//Wrap entire contents of modal in transitional container.
|
||||
return (
|
||||
<TransitionGroup className="o-modal__transition-container">
|
||||
{ displayedContents }
|
||||
</TransitionGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
modal: state.modal,
|
||||
language: state.language
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return bindActionCreators({
|
||||
openModal: openModal,
|
||||
closeModal: closeModal
|
||||
},dispatch);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Modal);
|
53
public/objects/typography/Heading.jsx
Normal file
53
public/objects/typography/Heading.jsx
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
const Heading = (props) => {
|
||||
let level = props.level || 1;
|
||||
let CustomTag = "h"+level;
|
||||
let clazz = "o-heading o-heading--"+level;
|
||||
if(props.className) clazz += " " + props.className;
|
||||
|
||||
|
||||
return (
|
||||
<CustomTag {...props} className={clazz} />
|
||||
);
|
||||
}
|
||||
export default Heading;
|
||||
|
||||
const Heading1 = (props) => { return <Heading {...props} level="1" />; };
|
||||
const Heading2 = (props) => { return <Heading {...props} level="2" />; };
|
||||
const Heading3 = (props) => { return <Heading {...props} level="3" />; };
|
||||
const Heading4 = (props) => { return <Heading {...props} level="4" />; };
|
||||
const Heading5 = (props) => { return <Heading {...props} level="5" />; };
|
||||
const Heading6 = (props) => { return <Heading {...props} level="6" />; };
|
||||
|
||||
export {
|
||||
Heading1,
|
||||
Heading2,
|
||||
Heading3,
|
||||
Heading4,
|
||||
Heading5,
|
||||
Heading6
|
||||
};
|
31
public/objects/typography/Paragraph.jsx
Normal file
31
public/objects/typography/Paragraph.jsx
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default (props) => {
|
||||
let clazz = "o-paragraph";
|
||||
if(props.className) clazz += " "+props.className;
|
||||
|
||||
return <p {...props} className={clazz} />
|
||||
};
|
32
public/objects/typography/Subtitle.jsx
Normal file
32
public/objects/typography/Subtitle.jsx
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default function(props) {
|
||||
return (
|
||||
<p className={ "o-subtitle" + ( props.className ? " " + props.className : "") }>
|
||||
{ props.children }
|
||||
</p>
|
||||
);
|
||||
}
|
32
public/objects/typography/Title.jsx
Normal file
32
public/objects/typography/Title.jsx
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default function(props) {
|
||||
return (
|
||||
<h1 className={ "o-title" + ( props.className ? " " + props.className : "") }>
|
||||
{ props.children }
|
||||
</h1>
|
||||
);
|
||||
}
|
41
public/objects/typography/Typography.jsx
Normal file
41
public/objects/typography/Typography.jsx
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import Title from './Title';
|
||||
import Subtitle from './Subtitle';
|
||||
import Paragraph from './Paragraph';
|
||||
import Heading, { Heading1, Heading2, Heading3, Heading4, Heading5, Heading6 } from './Heading';
|
||||
|
||||
export {
|
||||
Title,
|
||||
Subtitle,
|
||||
Paragraph,
|
||||
|
||||
Heading,
|
||||
Heading1,
|
||||
Heading2,
|
||||
Heading3,
|
||||
Heading4,
|
||||
Heading5,
|
||||
Heading6
|
||||
}
|
164
public/objects/video/Video.jsx
Normal file
164
public/objects/video/Video.jsx
Normal file
@ -0,0 +1,164 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
import Loader from './../loading/Loader';
|
||||
import Image from './../image/Image';
|
||||
|
||||
//Adjust the order to adjust the load position
|
||||
const VALID_SOURCES = [
|
||||
"webm",
|
||||
"mp4",
|
||||
"ogg"
|
||||
]
|
||||
|
||||
export default class Video extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
//Initial State
|
||||
this.state = {
|
||||
autoPlay: this.props.autoPlay,
|
||||
loop: this.props.loop,
|
||||
loader: false,
|
||||
controls: this.props.controls
|
||||
};
|
||||
|
||||
//Bound events (for removing event listeners)
|
||||
this.onPlayingBound = this.onPlaying.bind(this);
|
||||
this.onWaitingBound = this.onWaiting.bind(this);
|
||||
this.onPauseBound = this.onPause.bind(this);
|
||||
this.onSeekedBound = this.onSeeked.bind(this);
|
||||
this.onLoadStartBound = this.onLoadStart.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.refs.video.addEventListener('playing', this.onPlayingBound);
|
||||
this.refs.video.addEventListener('waiting', this.onWaitingBound);
|
||||
this.refs.video.addEventListener('seeked', this.onSeekedBound);
|
||||
this.refs.video.addEventListener('pause', this.onPauseBound);
|
||||
this.refs.video.addEventListener('loadstart', this.onLoadStartBound);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
}
|
||||
|
||||
//Standard Events - https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events
|
||||
onPlaying() {
|
||||
this.setState({
|
||||
loader: false
|
||||
});
|
||||
}
|
||||
|
||||
onPause() {
|
||||
this.setState({
|
||||
loader: false
|
||||
});
|
||||
}
|
||||
|
||||
onSeeked() {
|
||||
this.setState({
|
||||
loader: false
|
||||
});
|
||||
}
|
||||
|
||||
onLoadStart() {
|
||||
if(this.isPaused()) return;
|
||||
this.setState({
|
||||
loader: true
|
||||
});
|
||||
}
|
||||
|
||||
onWaiting() {
|
||||
this.setState({
|
||||
loader: true
|
||||
});
|
||||
}
|
||||
|
||||
//Media Highlevel Functions
|
||||
isPaused() {
|
||||
return this.refs.video.paused
|
||||
}
|
||||
|
||||
//React Render
|
||||
render() {
|
||||
//TODO: Add state support, as well as functional controls.
|
||||
|
||||
//Sources
|
||||
let sources = [];
|
||||
let sourceProps = this.props.sources ? this.props.sources : this.props;
|
||||
|
||||
for(let i = 0; i < VALID_SOURCES.length; i++) {
|
||||
let s = VALID_SOURCES[i];
|
||||
if(!sourceProps[s]) continue;
|
||||
sources.push(<source type={"video/"+s} src={sourceProps[s]} key={s} />);
|
||||
}
|
||||
|
||||
//Classes
|
||||
let clazz = "o-video";
|
||||
if(this.props.className) clazz += " " + this.props.className;
|
||||
if(sourceProps.image) clazz += " has-image";
|
||||
if(sourceProps.gif) clazz += " has-gif";
|
||||
if(this.state.autoplay) clazz += " is-autoplaying";
|
||||
if(this.state.loop) clazz += " is-looping";
|
||||
|
||||
let videoClass = "o-video__video";
|
||||
if(this.props.fill) videoClass += " is-full";
|
||||
|
||||
|
||||
//Fallback.
|
||||
let fallback;
|
||||
if(sourceProps.image) {
|
||||
fallback = <Image image={sourceProps.image} alt={sourceProps.alt} className="o-video__image" />
|
||||
}
|
||||
|
||||
//Loader
|
||||
let loader;
|
||||
if(this.state.loader) {
|
||||
loader = <Loader className="o-video__loader" />
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className={clazz}>
|
||||
{ /* Video Element (And sources) */ }
|
||||
<video
|
||||
className={ videoClass }
|
||||
autoPlay={this.state.autoPlay}
|
||||
loop={this.state.loop}
|
||||
controls={this.state.controls}
|
||||
ref="video"
|
||||
>
|
||||
{ sources }
|
||||
</video>
|
||||
|
||||
{/* Loader */}
|
||||
{ loader }
|
||||
|
||||
{ /* Fallback Picture */ }
|
||||
{ fallback }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
65
public/objects/window/AddressBar.jsx
Normal file
65
public/objects/window/AddressBar.jsx
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import Frame from './Frame';
|
||||
import Language from './../language/Language';
|
||||
|
||||
class AddressBar extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
onChange() {
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
let clazz = "o-window__address-bar";
|
||||
|
||||
return (
|
||||
<div className={clazz}>
|
||||
<span className="o-window__address-bar-title">
|
||||
{ Language.get("window.address") }
|
||||
</span>
|
||||
<Frame className="o-window__address-bar-frame">
|
||||
<input
|
||||
type="text"
|
||||
value={this.props.href}
|
||||
className="o-window__input o-window__address-bar-input"
|
||||
onChange={ this.onChange.bind(this) }
|
||||
/>
|
||||
</Frame>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
code: state.language.code
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(AddressBar);
|
53
public/objects/window/ContextMenu.jsx
Normal file
53
public/objects/window/ContextMenu.jsx
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
class ContextMenu extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="o-window__context-menu" ref="menu">
|
||||
{ this.props.children }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default ContextMenu;
|
||||
|
||||
const ContextMenuOption = (props) => {
|
||||
return (
|
||||
<div className="o-window__context-menu-option">
|
||||
<div className="o-window__context-menu-option-title">
|
||||
{ props.title }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export {
|
||||
ContextMenuOption
|
||||
}
|
37
public/objects/window/Frame.jsx
Normal file
37
public/objects/window/Frame.jsx
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default (props) => {
|
||||
let clazz = "o-window__frame";
|
||||
if(props.className) {
|
||||
clazz += " " + props.className;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={clazz}>
|
||||
{ props.children }
|
||||
</div>
|
||||
);
|
||||
}
|
143
public/objects/window/MenuBar.jsx
Normal file
143
public/objects/window/MenuBar.jsx
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
import ContextMenu from './ContextMenu';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export default (props) => {
|
||||
return (
|
||||
<div className="o-window__menu-bar">
|
||||
{ props.children }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
class MenuOption extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
//Bound Methods
|
||||
this.onClickBound = this.onClick.bind(this);
|
||||
this.onMouseLeaveBound = this.onMouseLeave.bind(this);
|
||||
|
||||
this.state = {
|
||||
open: false,
|
||||
disabled: props.disabled || false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hasMenu() {
|
||||
return this.props.menu;
|
||||
}
|
||||
|
||||
isMenuOpen() { return this.state.open; }
|
||||
isDisabled() { return this.state.disabled; }
|
||||
|
||||
//Event Handlers
|
||||
onClick() {
|
||||
if(this.isDisabled()) return;
|
||||
if(this.hasMenu()) {
|
||||
this.setState({
|
||||
open: !this.state.open
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onMouseLeave() {
|
||||
if(!this.hasMenu()) return;
|
||||
if(!this.isMenuOpen()) return;
|
||||
|
||||
this.setState({
|
||||
open: false
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
//Add event listeners
|
||||
this.refs.button.addEventListener('click', this.onClickBound);
|
||||
this.refs.option.addEventListener('mouseleave', this.onMouseLeaveBound);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
//Remove event listeners
|
||||
this.refs.button.removeEventListener('click', this.onClickBound);
|
||||
this.refs.option.removeEventListener('mouseleave', this.onMouseLeaveBound);
|
||||
}
|
||||
|
||||
//Render method
|
||||
render() {
|
||||
let menu;
|
||||
let button;
|
||||
|
||||
if(this.props.menu) {
|
||||
menu = (
|
||||
<ContextMenu>
|
||||
{ this.props.menu }
|
||||
</ContextMenu>
|
||||
);
|
||||
clazz += " has-menu";
|
||||
}
|
||||
|
||||
if(this.props.href) {
|
||||
button = (
|
||||
<a href={this.props.href} className="o-window__menu-bar-button" ref="button" target={this.props.target}>
|
||||
{ this.props.title }
|
||||
</a>
|
||||
);
|
||||
} else if(this.props.to) {
|
||||
button = (
|
||||
<Link to={this.props.to} className="o-window__menu-bar-button" ref="button" target={this.props.target}>
|
||||
{ this.props.title }
|
||||
</Link>
|
||||
);
|
||||
} else {
|
||||
button = (
|
||||
<div className="o-window__menu-bar-button" ref="button">
|
||||
{this.props.title}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let clazz = "o-window__menu-bar-option"
|
||||
if(this.props.disabled) {
|
||||
clazz += " is-disabled";
|
||||
}
|
||||
|
||||
if(this.state.open) {
|
||||
clazz += " is-active";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={clazz} ref="option">
|
||||
{ button }
|
||||
{ menu }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
MenuOption
|
||||
};
|
69
public/objects/window/TitleBar.jsx
Normal file
69
public/objects/window/TitleBar.jsx
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
//Title Bar
|
||||
export default (props) => {
|
||||
return (
|
||||
<div className="o-window__title-bar">
|
||||
<div className="o-window__title-bar-buttons">
|
||||
{ props.buttons }
|
||||
</div>
|
||||
|
||||
<div className="o-window__title-bar-title">
|
||||
{ props.children }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
//Buttons
|
||||
const TitleBarButton = (props) => {
|
||||
let clz = "o-window__title-bar-button";
|
||||
if(props.className) clz += " o-window__title-bar-button--"+props.className;
|
||||
if(props.disabled) clz += " is-disabled";
|
||||
return (
|
||||
<div className={clz}>
|
||||
{ props.children }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const Close = (props) => {
|
||||
return (
|
||||
<TitleBarButton {...props} className="close" title="Close" />
|
||||
);
|
||||
}
|
||||
|
||||
const Minimize = (props) => {
|
||||
return (
|
||||
<TitleBarButton {...props} className="minimize" title="Minimize" />
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
TitleBarButton,
|
||||
Close,
|
||||
Minimize
|
||||
}
|
53
public/objects/window/Window95.jsx
Normal file
53
public/objects/window/Window95.jsx
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
import TitleBar, { Close, Minimize } from './TitleBar';
|
||||
import MenuBar, { MenuOption } from './MenuBar';
|
||||
import ContextMenu, { ContextMenuOption } from './ContextMenu';
|
||||
import Frame from './Frame';
|
||||
import AddressBar from './AddressBar';
|
||||
|
||||
export default (props) => {
|
||||
return (
|
||||
<div className="o-window">
|
||||
{ props.children }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
TitleBar,
|
||||
Close,
|
||||
Minimize,
|
||||
|
||||
MenuBar,
|
||||
MenuOption,
|
||||
|
||||
ContextMenu,
|
||||
ContextMenuOption,
|
||||
|
||||
Frame,
|
||||
|
||||
AddressBar
|
||||
}
|
Reference in New Issue
Block a user