76 | }
77 | )
78 | }
79 | }
80 |
81 | export default BodymovinFolder
--------------------------------------------------------------------------------
/src/components/bodymovin/bodymovin_refresh.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Bodymovin from './bodymovin'
3 | import refresh from '../../assets/animations/refresh.json'
4 | import { StyleSheet, css } from 'aphrodite'
5 |
6 | const styles = StyleSheet.create({
7 | wrapper: {
8 | width: '100%',
9 | height: '100%',
10 | background:'none',
11 | cursor: 'pointer'
12 | }
13 | })
14 |
15 | class BodymovinCheckbox extends React.Component {
16 |
17 | constructor() {
18 | super()
19 | this.handleMouseEnter = this.handleMouseEnter.bind(this)
20 | this.handleMouseLeave = this.handleMouseLeave.bind(this)
21 | }
22 |
23 | handleMouseEnter(){
24 | this.bm_instance.resetSegments(true)
25 | this.bm_instance.playSegments([[0,29],[29,58]], true)
26 | this.bm_instance.loop(true)
27 | }
28 |
29 | handleMouseLeave(){
30 | let currentFrame = this.bm_instance.getCurrentFrame()
31 | let firstFrame = this.bm_instance.getFirstFrame()
32 | this.bm_instance.resetSegments(true)
33 | this.bm_instance.playSegments([[currentFrame + firstFrame,0]], true)
34 | this.bm_instance.loop(false)
35 |
36 | }
37 |
38 | render() {
39 | return (
this.bm_instance = elem} animationLoaded={this.checkAnimation} animationData={refresh} autoplay={false} loop={true}>
40 |
41 | )
42 | }
43 | }
44 |
45 | export default BodymovinCheckbox
--------------------------------------------------------------------------------
/src/components/bodymovin/bodymovin_settings.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Bodymovin from './bodymovin'
3 | class BodymovinSettings extends React.Component {
4 |
5 | constructor() {
6 | super()
7 | this.checkAnimation = this.checkAnimation.bind(this)
8 | }
9 |
10 | componentWillReceiveProps(props) {
11 | if (props.animate && !this.props.animate) {
12 | this.bm_instance.goToAndPlay(0)
13 | } else if (!props.animate && this.props.animate) {
14 | this.bm_instance.goToAndStop(0)
15 | }
16 | }
17 |
18 | checkAnimation() {
19 | if(this.props.animate) {
20 | this.bm_instance.goToAndPlay(0)
21 | } else {
22 | this.bm_instance.goToAndStop(0)
23 | }
24 | }
25 |
26 | render() {
27 | return (
this.bm_instance = elem} animationLoaded={this.checkAnimation} animationData={this.props.animationData}>
28 | {this.props.children}
29 | )
30 | }
31 | }
32 |
33 | export default BodymovinSettings
--------------------------------------------------------------------------------
/src/components/bodymovin/bodymovin_toggle.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Bodymovin from './bodymovin'
3 | class BodymovinToggle extends React.PureComponent {
4 |
5 | constructor() {
6 | super()
7 | this.checkAnimation = this.checkAnimation.bind(this)
8 | }
9 |
10 | componentWillReceiveProps(props) {
11 | if (props.toggle !== this.props.toggle) {
12 | if(props.toggle === 'on') {
13 | this.bm_instance.setDirection(1)
14 | } else {
15 | this.bm_instance.setDirection(-1)
16 | }
17 | this.bm_instance.play()
18 | }
19 | }
20 |
21 | checkAnimation() {
22 | if(this.props.toggle === 'on') {
23 | this.bm_instance.goToAndPlay(0)
24 | } else {
25 | this.bm_instance.goToAndStop(0)
26 | }
27 | }
28 |
29 | render() {
30 | return (
this.bm_instance = elem} animationLoaded={this.checkAnimation} animationData={this.props.animationData}>
31 | {this.props.children}
32 | )
33 | }
34 | }
35 |
36 | export default BodymovinToggle
--------------------------------------------------------------------------------
/src/components/buttons/Base_button.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, css } from 'aphrodite'
3 | import Variables from '../../helpers/styles/variables'
4 | import Bodymovin from '../bodymovin/bodymovin'
5 |
6 | const styles = StyleSheet.create({
7 | container: {
8 | borderRadius: '3px',
9 | padding: '8px 20px',
10 | color: 'white',
11 | fontSize: '12px',
12 | fontFamily: 'Roboto-Bold',
13 | verticalAlign:'middle',
14 | cursor: 'pointer',
15 | whiteSpace: 'nowrap',
16 | overflow: 'hidden',
17 | textOverflow: 'ellipsis',
18 | minWidth: '80px'
19 | },
20 | green: {
21 | backgroundColor: Variables.colors.green,
22 | color: Variables.colors.white,
23 | ':disabled': {
24 | color: Variables.colors.gray2,
25 | backgroundColor: Variables.colors.gray,
26 | cursor: 'default'
27 | },
28 | ':hover': {
29 | backgroundColor: Variables.colors.green2,
30 | color: Variables.colors.white
31 | },
32 | disabled:{
33 | color: Variables.colors.gray2,
34 | backgroundColor: Variables.colors.gray,
35 | cursor: 'default'
36 | }
37 | },
38 | gray: {
39 | backgroundColor: Variables.colors.gray_lighter,
40 | border: '1px solid ' + Variables.colors.button_gray_text,
41 | color: Variables.colors.button_gray_text,
42 | ':disabled': {
43 | color: Variables.colors.gray2,
44 | cursor: 'default'
45 | },
46 | ':hover': {
47 | backgroundColor: Variables.colors.gray_lighter,
48 | color: Variables.colors.white,
49 | border: '1px solid ' + Variables.colors.white
50 | }
51 | },
52 | icon: {
53 | display: 'inline-block',
54 | width: '23px',
55 | height: '16px',
56 | verticalAlign: 'top',
57 | marginRight: '10px'
58 | }
59 |
60 | });
61 |
62 | class BaseButton extends React.Component{
63 |
64 | constructor(){
65 | super()
66 | this.mouseEnterHandler = this.mouseEnterHandler.bind(this)
67 | this.mouseLeaveHandler = this.mouseLeaveHandler.bind(this)
68 | }
69 |
70 | mouseEnterHandler(){
71 | if(this.bm_instance){
72 | this.bm_instance.goToAndPlay(0)
73 | }
74 | }
75 |
76 | mouseLeaveHandler(){
77 | if(this.bm_instance){
78 | this.bm_instance.goToAndStop(0)
79 | }
80 | }
81 |
82 | render(){
83 | let containerClasses = css(
84 | styles.container,
85 | this.props.type === 'green' && styles.green,
86 | this.props.type === 'gray' && styles.gray,
87 | this.props.disabled && styles.disabled,
88 | this.props.classes
89 | )
90 |
91 | return (
)
97 | }
98 |
99 | }
100 |
101 | BaseButton.defaultProps = {
102 | disabled: false
103 | }
104 |
105 | export default BaseButton
--------------------------------------------------------------------------------
/src/components/footer/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {connect} from 'react-redux'
3 | import { StyleSheet, css } from 'aphrodite'
4 |
5 | const styles = StyleSheet.create({
6 | wrapper: {
7 | height: '10px',
8 | position: 'absolute',
9 | bottom:'4px',
10 | right:'0',
11 | overflow: 'hidden',
12 | 'font-size': '10px',
13 | padding: '0 10px',
14 | color: '#aaa'
15 | }
16 | })
17 |
18 | class Footer extends React.PureComponent {
19 |
20 | render() {
21 | return (
{'Version: ' + this.props.version}
22 |
)
23 | }
24 | }
25 |
26 | function mapStateToProps(state) {
27 | return {version: state.project.version}
28 | }
29 |
30 | export default connect(mapStateToProps, null)(Footer)
--------------------------------------------------------------------------------
/src/components/header/Main_header.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, css } from 'aphrodite'
3 | import BaseButton from '../buttons/Base_button'
4 | import BodymovinRefresh from '../bodymovin/bodymovin_refresh'
5 | import Variables from '../../helpers/styles/variables'
6 |
7 | const styles = StyleSheet.create({
8 | container: {
9 | width: '100%',
10 | marginBottom: '10px'
11 | },
12 | right: {
13 | float: 'right'
14 | },
15 | buttons_container: {
16 | width: '100%',
17 | height: '50px',
18 | display: 'flex',
19 | alignItems:'center'
20 | },
21 | button: {
22 | marginRight:'7px',
23 | flexGrow: 0,
24 | },
25 | buttons_separator: {
26 | flexGrow: 1
27 | },
28 | refresh: {
29 | width: '40px',
30 | height: '31px',
31 | backgroundColor: 'transparent',
32 | verticalAlign:'middle',
33 | cursor: 'pointer',
34 | transition: 'transform 500ms ease-out',
35 | webkitFilter: 'saturate(100%)'
36 | },
37 | refresh_image: {
38 | maxWidth: '100%',
39 | maxHeight: '100%'
40 | },
41 | separator: {
42 | width: '100%',
43 | height: '1px',
44 | backgroundColor: Variables.colors.gray2,
45 | marginTop: '20px',
46 | marginBottom: '20px'
47 | }
48 | })
49 |
50 | function Main_header(props) {
51 | return (
)
60 | }
61 |
62 | export default Main_header
--------------------------------------------------------------------------------
/src/components/range/Range.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, css } from 'aphrodite'
3 | import Thumb from '../../assets/svg/preview_thumb.svg'
4 | import Variables from '../../helpers/styles/variables'
5 |
6 | const styles = StyleSheet.create({
7 | container: {
8 | width: '100%',
9 | height: '30px',
10 | backgroundColor:'transparent',
11 | position: 'relative',
12 | top: 0,
13 | left: 0,
14 | cursor: 'pointer'
15 | },
16 | progress: {
17 | width: '100%',
18 | height: '10px',
19 | position: 'absolute',
20 | margin: 'auto',
21 | top:0,
22 | bottom:0,
23 | backgroundColor: Variables.colors.gray_darkest,
24 | borderRadius: '5px',
25 | overflow:'hidden'
26 | },
27 | progress_color: {
28 | width: '100%',
29 | height: '100%',
30 | background: Variables.gradients.blueGreenFull
31 | },
32 | thumb: {
33 | width: '20px',
34 | height: '20px',
35 | position: 'absolute',
36 | margin: 'auto',
37 | top:0,
38 | bottom:0,
39 | pointerEvents: 'none'
40 | },
41 | thumbDisplay: {
42 | width: '100%',
43 | height: '100%',
44 | transform: 'translateX(-50%)'
45 | }
46 | })
47 |
48 | class Range extends React.Component {
49 |
50 | constructor(){
51 | super()
52 | this.state = {
53 | isDown:false,
54 | width: 0,
55 | mix: 0
56 | }
57 | this.mouseUpHandler = this.mouseUpHandler.bind(this)
58 | this.mouseMoveHandler = this.mouseMoveHandler.bind(this)
59 | this.mouseDownHandler = this.mouseDownHandler.bind(this)
60 | this.resizeHandler = this.resizeHandler.bind(this)
61 | }
62 |
63 | componentWillUpdate(nextProps, nextState) {
64 | if(nextState.isDown === true && this.state.isDown === false) {
65 | document.addEventListener('mouseup', this.mouseUpHandler)
66 | document.addEventListener('mousemove', this.mouseMoveHandler)
67 | }
68 | }
69 |
70 | mouseMoveHandler(ev) {
71 | if(!this.state.isDown){
72 | return
73 | }
74 | this.props.updateProgress(Math.min(Math.max(0,(ev.clientX - this.state.min) / (this.state.width)),1))
75 | }
76 |
77 | mouseUpHandler(ev) {
78 | document.removeEventListener('mouseup', this.mouseUpHandler)
79 | document.removeEventListener('mousemove', this.mouseMoveHandler)
80 | this.setState({
81 | isDown: false
82 | })
83 | }
84 |
85 | mouseDownHandler(ev) {
86 | if(!this.props.canScrub){
87 | return
88 | }
89 | var rect = this.container.getBoundingClientRect()
90 | this.setState({
91 | isDown: true,
92 | width: rect.right - rect.left,
93 | min: rect.left
94 | })
95 | this.props.updateProgress((ev.clientX - rect.left) / (rect.right - rect.left))
96 | }
97 |
98 | resizeHandler() {
99 | var rect = this.container.getBoundingClientRect()
100 | this.setState({
101 | width: rect.right - rect.left,
102 | min: rect.left,
103 | })
104 | }
105 |
106 | componentDidMount() {
107 | window.addEventListener('resize', this.resizeHandler)
108 | this.resizeHandler()
109 | }
110 |
111 | componentWillUnmount() {
112 | window.removeEventListener('resize', this.resizeHandler)
113 | document.removeEventListener('mouseup', this.mouseUpHandler)
114 | document.removeEventListener('mousemove', this.mouseMoveHandler)
115 | }
116 |
117 | render() {
118 | let pos = this.state.width * this.props.progress
119 | let styler = {
120 | 'transform':'translateX(' + pos + 'px)',
121 | 'WebkitTransform':'translateX(' + pos + 'px)'
122 | }
123 |
124 | let progressStyler = {
125 | 'transform':'translateX(' + -(1-this.props.progress)*100 + '%)',
126 | 'WebkitTransform':'translateX(' + -(1-this.props.progress)*100 + '%)'
127 | }
128 |
129 | return (
this.container = elem}
131 | className={css(styles.container)}
132 | onMouseDown={this.mouseDownHandler} >
133 |
138 |
139 |
140 |

141 |
142 |
143 |
)
144 | }
145 | }
146 |
147 | export default Range
--------------------------------------------------------------------------------
/src/helpers/CSInterfaceHelper.js:
--------------------------------------------------------------------------------
1 | import {CSInterface} from './CSInterface'
2 | var csInterface = new CSInterface();
3 |
4 | export default csInterface
--------------------------------------------------------------------------------
/src/helpers/CompositionsStateSync.js:
--------------------------------------------------------------------------------
1 | import csInterface from './CSInterfaceHelper'
2 | import extensionLoader from './ExtensionLoader'
3 |
4 | function setCompositionSelection(comp) {
5 | extensionLoader.then(function(){
6 | var eScript = '$.__bodymovin.bm_compsManager.setCompositionSelectionState(' + comp.id + ',' + comp.selected + ')'
7 | csInterface.evalScript(eScript)
8 | })
9 | }
10 |
11 | export {
12 | setCompositionSelection
13 | }
--------------------------------------------------------------------------------
/src/helpers/DataCompressorHelper.js:
--------------------------------------------------------------------------------
1 | var zlib = require('zlib');
2 |
3 | function compressData(data) {
4 | let path = data.path
5 | let message = data.message
6 |
7 | var input = new Buffer(message, 'utf8')
8 | return new Promise(function(res, rej) {
9 | zlib.gzip(input, {level: zlib.Z_BEST_COMPRESSION}, function(err, buf) {
10 | res({path: path, buf: buf})
11 | })
12 | });
13 | }
14 |
15 | export default compressData
16 |
--------------------------------------------------------------------------------
/src/helpers/ExtensionLoader.js:
--------------------------------------------------------------------------------
1 | import {SystemPath} from './CSInterface'
2 | import csInterface from './CSInterfaceHelper'
3 |
4 | var fileName = 'initializer.jsx';
5 | var promise = new Promise(loadJSX);
6 | var isRunning = false;
7 |
8 | function loadJSX(resolve, reject) {
9 | function init(){
10 | if(isRunning) {
11 | return;
12 | }
13 | isRunning = true;
14 | var extensionRoot = csInterface.getSystemPath(SystemPath.EXTENSION) + "/jsx/";
15 | csInterface.evalScript('$.evalFile("' + extensionRoot + fileName + '");'
16 | , function(){
17 | window.removeEventListener('focus', init);
18 | window.removeEventListener('click', init);
19 | window.removeEventListener('mousedown', init);
20 | window.removeEventListener('mouseenter', init);
21 | window.removeEventListener('mouseover', init);
22 | window.removeEventListener('mousemove', init);
23 | resolve();
24 | });
25 | }
26 | window.addEventListener('focus', init);
27 | window.addEventListener('click', init);
28 | window.addEventListener('mousedown', init);
29 | window.addEventListener('mouseenter', init);
30 | window.addEventListener('mouseover', init);
31 | window.addEventListener('mousemove', init);
32 | }
33 |
34 | export default promise;
--------------------------------------------------------------------------------
/src/helpers/FileBrowser.js:
--------------------------------------------------------------------------------
1 | import csInterface from './CSInterfaceHelper'
2 | import extensionLoader from './ExtensionLoader'
3 |
4 | var resolve, reject
5 |
6 | csInterface.addEventListener('bm:file:uri', function (ev) {
7 | resolve(ev.data)
8 | })
9 |
10 | csInterface.addEventListener('bm:file:cancel', function (ev) {
11 | reject()
12 | })
13 |
14 | function browseFile(path) {
15 | var promise = new Promise(function(_resolve, _reject) {
16 | resolve = _resolve
17 | reject = _reject
18 | })
19 |
20 | extensionLoader.then(function(){
21 | path = path ? path.replace(/\\/g,"\\\\") : ''
22 | var eScript = '$.__bodymovin.bm_main.browseFile("' + path + '")';
23 | csInterface.evalScript(eScript);
24 | })
25 | return promise
26 | }
27 |
28 | export default browseFile
--------------------------------------------------------------------------------
/src/helpers/FileLoader.js:
--------------------------------------------------------------------------------
1 | function loadBodymovinFileData(path) {
2 | var reject, resolve
3 | var promise = new Promise(function(_resolve, _reject) {
4 | resolve = _resolve
5 | reject = _reject
6 | })
7 | var result = window.cep.fs.readFile(path)
8 | try {
9 | if(result.err === 0) {
10 | var jsonData = JSON.parse(result.data)
11 | if(jsonData.v) {
12 | resolve(jsonData)
13 | }
14 | } else {
15 | reject()
16 | }
17 | } catch(err) {
18 | reject()
19 | }
20 |
21 | return promise
22 | }
23 |
24 | export default loadBodymovinFileData
--------------------------------------------------------------------------------
/src/helpers/FileSaver.js:
--------------------------------------------------------------------------------
1 | function saveFile(data, formats, name) {
2 | var result;
3 | try {
4 | result = window.cep.fs.showSaveDialogEx('Select location', '', formats, name);
5 | } catch(err) {
6 | result = window.cep.fs.showOpenDialog(false, true);
7 | }
8 | if(result.data) {
9 | var targetFilePath = (result.data instanceof Array) ? result.data[0] + '/snapshot.svg' : result.data;
10 | var writeResult = window.cep.fs.writeFile(targetFilePath, data);
11 | if (0 !== writeResult.err) {
12 | console.log('ERROR: ', writeResult.err)
13 | }
14 | }
15 | }
16 |
17 | export default saveFile
--------------------------------------------------------------------------------
/src/helpers/RenderBridge.js:
--------------------------------------------------------------------------------
1 | import csInterface from './CSInterfaceHelper'
2 | import {dispatcher} from './storeDispatcher'
3 | import actions from '../redux/actions/actionTypes'
4 |
5 | csInterface.addEventListener('bm:render:start', function (ev) {
6 | if(ev.data) {
7 | } else {
8 | }
9 | });
10 |
11 | csInterface.addEventListener('bm:render:complete', function (ev) {
12 | if(ev.data) {
13 | } else {
14 | }
15 | });
16 |
17 | csInterface.addEventListener('bm:render:update', function (ev) {
18 | if(ev.data) {
19 | } else {
20 | }
21 | });
22 |
23 | csInterface.addEventListener('bm:render:fonts', function (ev) {
24 | if(ev.data) {
25 | } else {
26 | }
27 | });
28 |
29 |
30 | csInterface.addEventListener('bm:render:chars', function (ev) {
31 | if(ev.data) {
32 | } else {
33 | }
34 | });
35 |
36 |
--------------------------------------------------------------------------------
/src/helpers/fs_proxy.js:
--------------------------------------------------------------------------------
1 | function proxy_fs() {
2 | return window.__fs
3 | }
4 |
5 | module.exports = proxy_fs()
--------------------------------------------------------------------------------
/src/helpers/localStorageHelper.js:
--------------------------------------------------------------------------------
1 | function getProjectFromLocalStorage(id) {
2 | let resolve, reject
3 | let prom = new Promise(function(_resolve, _reject){
4 | resolve = _resolve
5 | reject = _reject
6 | })
7 | try {
8 | var project = localStorage.getItem('project_' + id);
9 | if(project) {
10 | resolve(JSON.parse(project))
11 | } else {
12 | reject()
13 | }
14 | } catch(err) {
15 | reject()
16 | }
17 | return prom
18 | }
19 |
20 | function saveProjectToLocalStorage(data, id) {
21 | let resolve, reject
22 | let prom = new Promise(function(_resolve, _reject){
23 | resolve = _resolve
24 | reject = _reject
25 | })
26 | try {
27 | let serialized = JSON.stringify(data)
28 | localStorage.setItem('project_' + id, serialized)
29 | resolve()
30 | } catch(err) {
31 | reject()
32 | }
33 | return prom
34 | }
35 |
36 | function getFontsFromLocalStorage(fonts) {
37 | let resolve, reject
38 | let prom = new Promise(function(_resolve, _reject){
39 | resolve = _resolve
40 | reject = _reject
41 | })
42 | var storedFonts = JSON.parse(localStorage.getItem('fonts'))
43 | storedFonts = storedFonts || []
44 | let len = storedFonts.length, i = 0
45 | let storedFont
46 | let storedData = fonts.map(function(item){
47 | storedFont = {
48 | fName: item.name,
49 | data:null
50 | }
51 | i = 0
52 | while(i
animVersion[0]){
4 | return false;
5 | } else if(animVersion[0] > minimum[0]){
6 | return true;
7 | }
8 | if(minimum[1]>animVersion[1]){
9 | return false;
10 | } else if(animVersion[1] > minimum[1]){
11 | return true;
12 | }
13 | if(minimum[2]>animVersion[2]){
14 | return false;
15 | } else if(animVersion[2] > minimum[2]){
16 | return true;
17 | }
18 | }
19 |
20 | export default checkVersion
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | *{
2 | box-sizing: border-box;
3 | }
4 |
5 | html, body {
6 | margin: 0;
7 | padding: 0;
8 | font-family: Roboto, Tahoma, sans-serif;
9 | background-color: #474747;
10 | width: 100%;
11 | height: 100%;
12 | overflow: hidden;
13 | }
14 |
15 | button, input {
16 | font-family: Roboto, Tahoma, sans-serif;
17 | }
18 |
19 | button:focus {
20 | outline: none;
21 | }
22 |
23 | #root {
24 | height: 100%;
25 | }
26 |
27 | [data-reactroot]
28 | {height: 100% !important; }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import './index.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/redux/actions/actionTypes.js:
--------------------------------------------------------------------------------
1 | export default {
2 | COMPOSITION_DISPLAY_SETTINGS: 'COMPOSITIONS/DISPLAY_SETTINGS',
3 | COMPOSITIONS_FILTER_CHANGE: 'COMPOSITIONS/FILTER_CHANGE',
4 | COMPOSITIONS_GET_COMPS: 'COMPOSITIONS/GET_COMPS',
5 | COMPOSITION_GET_DESTINATION: 'COMPOSITIONS/GET_DESTINATION',
6 | COMPOSITION_SET_DESTINATION: 'COMPOSITIONS/SET_DESTINATION',
7 | COMPOSITIONS_TOGGLE_ITEM: 'COMPOSITIONS/TOGGLE_ITEM',
8 | COMPOSITIONS_UPDATED: 'COMPOSITIONS/UPDATED',
9 | COMPOSITIONS_SET_CURRENT_COMP_ID: 'COMPOSITIONS/SET_CURRENT_COMP_ID',
10 | GOTO_PREVIEW: 'GOTO/PREVIEW',
11 | GOTO_PLAYER: 'GOTO/PLAYER',
12 | GOTO_COMPS: 'GOTO/COMPS',
13 | GOTO_SETTINGS: 'GOTO/SETTINGS',
14 | GENERAL_LOG: 'GENERAL/LOG',
15 | PREVIEW_BROWSE_FILE: 'PREVIEW/BROWSE_FILE',
16 | PREVIEW_FILE_BROWSED: 'PREVIEW/FILE_BROWSED',
17 | PREVIEW_ANIMATION_LOADED: 'PREVIEW/ANIMATION_LOADED',
18 | PREVIEW_ANIMATION_LOAD_FAILED: 'PREVIEW/ANIMATION_LOAD_FAILED',
19 | PREVIEW_ANIMATION_PROGRESS: 'PREVIEW/ANIMATION_PROGRESS',
20 | PREVIEW_FROM_PATH: 'PREVIEW/FROM_PATH',
21 | PREVIEW_TOTAL_FRAMES: 'PREVIEW/TOTAL_FRAMES',
22 | PREVIEW_NO_CURRENT_RENDERS: 'PREVIEW/NO_CURRENT_RENDERS',
23 | RENDER_PROCESS_IMAGE: 'RENDER/PROCESS_IMAGE',
24 | PROJECT_SET_ID: 'PROJECT/SET_ID',
25 | PROJECT_STORED_DATA: 'PROJECT/STORED_DATA',
26 | RENDER_CREATE_AVD: 'RENDER/CREATE_AVD',
27 | RENDER_BLOCK: 'RENDER/BLOCK',
28 | RENDER_FONTS: 'RENDER/FONTS',
29 | RENDER_SET_FONTS: 'RENDER/SET_FONTS',
30 | RENDER_START: 'RENDER/START',
31 | RENDER_STOP: 'RENDER/STOP',
32 | RENDER_STORED_FONTS_FETCHED: 'RENDER/STORED_FONTS_FETCHED',
33 | RENDER_COMPLETE: 'RENDER/COMPLETE',
34 | RENDER_FINISHED: 'RENDER/FINISHED',
35 | RENDER_UPDATE: 'RENDER/UPDATE',
36 | RENDER_UPDATE_FONT_ORIGIN: 'RENDER/UPDATE_FONT_ORIGIN',
37 | RENDER_UPDATE_INPUT: 'RENDER/UPDATE_INPUT',
38 | SETTINGS_CANCEL: 'SETTINGS/CANCEL',
39 | SETTINGS_TOGGLE_VALUE: 'SETTINGS/TOGGLE_VALUE',
40 | SETTINGS_TOGGLE_EXTRA_COMP: 'SETTINGS/TOGGLE_EXTRA_COMP',
41 | SETTINGS_UPDATE_VALUE: 'SETTINGS/UPDATE_VALUE',
42 | SETTINGS_TOGGLE_SELECTED: 'SETTINGS/TOGGLE_SELECTED',
43 | ALERT_HIDE: 'ALERT/HIDE',
44 | PATHS_GET: 'PATHS/GET',
45 | PATHS_FETCHED: 'PATHS/FETCHED',
46 | VERSION_GET: 'VERSION/GET',
47 | VERSION_FETCHED: 'VERSION/FETCHED',
48 | APP_VERSION_FETCHED: 'APP_VERSION/FETCHED',
49 | WRITE_ERROR: 'WRITE/ERROR',
50 | TG_COMPRESS: 'TG/COMPRESS'
51 | }
--------------------------------------------------------------------------------
/src/redux/actions/compositionActions.js:
--------------------------------------------------------------------------------
1 | import actionTypes from './actionTypes'
2 |
3 | function filterChange(event) {
4 | return {
5 | type: actionTypes.COMPOSITIONS_FILTER_CHANGE,
6 | value: event.target.value
7 | }
8 | }
9 |
10 | function toggleItem(comp) {
11 | return {
12 | type: actionTypes.COMPOSITIONS_TOGGLE_ITEM,
13 | id: comp.id
14 | }
15 | }
16 |
17 | function getCompositions() {
18 | return {
19 | type: actionTypes.COMPOSITIONS_GET_COMPS
20 | }
21 | }
22 |
23 | function setDestination(comp) {
24 | return {
25 | type: actionTypes.COMPOSITION_SET_DESTINATION,
26 | comp: comp
27 | }
28 | }
29 |
30 | function getDestination(comp) {
31 | return {
32 | type: actionTypes.COMPOSITION_GET_DESTINATION,
33 | comp: comp
34 | }
35 | }
36 |
37 | function displaySettings(id) {
38 | return {
39 | type: actionTypes.COMPOSITION_DISPLAY_SETTINGS,
40 | id: id
41 | }
42 | }
43 |
44 | function setCurrentCompId(id) {
45 | return {
46 | type: actionTypes.COMPOSITIONS_SET_CURRENT_COMP_ID,
47 | id: id
48 | }
49 | }
50 |
51 | function cancelSettings(storedSettings) {
52 | return {
53 | type: actionTypes.SETTINGS_CANCEL,
54 | storedSettings: storedSettings
55 | }
56 | }
57 |
58 | function toggleSettingsValue(name) {
59 | return {
60 | type: actionTypes.SETTINGS_TOGGLE_VALUE,
61 | name: name
62 | }
63 | }
64 |
65 | function updateSettingsValue(name, value) {
66 | return {
67 | type: actionTypes.SETTINGS_UPDATE_VALUE,
68 | value: value,
69 | name: name
70 | }
71 | }
72 |
73 | function toggleExtraComp(id) {
74 | return {
75 | type: actionTypes.SETTINGS_TOGGLE_EXTRA_COMP,
76 | id: id,
77 | }
78 | }
79 |
80 | function goToPreview() {
81 | return {
82 | type: actionTypes.GOTO_PREVIEW,
83 | }
84 | }
85 |
86 | function goToPlayer() {
87 | return {
88 | type: actionTypes.GOTO_PLAYER,
89 | }
90 | }
91 |
92 | function goToComps() {
93 | return {
94 | type: actionTypes.GOTO_COMPS,
95 | }
96 | }
97 |
98 | function toggleShowSelected() {
99 | console.log('toggleShowSelected:')
100 | return {
101 | type: actionTypes.SETTINGS_TOGGLE_SELECTED,
102 | }
103 | }
104 |
105 | export {
106 | filterChange,
107 | toggleShowSelected,
108 | toggleItem,
109 | getCompositions,
110 | getDestination,
111 | setDestination,
112 | displaySettings,
113 | setCurrentCompId,
114 | cancelSettings,
115 | toggleSettingsValue,
116 | toggleExtraComp,
117 | updateSettingsValue,
118 | goToPreview,
119 | goToPlayer,
120 | goToComps
121 | }
--------------------------------------------------------------------------------
/src/redux/actions/generalActions.js:
--------------------------------------------------------------------------------
1 | import actionTypes from './actionTypes'
2 |
3 | function hideAlert() {
4 | return {
5 | type: actionTypes.ALERT_HIDE
6 | }
7 | }
8 | function getPaths() {
9 | return {
10 | type: actionTypes.PATHS_GET
11 | }
12 | }
13 |
14 | function getVersion() {
15 | return {
16 | type: actionTypes.VERSION_GET
17 | }
18 | }
19 |
20 | function versionFetched(version) {
21 | return {
22 | type: actionTypes.VERSION_FETCHED,
23 | version: version
24 | }
25 | }
26 |
27 | function appVersionFetched(version) {
28 | return {
29 | type: actionTypes.APP_VERSION_FETCHED,
30 | version: version
31 | }
32 | }
33 |
34 | export {
35 | hideAlert,
36 | getPaths,
37 | getVersion,
38 | versionFetched,
39 | appVersionFetched
40 | }
--------------------------------------------------------------------------------
/src/redux/actions/previewActions.js:
--------------------------------------------------------------------------------
1 | import actionTypes from './actionTypes'
2 |
3 | function browsePreviewFile(event) {
4 | return {
5 | type: actionTypes.PREVIEW_BROWSE_FILE
6 | }
7 | }
8 |
9 | function previewFileBrowsed(event) {
10 | return {
11 | type: actionTypes.PREVIEW_FILE_BROWSED
12 | }
13 | }
14 |
15 | function updateProgress(progress) {
16 | return {
17 | type: actionTypes.PREVIEW_ANIMATION_PROGRESS,
18 | progress: progress
19 | }
20 | }
21 |
22 | function setTotalFrames(value) {
23 | return {
24 | type: actionTypes.PREVIEW_TOTAL_FRAMES,
25 | totalFrames: value
26 | }
27 | }
28 |
29 | function showNoCurrentRenders(pars) {
30 | return {
31 | type: actionTypes.PREVIEW_NO_CURRENT_RENDERS
32 | }
33 | }
34 |
35 | function previewFromPath(path) {
36 | return {
37 | type: actionTypes.PREVIEW_FILE_BROWSED,
38 | path: path
39 | }
40 | }
41 |
42 | export {
43 | browsePreviewFile,
44 | previewFileBrowsed,
45 | updateProgress,
46 | setTotalFrames,
47 | showNoCurrentRenders,
48 | previewFromPath
49 | }
--------------------------------------------------------------------------------
/src/redux/actions/renderActions.js:
--------------------------------------------------------------------------------
1 | import actionTypes from './actionTypes'
2 |
3 | function startRender(comp) {
4 | return {
5 | type: actionTypes.RENDER_START
6 | }
7 | }
8 |
9 | function stopRender(comp) {
10 | return {
11 | type: actionTypes.RENDER_STOP
12 | }
13 | }
14 |
15 | function updateFontOrigin(origin, item) {
16 | return {
17 | type: actionTypes.RENDER_UPDATE_FONT_ORIGIN,
18 | item: item,
19 | origin: origin
20 | }
21 | }
22 |
23 | function updateInput(value, inputName, item) {
24 | return {
25 | type: actionTypes.RENDER_UPDATE_INPUT,
26 | item: item,
27 | inputName: inputName,
28 | value: value
29 | }
30 | }
31 |
32 | function setFonts() {
33 | return {
34 | type: actionTypes.RENDER_SET_FONTS
35 | }
36 | }
37 |
38 | function showRenderBlock(pars) {
39 | return {
40 | type: actionTypes.RENDER_BLOCK,
41 | pars: pars
42 | }
43 | }
44 |
45 | export {
46 | startRender,
47 | stopRender,
48 | updateFontOrigin,
49 | updateInput,
50 | setFonts,
51 | showRenderBlock
52 | }
--------------------------------------------------------------------------------
/src/redux/reducers/alerts.js:
--------------------------------------------------------------------------------
1 | import actionTypes from '../actions/actionTypes'
2 |
3 | let initialState = {
4 | show: false,
5 | type: '',
6 | pars:[]
7 | }
8 |
9 | export default function project(state = initialState, action) {
10 | switch (action.type) {
11 | case actionTypes.RENDER_BLOCK:
12 | case actionTypes.WRITE_ERROR:
13 | return {...state, ...{show: true, pars:action.pars}}
14 | case actionTypes.PREVIEW_NO_CURRENT_RENDERS:
15 | return {...state, ...{show: true, pars:['You have no current renders to preview','Try browsing your files to select a .json file']}}
16 | case actionTypes.PREVIEW_ANIMATION_LOAD_FAILED:
17 | return {...state, ...{show: true, pars:['The animation could not be loaded']}}
18 | /*case actionTypes.GENERAL_LOG:
19 | return {...state, ...{show: true, pars:[action.data]}}*/
20 | case actionTypes.ALERT_HIDE:
21 | return {...state, ...{show: false}}
22 | default:
23 | return state
24 | }
25 | }
--------------------------------------------------------------------------------
/src/redux/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux'
2 | import compositions from './compositions'
3 | import render from './render'
4 | import project from './project'
5 | import preview from './preview'
6 | import alerts from './alerts'
7 | import paths from './paths'
8 | import routes from './routes'
9 |
10 | export default combineReducers({
11 | routes,
12 | compositions,
13 | render,
14 | project,
15 | preview,
16 | alerts,
17 | paths
18 | })
--------------------------------------------------------------------------------
/src/redux/reducers/paths.js:
--------------------------------------------------------------------------------
1 | import actionTypes from '../actions/actionTypes'
2 |
3 | let initialState = {
4 | destinationPath: '',
5 | previewPath: ''
6 | }
7 |
8 | function setDestinationPath(state, action) {
9 | let newState = {...state}
10 | let destinationPath = action.compositionData.destination.substring(0,action.compositionData.destination.lastIndexOf('\\') + 1)
11 | newState.destinationPath = destinationPath
12 | return newState
13 | }
14 |
15 | function setPreviewPath(state, action) {
16 | let newState = {...state}
17 | let previewPath = action.path.substring(0,action.path.lastIndexOf('\\') + 1)
18 | newState.previewPath = previewPath
19 | return newState
20 | }
21 |
22 | export default function project(state = initialState, action) {
23 | switch (action.type) {
24 | case actionTypes.COMPOSITION_SET_DESTINATION:
25 | return setDestinationPath(state, action)
26 | case actionTypes.PREVIEW_FILE_BROWSED:
27 | return setPreviewPath(state, action)
28 | case actionTypes.PATHS_FETCHED:
29 | return action.pathsData
30 | default:
31 | return state
32 | }
33 | }
--------------------------------------------------------------------------------
/src/redux/reducers/preview.js:
--------------------------------------------------------------------------------
1 | import actionTypes from '../actions/actionTypes'
2 |
3 | let initialState = {
4 | progress: 0,
5 | animationData: null,
6 | path: null,
7 | totalFrames:0
8 | }
9 |
10 | export default function project(state = initialState, action) {
11 | switch (action.type) {
12 | case actionTypes.PREVIEW_ANIMATION_LOADED:
13 | return {...state, ...{animationData: action.animationData, path: action.path}}
14 | case actionTypes.PREVIEW_ANIMATION_PROGRESS:
15 | return {...state, ...{progress: action.progress}}
16 | case actionTypes.PREVIEW_TOTAL_FRAMES:
17 | return {...state, ...{totalFrames: action.totalFrames}}
18 | default:
19 | return state
20 | }
21 | }
--------------------------------------------------------------------------------
/src/redux/reducers/project.js:
--------------------------------------------------------------------------------
1 | import actionTypes from '../actions/actionTypes'
2 |
3 | let initialState = {
4 | id: '',
5 | version: '',
6 | app_version: ''
7 | }
8 |
9 | export default function project(state = initialState, action) {
10 | switch (action.type) {
11 | case actionTypes.PROJECT_SET_ID:
12 | return {...state, ...{id: action.id}}
13 | case actionTypes.VERSION_FETCHED:
14 | return {...state, ...{version: action.version}}
15 | case actionTypes.APP_VERSION_FETCHED:
16 | return {...state, ...{app_version: action.version ? action.version.substr(0, action.version.indexOf('x')) : '0.0.0'}}
17 | default:
18 | return state
19 | }
20 | }
--------------------------------------------------------------------------------
/src/redux/reducers/render.js:
--------------------------------------------------------------------------------
1 | import actionTypes from '../actions/actionTypes'
2 |
3 | let initialState = {
4 | message: '',
5 | progress: 0,
6 | finished: false,
7 | cancelled: false,
8 | fonts: []
9 | }
10 |
11 | function updateRenderData(state, action) {
12 | let newState = {...state, ...{message: action.data.message, progress: action.data.progress}}
13 | return newState
14 | }
15 |
16 | function updateFontsData(state, action) {
17 | let fontFormData = {
18 | origin: 0,
19 | fPath:'',
20 | fClass:'',
21 | fFamily:'',
22 | fWeight:'',
23 | fStyle:'',
24 | fName:''
25 | }
26 | let fonts = []
27 | let item, i, len = action.data.fonts.length
28 | for(i = 0; i < len; i += 1) {
29 | item = action.data.fonts[i]
30 | fonts.push({...fontFormData,...{fFamily: item.family, fStyle: item.style, fName: item.name}})
31 | }
32 | let newState = {...state, ...{fonts: fonts}}
33 | return newState
34 | }
35 |
36 | function updateFontOrigin(state, action) {
37 | let fonts = state.fonts
38 | let index = fonts.indexOf(action.item)
39 | let newFontData = {...fonts[index], ...{origin: action.origin}}
40 | let newFonts = [...fonts.slice(0,index),newFontData,...fonts.slice(index + 1)]
41 | let newState ={...state, ...{fonts: newFonts}}
42 | return newState
43 | }
44 |
45 | function updateInput(state, action) {
46 | let fonts = state.fonts
47 | let index = fonts.indexOf(action.item)
48 | let newFontData = {...fonts[index], ...{[action.inputName]: action.value}}
49 | let newFonts = [...fonts.slice(0,index),newFontData,...fonts.slice(index + 1)]
50 | let newState ={...state, ...{fonts: newFonts}}
51 | return newState
52 | }
53 |
54 | function updateFontFromLocalData(state, action) {
55 | let fonts = state.fonts
56 | let storedFonts = action.storedFonts
57 | if(!storedFonts){
58 | return state
59 | }
60 | let len = storedFonts.length
61 | let i
62 | let newFonts = fonts.map(function(item) {
63 | i = 0
64 | while(i state.compositions.items[id]
4 |
5 | const getCompositionsList = createSelector(
6 | [ getItem ],
7 | (item) => {
8 | return item
9 | }
10 | )
11 |
12 | export default getCompositionsList
--------------------------------------------------------------------------------
/src/redux/selectors/compositions_selector.js:
--------------------------------------------------------------------------------
1 | import { createSelector } from 'reselect'
2 |
3 | const getFilter = (state) => state.compositions.filter
4 | const getSelected = (state) => state.compositions.show_only_selected
5 | const getItems = (state) => state.compositions.items
6 | const getList = (state) => state.compositions.list
7 |
8 | function getVisibleItems(items, list, filter, showOnlySelected) {
9 | filter = filter.toLowerCase();
10 | let renderItemIds = list.filter((id, val) => {
11 | let item = items[id]
12 | //return true
13 | return item.name.toLowerCase().indexOf(filter) !== -1 || filter === ''
14 | })
15 | let renderItems = renderItemIds.map((id) => {
16 | let item = items[id]
17 | /*let copyItem = {
18 | id: item.id,
19 | name: item.name,
20 | hidden: !(item.name.indexOf(filter) !== -1 || filter === '')
21 | }*/
22 | return item
23 | }).filter((item) => (!showOnlySelected || (showOnlySelected && item.selected)))
24 | return renderItems
25 | }
26 |
27 | function checkRenderable(items, list) {
28 | let canRender = list.some((id, val) => {
29 | return items[id].selected && items[id].destination
30 | })
31 | return canRender
32 |
33 | }
34 |
35 | const getCompositionsList = createSelector(
36 | [ getFilter, getItems, getList, getSelected ],
37 | (filter, items, list, showOnlySelected) => {
38 | return {
39 | canRender: checkRenderable(items, list),
40 | filter: filter,
41 | showOnlySelected: showOnlySelected,
42 | visibleItems: getVisibleItems(items, list, filter, showOnlySelected)
43 | }
44 | }
45 | )
46 |
47 | export default getCompositionsList
--------------------------------------------------------------------------------
/src/redux/selectors/fonts_view_selector.js:
--------------------------------------------------------------------------------
1 | import { createSelector } from 'reselect'
2 |
3 | const getFonts = (state) => state.render.fonts
4 |
5 | const getFontsViewData = createSelector(
6 | [ getFonts ],
7 | (fonts) => {
8 | return {
9 | fonts: fonts
10 | }
11 | }
12 | )
13 |
14 | export default getFontsViewData
--------------------------------------------------------------------------------
/src/redux/selectors/preview_view_selector.js:
--------------------------------------------------------------------------------
1 | import { createSelector } from 'reselect'
2 |
3 | const getPreview = (state) => state.preview
4 | const getCompositions = (state) => state.compositions
5 |
6 | function getRenderer(animationData) {
7 | var i = 0, len = animationData.layers.length;
8 | while(i < len){
9 | if(animationData.layers[i].ddd) {
10 | return 'html'
11 | }
12 | i += 1;
13 |
14 | }
15 | return 'svg'
16 | }
17 |
18 | const previewViewSelector = createSelector(
19 | [ getPreview, getCompositions ],
20 | (preview, compositions) => {
21 | let totalFrames, renderer
22 | if(preview.animationData) {
23 | totalFrames = preview.animationData.op - preview.animationData.ip
24 | renderer = getRenderer(preview.animationData)
25 | } else {
26 | renderer = 'svg'
27 | totalFrames = 1
28 | }
29 |
30 | let previewableItems = compositions.list.filter(function(id){
31 | return compositions.items[id].renderStatus === 1 && compositions.items[id].settings.standalone === false
32 | }).map(function(id){
33 | return compositions.items[id]
34 | })
35 |
36 | return {
37 | preview: preview,
38 | totalFrames: totalFrames,
39 | renderer: renderer,
40 | previewableItems: previewableItems
41 | }
42 | }
43 | )
44 |
45 | export default previewViewSelector
--------------------------------------------------------------------------------
/src/redux/selectors/render_composition_selector.js:
--------------------------------------------------------------------------------
1 | import { createSelector } from 'reselect'
2 |
3 | const getItem = (state) => {
4 | if(state.render.cancelled){
5 | return null
6 | }
7 | let i = 0, len = state.compositions.list.length
8 | while(i < len) {
9 | if(state.compositions.items[state.compositions.list[i]].selected && state.compositions.items[state.compositions.list[i]].destination && state.compositions.items[state.compositions.list[i]].renderStatus === 0){
10 | return state.compositions.items[state.compositions.list[i]]
11 | }
12 | i += 1
13 | }
14 | return null
15 | }
16 |
17 | const getRenderComposition = createSelector(
18 | [ getItem ],
19 | (item) => {
20 | return item
21 | }
22 | )
23 |
24 | export default getRenderComposition
--------------------------------------------------------------------------------
/src/redux/selectors/render_font_selector.js:
--------------------------------------------------------------------------------
1 | import { createSelector } from 'reselect'
2 |
3 | const getFonts = (state) => state.render.fonts
4 |
5 | const renderFontSelector = createSelector(
6 | [ getFonts ],
7 | (fonts) => {
8 | return fonts
9 | }
10 | )
11 |
12 | export default renderFontSelector
--------------------------------------------------------------------------------
/src/redux/selectors/render_selector.js:
--------------------------------------------------------------------------------
1 | import { createSelector } from 'reselect'
2 |
3 | const getItems = (state) => state.compositions.items
4 | const getList = (state) => state.compositions.list
5 | const getRender = (state) => state.render
6 |
7 | const renderSelector = createSelector(
8 | [ getItems, getList, getRender ],
9 | (items, list, render) => {
10 | let renderingItems = list.reduce(function(a, id) {
11 | let item = items[id]
12 | if(item.selected && item.destination) {
13 | a.push(item)
14 | }
15 | return a
16 | }, [])
17 | return {
18 | renderingItems: renderingItems,
19 | render: render
20 | }
21 | }
22 | )
23 |
24 | export default renderSelector
--------------------------------------------------------------------------------
/src/redux/selectors/set_fonts_selector.js:
--------------------------------------------------------------------------------
1 | import { createSelector } from 'reselect'
2 |
3 | const getFonts = (state) => state.render.fonts
4 |
5 | const setFontSelector = createSelector(
6 | [ getFonts ],
7 | (fonts) => {
8 | return fonts
9 | }
10 | )
11 |
12 | export default setFontSelector
--------------------------------------------------------------------------------
/src/redux/selectors/settings_comp_selector.js:
--------------------------------------------------------------------------------
1 | import { createSelector } from 'reselect'
2 |
3 | const getItemId = (state) => {
4 | return state.compositions.current
5 | }
6 |
7 | const getRenderComposition = createSelector(
8 | [ getItemId ],
9 | (itemId) => {
10 | return itemId
11 | }
12 | )
13 |
14 | export default getRenderComposition
--------------------------------------------------------------------------------
/src/redux/selectors/settings_view_selector.js:
--------------------------------------------------------------------------------
1 | import { createSelector } from 'reselect'
2 | import validateVersion from '../../helpers/versionValidator'
3 |
4 | const getItems = (state) => {
5 | return state.compositions.items
6 | }
7 | const getList = (state) => {
8 | return state.compositions.list
9 | }
10 | const getCurrentComp = (state) => {
11 | return state.compositions.current
12 | }
13 | const getProjectVersion = (state) => {
14 | return state.project.app_version
15 | }
16 |
17 | function getExtraCompsList(extra, list, items) {
18 | let extraComps = list.map(function(id, index){
19 | let comp = items[id]
20 | let extraCompData = {
21 | id: id,
22 | name: comp.name,
23 | selected: extra.list.indexOf(id) !== -1
24 | }
25 | return extraCompData
26 | })
27 | return extraComps
28 | }
29 |
30 | const getRenderComposition = createSelector(
31 | [getList, getItems, getCurrentComp, getProjectVersion ],
32 | (list, items, current, projectVersion) => {
33 | let canCompressAssets = validateVersion([10,0,0], projectVersion);
34 | return {
35 | settings: items[current] ? items[current].settings : null,
36 | extraCompsList: items[current] ? getExtraCompsList(items[current].settings.extraComps, list, items) : [],
37 | canCompressAssets: canCompressAssets
38 | }
39 | }
40 | )
41 |
42 | export default getRenderComposition
--------------------------------------------------------------------------------
/src/redux/selectors/storing_data_selector.js:
--------------------------------------------------------------------------------
1 | import { createSelector } from 'reselect'
2 |
3 | const getCompositions = (state) => state.compositions.items
4 | const getID = (state) => state.project.id
5 |
6 | const storingDataSelector = createSelector(
7 | [ getCompositions, getID ],
8 | (compositions, id) => {
9 | return {
10 | data: {
11 | compositions: compositions
12 | },
13 | id: id
14 | }
15 | }
16 | )
17 |
18 | export default storingDataSelector
--------------------------------------------------------------------------------
/src/redux/selectors/storing_paths_selector.js:
--------------------------------------------------------------------------------
1 | import { createSelector } from 'reselect'
2 |
3 | const getPaths = (state) => state.paths
4 |
5 | const storingPathsSelector = createSelector(
6 | [ getPaths ],
7 | (paths) => {
8 | return paths
9 | }
10 | )
11 |
12 | export default storingPathsSelector
--------------------------------------------------------------------------------
/src/reset.css:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 |
6 | html, body, div, span, applet, object, iframe,
7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8 | a, abbr, acronym, address, big, cite, code,
9 | del, dfn, em, img, ins, kbd, q, s, samp,
10 | small, strike, strong, sub, sup, tt, var,
11 | b, u, i, center,
12 | dl, dt, dd, ol, ul, li,
13 | fieldset, form, label, legend,
14 | table, caption, tbody, tfoot, thead, tr, th, td,
15 | article, aside, canvas, details, embed,
16 | figure, figcaption, footer, header, hgroup,
17 | menu, nav, output, ruby, section, summary,
18 | time, mark, audio, video {
19 | margin: 0;
20 | padding: 0;
21 | border: 0;
22 | font-size: 100%;
23 | font: inherit;
24 | vertical-align: baseline;
25 | }
26 | /* HTML5 display-role reset for older browsers */
27 | article, aside, details, figcaption, figure,
28 | footer, header, hgroup, menu, nav, section {
29 | display: block;
30 | }
31 | body {
32 | line-height: 1;
33 | }
34 | ol, ul {
35 | list-style: none;
36 | }
37 | blockquote, q {
38 | quotes: none;
39 | }
40 | blockquote:before, blockquote:after,
41 | q:before, q:after {
42 | content: '';
43 | content: none;
44 | }
45 | table {
46 | border-collapse: collapse;
47 | border-spacing: 0;
48 | }
--------------------------------------------------------------------------------
/src/views/ViewsContainer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {connect} from 'react-redux'
3 |
4 | import Render from './render/Render'
5 | import Compositions from './compositions/Compositions'
6 | import SettingsView from './settings/Settings'
7 | import PreviewView from './preview/Preview'
8 | import FontsView from './fonts/Fonts'
9 | import PlayerView from './player/Player'
10 |
11 | function getView(route) {
12 | switch(route) {
13 | case 0:
14 | return
15 | case 1:
16 | return
17 | case 2:
18 | return
19 | case 3:
20 | return
21 | case 4:
22 | return
23 | case 5:
24 | return
25 | default:
26 | return
27 | }
28 | }
29 |
30 | let ViewsContainer = (props) => {getView(props.route)}
31 |
32 | function mapStateToProps(state) {
33 | return state.routes
34 | }
35 |
36 | export default connect(mapStateToProps,null)(ViewsContainer)
--------------------------------------------------------------------------------
/src/views/compositions/Compositions.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {connect} from 'react-redux'
3 | import { StyleSheet, css } from 'aphrodite'
4 | import CompositionsList from './list/CompositionsList'
5 | import CompositionsListHeader from './listHeader/CompositionsListHeader'
6 | import MainHeader from '../../components/header/Main_header'
7 | import {getDestination, filterChange, toggleItem, displaySettings, getCompositions, goToPreview, goToPlayer, toggleShowSelected} from '../../redux/actions/compositionActions'
8 | import {startRender, showRenderBlock} from '../../redux/actions/renderActions'
9 | import compositions_selector from '../../redux/selectors/compositions_selector'
10 | import Variables from '../../helpers/styles/variables'
11 |
12 | const styles = StyleSheet.create({
13 | wrapper: {
14 | width: '100%',
15 | height: '100%',
16 | padding: '10px',
17 | backgroundColor: '#474747'
18 | },
19 | toggleButton: {
20 | fontSize: '12px',
21 | color: '#eee',
22 | textDecoration:'underline',
23 | cursor: 'pointer',
24 | paddingTop: '6px',
25 | ':hover': {
26 | color: Variables.colors.green,
27 | }
28 | }
29 | })
30 |
31 | class Compositions extends React.Component {
32 |
33 | constructor() {
34 | super()
35 | this.selectDestination = this.selectDestination.bind(this)
36 | this.showSettings = this.showSettings.bind(this)
37 | this.renderComps = this.renderComps.bind(this)
38 | //this.goToPreview = this.goToPreview.bind(this)
39 | }
40 |
41 | selectDestination(comp) {
42 | this.props.getDestination(comp)
43 | }
44 |
45 | showSettings(item) {
46 | this.props.displaySettings(item.id)
47 | }
48 |
49 |
50 |
51 | renderComps() {
52 | if(!this.props.canRender){
53 | this.props.showRenderBlock(['There are no Compositions to render.','Make sure you have at least one selected and a Destination Path set.'])
54 | } else {
55 | this.props.startRender()
56 | //browserHistory.push('/render')
57 | }
58 |
59 | }
60 | /*goToPreview() {
61 | //browserHistory.push('/preview')
62 | }*/
63 |
64 | /*goToPlayer() {
65 | browserHistory.push('/player')
66 | }*/
67 |
68 | render() {
69 |
70 | return (
71 |
72 |
78 |
81 |
86 |
87 | )
88 | }
89 | }
90 |
91 | function mapStateToProps(state) {
92 | return compositions_selector(state)
93 | }
94 |
95 | const mapDispatchToProps = {
96 | getDestination: getDestination,
97 | toggleItem: toggleItem,
98 | displaySettings: displaySettings,
99 | getCompositions: getCompositions,
100 | filterChange: filterChange,
101 | startRender: startRender,
102 | goToPreview: goToPreview,
103 | goToPlayer: goToPlayer,
104 | showRenderBlock: showRenderBlock,
105 | toggleShowSelected: toggleShowSelected
106 | }
107 |
108 | export default connect(mapStateToProps, mapDispatchToProps)(Compositions)
109 |
--------------------------------------------------------------------------------
/src/views/compositions/list/CompositionsList.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, css } from 'aphrodite'
3 | import CompositionsListItem from './CompositionsListItem'
4 |
5 | const styles = StyleSheet.create({
6 | list: {
7 | height: 'calc( 100% - 180px)',
8 | overflow: 'auto'
9 | }
10 | })
11 |
12 | class CompositionsList extends React.PureComponent {
13 |
14 | createItem(item) {
15 | return
21 | }
22 |
23 | render() {
24 |
25 | let items = this.props.items.map((item) => {
26 | return this.createItem(item)
27 | })
28 |
29 | return (
30 |
33 | );
34 | }
35 | }
36 |
37 | export default CompositionsList
--------------------------------------------------------------------------------
/src/views/compositions/list/CompositionsListItem.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, css } from 'aphrodite'
3 | import BodymovinCheckbox from '../../../components/bodymovin/bodymovin_checkbox'
4 | import BodymovinDots from '../../../components/bodymovin/bodymovin_dots'
5 | import checkbox from '../../../assets/animations/checkbox.json'
6 | import Variables from '../../../helpers/styles/variables'
7 | import textEllipsis from '../../../helpers/styles/textEllipsis'
8 |
9 | const styles = StyleSheet.create({
10 | composition: {
11 | width: '100%',
12 | fontSize: '12px',
13 | color: '#ffffff',
14 | backgroundColor: Variables.colors.gray_darkest,
15 | height: '30px',
16 | marginBottom: '2px'
17 | },
18 | composition__selected: {
19 | background: Variables.gradients.blueGreen
20 | },
21 | item: {
22 | display: 'inline-block',
23 | verticalAlign: 'middle',
24 | backgroundColor:'transparent'
25 | },
26 | itemContainer: {
27 | padding: '4px 0',
28 | width: '100%',
29 | height: '100%'
30 | },
31 | radio: {
32 | height: '100%',
33 | width: '70px',
34 | padding:'2px',
35 | cursor: 'pointer'
36 | },
37 | settings: {
38 | height: '100%',
39 | width: '80px',
40 | cursor: 'pointer'
41 | },
42 | name: {
43 | width: 'calc( 60% - 75px)',
44 | lineHeight: '22px',
45 | padding: '0 10px'
46 | },
47 | destination: {
48 | width: 'calc( 40% - 75px)',
49 | padding: '0 10px',
50 | color: Variables.colors.green
51 | },
52 | destinationPlaceholder: {
53 | width: 'calc( 40% - 75px)',
54 | padding: '0 0 0 10px',
55 | height: '100%'
56 | },
57 | hidden: {
58 | display: 'none'
59 | },
60 | 'destination_placeholder--dot': {
61 | width: '4px',
62 | height: '4px',
63 | borderRadius: '50%',
64 | backgroundColor: Variables.colors.green,
65 | display: 'inline-block',
66 | marginRight: '2px'
67 | }
68 | })
69 |
70 | class CompositionsListItem extends React.Component {
71 |
72 | constructor() {
73 | super()
74 | this.showSettings = this.showSettings.bind(this)
75 | this.toggleItem = this.toggleItem.bind(this)
76 | this.selectDestination = this.selectDestination.bind(this)
77 | this.settingsHovered = this.settingsHovered.bind(this)
78 | this.settingsLeft = this.settingsLeft.bind(this)
79 | this.state = {
80 | settingsHovered: false
81 | }
82 | }
83 |
84 | shouldComponentUpdate(nextProps, nextState) {
85 | return this.props.item !== nextProps.item || this.state !== nextState
86 | }
87 |
88 | showSettings() {
89 | this.props.showSettings(this.props.item)
90 | }
91 |
92 | toggleItem() {
93 | this.props.toggleItem(this.props.item)
94 | }
95 |
96 | selectDestination() {
97 | this.props.selectDestination(this.props.item)
98 | }
99 |
100 | settingsHovered() {
101 | this.setState({settingsHovered:true})
102 | }
103 |
104 | settingsLeft() {
105 | this.setState({settingsHovered:false})
106 | }
107 |
108 | render(){
109 | return (
111 |
112 |
113 |
114 |
115 |
{this.props.item.name}
116 | {this.props.item.destination
117 | &&
{this.props.item.destination}
}
118 | {!this.props.item.destination &&
119 |
120 |
}
121 |
122 | )
123 | }
124 | }
125 |
126 | export default CompositionsListItem
--------------------------------------------------------------------------------
/src/views/compositions/listHeader/CompositionsListHeader.css:
--------------------------------------------------------------------------------
1 | .testClase{
2 | width: 150px;
3 | background-color: red;
4 | }
--------------------------------------------------------------------------------
/src/views/compositions/listHeader/CompositionsListHeader.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { StyleSheet, css } from 'aphrodite';
3 | import glass from '../../../assets/svg/glass.svg'
4 | import Variables from '../../../helpers/styles/variables'
5 | import textEllipsis from '../../../helpers/styles/textEllipsis'
6 |
7 | const styles = StyleSheet.create({
8 | container: {
9 | width: '100%',
10 | fontSize: '12px',
11 | color: '#eee',
12 | marginBottom: '10px'
13 | },
14 | item: {
15 | display: 'inline-block',
16 | verticalAlign: 'middle',
17 | textAlign: 'center',
18 | padding: '0px 10px',
19 | },
20 | radio: {
21 | width: '70px'
22 | },
23 | settings: {
24 | width: '80px'
25 | },
26 | name: {
27 | width: 'calc( 60% - 75px)',
28 | height: '24px'
29 |
30 | },
31 | nameBox: {
32 | border: '2px solid ' + Variables.colors.gray2,
33 | backgroundColor: '#333',
34 | borderRadius: '6px',
35 | width: '100%',
36 | height: '100%'
37 | },
38 | name_input: {
39 | display: 'inline-block',
40 | verticalAlign: 'top',
41 | height: '100%',
42 | width: 'calc( 100% - 30px)',
43 | background: 'none',
44 | color: '#eee',
45 | padding: '0px 3px',
46 | border: 'none',
47 | ':focus': {
48 | border: 'none',
49 | outline: 'none'
50 | }
51 | },
52 | name_glass: {
53 | display: 'inline-block',
54 | verticalAlign: 'top',
55 | width: '30px',
56 | height: '100%',
57 | backgroundImage: 'url("'+glass+'")',
58 | backgroundRepeat: 'no-repeat',
59 | backgroundPosition: 'center',
60 | backgroundSize: '17px 17px'
61 | },
62 | name_glass_image: {
63 | maxHeight: '50%',
64 | maxWidth: '50%'
65 | },
66 | destination: {
67 | width: 'calc( 40% - 75px)',
68 | textAlign: 'left'
69 | }
70 | });
71 |
72 | class CompositionsListHeader extends React.Component {
73 | render() {
74 | return (
75 |
76 | - Selected
77 | -
78 |
83 |
84 | - Destination Folder
85 |
86 | );
87 | }
88 | }
89 |
90 | export default CompositionsListHeader
--------------------------------------------------------------------------------
/src/views/fonts/Fonts.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {connect} from 'react-redux'
3 | import { StyleSheet, css } from 'aphrodite'
4 | import fonts_view_selector from '../../redux/selectors/fonts_view_selector'
5 | import BaseButton from '../../components/buttons/Base_button'
6 | import FontForm from './form/FontForm'
7 | import {updateFontOrigin, updateInput, setFonts, stopRender} from '../../redux/actions/renderActions'
8 | import Bodymovin from '../../components/bodymovin/bodymovin'
9 | import fontsAnim from '../../assets/animations/fonts.json'
10 | import Variables from '../../helpers/styles/variables'
11 |
12 | const styles = StyleSheet.create({
13 | wrapper: {
14 | width: '100%',
15 | height: '100%',
16 | padding: '10px',
17 | backgroundColor: '#474747'
18 | },
19 | container: {
20 | width: '100%',
21 | height: '100%',
22 | display: 'flex',
23 | flexDirection:'column'
24 | },
25 | header: {
26 | width: '100%',
27 | height: '60px',
28 | fontFamily: 'Roboto-Bold',
29 | fontSize: '12px',
30 | marginBottom: '20px',
31 | flexGrow: 0,
32 | flexShrink: 0,
33 | borderBottom: '1px solid ' + Variables.colors.gray2
34 | },
35 | headerTitle:{
36 | display: 'inline-block',
37 | verticalAlign: 'middle',
38 | color: Variables.colors.white
39 | },
40 | header_animation_container: {
41 | height: '100%',
42 | width: '50px',
43 | display: 'inline-block',
44 | verticalAlign: 'middle'
45 | },
46 | list: {
47 | width: '100%',
48 | flexGrow: 1,
49 | flexShrink: 1,
50 | position: 'relative',
51 | backgroundColor: Variables.colors.gray_darkest,
52 | padding: '4px',
53 | overflowY: 'hidden',
54 | overflowX: 'hidden',
55 | marginBottom: '20px'
56 | },
57 | list_items: {
58 | position: 'absolute',
59 | top: '0',
60 | left: '0',
61 | overflowY: 'auto',
62 | width: '100%',
63 | height:'100%'
64 | },
65 | buttons: {
66 | width: '100%',
67 | flexGrow: 0,
68 | flexShrink: 0,
69 | textAlign: 'center'
70 | },
71 | button_separator: {
72 | width: '10px',
73 | display: 'inline-block'
74 | }
75 | })
76 |
77 | class Fonts extends React.Component {
78 |
79 | constructor(){
80 | super()
81 | this.cancelRender = this.cancelRender.bind(this)
82 | this.setFonts = this.setFonts.bind(this)
83 | }
84 |
85 | cancelRender() {
86 | this.props.stopRender()
87 | //browserHistory.push('/')
88 | }
89 |
90 | getFontsList() {
91 | return this.props.fonts.map((item) => {
92 | return
97 | })
98 | }
99 |
100 | setFonts() {
101 | this.props.setFonts()
102 | //browserHistory.push('/render')
103 | }
104 |
105 | render() {
106 | return (
107 |
108 |
109 |
110 |
111 |
112 |
113 |
Select font families and font paths when necessary
114 |
115 |
116 |
117 | {this.getFontsList()}
118 |
119 |
120 |
125 |
126 |
127 | );
128 | }
129 | }
130 |
131 | function mapStateToProps(state) {
132 | return fonts_view_selector(state)
133 | }
134 |
135 | const mapDispatchToProps = {
136 | updateFontOrigin: updateFontOrigin,
137 | updateInput: updateInput,
138 | setFonts: setFonts,
139 | stopRender: stopRender
140 | }
141 |
142 | export default connect(mapStateToProps, mapDispatchToProps)(Fonts)
143 |
--------------------------------------------------------------------------------
/src/views/fonts/form/FontForm.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, css } from 'aphrodite'
3 | import BodymovinCheckbox from '../../../components/bodymovin/bodymovin_checkbox'
4 | import anim from '../../../assets/animations/checkbox.json'
5 | import Variables from '../../../helpers/styles/variables'
6 |
7 | const styles = StyleSheet.create({
8 | wrapper:{
9 | marginTop: '5px',
10 | marginBottom: '15px',
11 | borderBottom: '2px solid ' + Variables.colors.gray_lighter
12 | },
13 | originSelect: {
14 | display:'inline-block',
15 | verticalAlign:'middle',
16 | paddingBottom: '10px',
17 | marginRight: '15px'
18 |
19 | },
20 | 'originSelect--radio': {
21 | width: '20px',
22 | padding:'2px',
23 | background:'none',
24 | display:'inline-block',
25 | verticalAlign:'middle',
26 | ':focus':{
27 | border:'none',
28 | outline:'none'
29 | }
30 | },
31 | 'originSelect--label': {
32 | display:'inline-block',
33 | verticalAlign:'middle',
34 | color:'white',
35 | fontSize: '10px'
36 | },
37 | inputLabel:{
38 | color:'white',
39 | fontSize: '10px'
40 | },
41 | inputBox:{
42 | color:'white',
43 | width:'100%',
44 | border: '1px solid ' + Variables.colors.white,
45 | backgroundColor: Variables.colors.gray_darkest,
46 | borderRadius: '6px',
47 | lineHeight:'20px',
48 | padding: '2px',
49 | ':focus':{
50 | outline:'none'
51 | }
52 | },
53 | inputBlock:{
54 | padding: '0 4px 10px 4px'
55 | },
56 | halfBlock:{
57 | width:'50%',
58 | display: 'inline-block'
59 | },
60 | fontNameTitle: {
61 | color: Variables.colors.white,
62 | fontFamily: 'Roboto-Bold',
63 | fontSize: '12px',
64 | padding: '0 4px 10px 4px'
65 | }
66 | })
67 |
68 | let FontForm = function(props) {
69 | return (
70 |
71 |
72 |
{props.data.fName}
73 |
74 | - props.changeOrigin(0, props.data)}>
75 |
76 |
77 |
78 |
None
79 |
80 | - props.changeOrigin(1, props.data)}>
81 |
82 |
83 |
84 |
Google Font
85 |
86 | - props.changeOrigin(2, props.data)}>
87 |
88 |
89 |
90 |
Typekit
91 |
92 | - props.changeOrigin(3, props.data)}>
93 |
94 |
95 |
96 |
URL
97 |
98 |
99 |
100 |
CSS Class
101 |
props.updateInput(ev.target.value, 'fClass', props.data)}
105 | value={props.data.fClass}/>
106 |
107 |
108 |
Font Path
109 |
props.updateInput(ev.target.value, 'fPath', props.data)}
113 | value={props.data.fPath}/>
114 |
115 |
116 |
Font Family
117 |
props.updateInput(ev.target.value, 'fFamily', props.data)}
121 | value={props.data.fFamily}/>
122 |
123 |
124 |
Font Weight
125 |
props.updateInput(ev.target.value, 'fWeight', props.data)}
129 | value={props.data.fWeight}/>
130 |
131 |
132 |
Font Style
133 |
props.updateInput(ev.target.value, 'fStyle', props.data)}
137 | value={props.data.fStyle}/>
138 |
139 |
140 |
141 | )
142 | }
143 |
144 | export default FontForm
--------------------------------------------------------------------------------
/src/views/player/Player.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {connect} from 'react-redux'
3 | import { StyleSheet, css } from 'aphrodite'
4 | import BaseButton from '../../components/buttons/Base_button'
5 | import Bodymovin from '../../components/bodymovin/bodymovin'
6 | import anim from '../../assets/animations/bm.json'
7 | import {openInBrowser, getPlayer} from '../../helpers/CompositionsProvider'
8 | import Variables from '../../helpers/styles/variables'
9 | import {goToComps} from '../../redux/actions/compositionActions'
10 |
11 | const styles = StyleSheet.create({
12 | container: {
13 | width: '100%',
14 | height: '100%',
15 | display: 'flex',
16 | flexDirection:'column',
17 | padding: '10px 30px',
18 | backgroundColor :'#474747'
19 | },
20 | back_container: {
21 | textAlign: 'right'
22 | },
23 | anim_container: {
24 | textAlign: 'center'
25 | },
26 | bm_container: {
27 | width: '80px',
28 | height: '80px',
29 | display: 'inline-block'
30 | },
31 | text_container: {
32 | paddingBottom: '15px',
33 | textAlign: 'center'
34 | },
35 | text_title: {
36 | color: Variables.colors.white,
37 | fontFamily: 'Roboto-Black',
38 | paddingBottom: '25px',
39 | fontSize: '14px'
40 | },
41 | text_par: {
42 | color: '#fff',
43 | fontSize: '10px',
44 | lineHeight:'14px'
45 | },
46 | link: {
47 | color: Variables.colors.green
48 | },
49 | buttons_container: {
50 | textAlign: 'center'
51 | },
52 | buttonSeparator: {
53 | width: '10px',
54 | display: 'inline-block'
55 | }
56 | })
57 |
58 | class Player extends React.Component {
59 |
60 | openInBrowser(){
61 | openInBrowser('https://github.com/airbnb/lottie-web')
62 | }
63 |
64 | getPlayer(){
65 | getPlayer(false)
66 | }
67 |
68 | getPlayerZipped(){
69 | getPlayer(true)
70 | }
71 |
72 | render() {
73 | return (
74 |
75 |
76 |
77 |
78 |
83 |
84 |
Bodymovin for Telegram Stickers
85 |
86 |
This plugin exports After Effects animations to a web compatible format.
87 |
In order to play the exported animation on your browser follow the instructions at
88 | Lottie on github
89 |
90 |
91 |
You can get the latest version of the player from the repository or copy the one included in the extension here.
92 |
93 |
94 |
99 |
100 | );
101 | }
102 | }
103 | const mapDispatchToProps = {
104 | goToComps: goToComps
105 | }
106 |
107 | export default connect(null, mapDispatchToProps)(Player)
108 |
--------------------------------------------------------------------------------
/src/views/preview/Preview.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {connect} from 'react-redux'
3 | import { StyleSheet, css } from 'aphrodite'
4 | import PreviewViewer from './viewer/PreviewViewer'
5 | import PreviewScrubber from './scrubber/PreviewScrubber'
6 | import PreviewHeader from './header/PreviewHeader'
7 | import CurrentRenders from './current_renders/CurrentRenders'
8 | import {browsePreviewFile, updateProgress, setTotalFrames, showNoCurrentRenders, previewFromPath} from '../../redux/actions/previewActions'
9 | import {goToComps} from '../../redux/actions/compositionActions'
10 | import preview_view_selector from '../../redux/selectors/preview_view_selector'
11 | import FileSaver from '../../helpers/FileSaver'
12 |
13 | const styles = StyleSheet.create({
14 | wrapper: {
15 | width: '100%',
16 | height: '100%',
17 | padding: '10px',
18 | backgroundColor:'#474747'
19 | },
20 | container: {
21 | width: '100%',
22 | height: '100%',
23 | display: 'flex',
24 | flexDirection:'column'
25 | },
26 | header: {
27 | width: '100%',
28 | flexGrow: 0,
29 | flexShrink: 0
30 | },
31 | animation: {
32 | width: '100%',
33 | flexGrow: 1,
34 | flexShrink: 1,
35 | position: 'relative'
36 | },
37 | scrubber: {
38 | width: '100%',
39 | flexGrow: 0,
40 | flexShrink: 0
41 | }
42 | })
43 |
44 | class Preview extends React.Component {
45 |
46 | constructor() {
47 | super()
48 | this.updateProgress = this.updateProgress.bind(this)
49 | this.saveFile = this.saveFile.bind(this)
50 | this.itemSelected = this.itemSelected.bind(this)
51 | this.selectCurrentRenders = this.selectCurrentRenders.bind(this)
52 | this.closeSelection = this.closeSelection.bind(this)
53 | this.state = {
54 | showingCurrentRenders: false
55 | }
56 | }
57 |
58 | changeStart() {
59 | //console.log('changeStart')
60 | }
61 |
62 | updateProgress(value) {
63 | this.props.updateProgress(value)
64 | }
65 |
66 | saveFile(fileData) {
67 |
68 | var svgData = this.previewViewer.snapshot()
69 | FileSaver(svgData, ['svg'], 'snapshot.svg')
70 | }
71 |
72 | itemSelected(item) {
73 | this.props.previewFromPath(item.destination)
74 | this.closeSelection()
75 | }
76 |
77 | closeSelection() {
78 | this.setState({
79 | showingCurrentRenders: false
80 | })
81 | }
82 |
83 | selectCurrentRenders() {
84 | if(!this.props.previewableItems.length){
85 | this.props.showNoCurrentRenders()
86 | } else {
87 | this.setState({
88 | showingCurrentRenders: true
89 | })
90 | }
91 | }
92 |
93 | render() {
94 | return (
95 |
96 |
97 |
103 |
104 |
this.previewViewer = elem)} />
111 |
112 |
120 |
121 | {this.state.showingCurrentRenders &&
}
125 |
126 | );
127 | }
128 | }
129 |
130 | function mapStateToProps(state) {
131 | return preview_view_selector(state)
132 | }
133 |
134 | const mapDispatchToProps = {
135 | browsePreviewFile: browsePreviewFile,
136 | previewFromPath: previewFromPath,
137 | updateProgress: updateProgress,
138 | setTotalFrames: setTotalFrames,
139 | goToComps: goToComps,
140 | showNoCurrentRenders: showNoCurrentRenders
141 | }
142 |
143 | export default connect(mapStateToProps, mapDispatchToProps)(Preview)
144 |
--------------------------------------------------------------------------------
/src/views/preview/current_renders/CurrentRenders.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, css } from 'aphrodite'
3 | import BaseButton from '../../../components/buttons/Base_button'
4 | import Variables from '../../../helpers/styles/variables'
5 | import textEllipsis from '../../../helpers/styles/textEllipsis'
6 |
7 | const styles = StyleSheet.create({
8 | container: {
9 | width: '100%',
10 | height: '100%',
11 | backgroundColor:'rgba(100,100,100,.8)',
12 | position: 'absolute',
13 | top: '0',
14 | left: '0',
15 | display: 'flex',
16 | flexDirection:'column',
17 | padding: '20px'
18 | },
19 | list:{
20 | flexGrow: 1,
21 | backgroundColor: Variables.colors.gray_darkest,
22 | width: '100%',
23 | overflowX: 'hidden',
24 | overflowY: 'auto'
25 | },
26 | nav:{
27 | flexGrow: 0,
28 | textAlign: 'right',
29 | marginBottom: '10px'
30 | },
31 | list_item:{
32 | width: '100%',
33 | height: '30px',
34 | fontSize: '12px',
35 | lineHeight: '26px',
36 | padding: '2px',
37 | color: Variables.colors.white,
38 | backgroundColor: Variables.colors.gray,
39 | borderBottom: '2px solid ' + Variables.colors.gray2,
40 | cursor: 'pointer',
41 | overflow: 'hidden',
42 | ':hover' : {
43 | color: Variables.colors.green,
44 | }
45 | }
46 | })
47 |
48 | function getItems(items, itemSelected) {
49 | return items.map(function(item, index){
50 | return itemSelected(item)} className={css(styles.list_item, textEllipsis)}>{item.name}
51 | })
52 | }
53 |
54 | let CurrentRenders = (props) => {
55 | return (
56 |
57 |
58 |
59 |
60 | {getItems(props.items, props.itemSelected)}
61 |
62 |
)
63 | }
64 |
65 | export default CurrentRenders
--------------------------------------------------------------------------------
/src/views/preview/header/PreviewHeader.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, css } from 'aphrodite'
3 | import Variables from '../../../helpers/styles/variables'
4 | import BaseButton from '../../../components/buttons/Base_button'
5 |
6 | const styles = StyleSheet.create({
7 | container: {
8 | width: '100%',
9 | marginBottom: '10px'
10 | },
11 | right: {
12 | float: 'right'
13 | },
14 | buttons_container: {
15 | width: '100%',
16 | height: '50px',
17 | display: 'flex',
18 | alignItems:'center'
19 | },
20 | button: {
21 | marginRight:'5px',
22 | flexGrow: 0
23 | },
24 | buttons_separator: {
25 | flexGrow: 1
26 | },
27 | refresh: {
28 | width: '40px',
29 | height: '34px',
30 | backgroundColor: 'transparent',
31 | verticalAlign:'middle'
32 | },
33 | refresh_image: {
34 | maxWidth: '100%',
35 | maxHeight: '100%'
36 | },
37 | separator: {
38 | width: '100%',
39 | height: '1px',
40 | backgroundColor: Variables.colors.gray2,
41 | marginTop: '20px',
42 | marginBottom: '20px'
43 | }
44 | })
45 |
46 | function PreviewHeader(props) {
47 | return ()
56 | }
57 |
58 | export default PreviewHeader
--------------------------------------------------------------------------------
/src/views/preview/scrubber/PreviewScrubber.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, css } from 'aphrodite'
3 | import Range from '../../../components/range/Range'
4 | import BaseButton from '../../../components/buttons/Base_button'
5 | import Variables from '../../../helpers/styles/variables'
6 | import snapshot from '../../../assets/animations/snapshot.json'
7 |
8 | const styles = StyleSheet.create({
9 | container: {
10 | width: '100%',
11 | height: '80px'
12 | },
13 | navContainer: {
14 | width: '100%',
15 | height: '36px',
16 | display: 'flex'
17 | },
18 | progressNumberContainer: {
19 | fontSize: '20px',
20 | lineHeight: '28px',
21 | color: Variables.colors.blue,
22 | flexGrow: 0,
23 | cursor: 'pointer'
24 | },
25 | progressNumber: {
26 | fontSize: '20px',
27 | lineHeight: '28px',
28 | color: Variables.colors.blue,
29 | display: 'inline-block'
30 | },
31 | inputNumber: {
32 | backgroundColor: Variables.colors.gray,
33 | border: '2px solid ' + Variables.colors.gray2,
34 | width: 'auto',
35 | ':focus' :{
36 | outline: 'none'
37 | }
38 | },
39 | emptySpace: {
40 | flexGrow: 1,
41 | backgroundColor: 'transparent'
42 | },
43 | button: {
44 | flexGrow: 0
45 | }
46 | })
47 |
48 | class PreviewScrubber extends React.Component {
49 |
50 | constructor() {
51 | super()
52 | this.state = {
53 | numberFocused: false,
54 | inputValue:0
55 | }
56 | this.focusNumber = this.focusNumber.bind(this)
57 | this.updateValue = this.updateValue.bind(this)
58 | this.setInitialValue = this.setInitialValue.bind(this)
59 | this.handleBlur = this.handleBlur.bind(this)
60 | this.handleKey = this.handleKey.bind(this)
61 | }
62 |
63 | focusNumber(){
64 | if(this.props.totalFrames === 0){
65 | //return
66 | }
67 | this.setState({
68 | numberFocused: true
69 | })
70 | }
71 |
72 | updateValue(ev) {
73 | if(ev.target.value === ''){
74 | this.setState({
75 | inputValue: ''
76 | })
77 | return
78 | }
79 | let newValue = parseInt(ev.target.value, 10)
80 | if(isNaN(newValue) || newValue < 0 || newValue > this.props.totalFrames){
81 | return
82 | }
83 | this.setState({
84 | inputValue: newValue
85 | })
86 | this.props.updateProgress(newValue/this.props.totalFrames)
87 | }
88 |
89 | setInitialValue() {
90 | this.setState({
91 | inputValue: Math.round(this.props.totalFrames * this.props.progress)
92 | })
93 | }
94 |
95 | handleBlur() {
96 | this.setState({
97 | numberFocused: false
98 | })
99 | }
100 |
101 | handleKey(ev){
102 | if(ev.keyCode === 40 && this.state.inputValue > 0){
103 | let newValue = this.state.inputValue - 1
104 | this.setState({
105 | inputValue: newValue
106 | })
107 | this.props.updateProgress(newValue/this.props.totalFrames)
108 | ev.preventDefault()
109 | }else if(ev.keyCode === 38 && this.state.inputValue < this.props.totalFrames){
110 | let newValue = this.state.inputValue + 1
111 | this.setState({
112 | inputValue: newValue
113 | })
114 | this.props.updateProgress(newValue/this.props.totalFrames)
115 | ev.preventDefault()
116 | }
117 | }
118 |
119 | render() {
120 |
121 | let inputLength = this.props.totalFrames.toString().length
122 |
123 | return (
124 |
125 |
126 |
127 |
128 | {!this.state.numberFocused
129 | &&
{Math.round(this.props.totalFrames * this.props.progress)}
}
130 | {this.state.numberFocused
131 | &&
}
141 |
/ {this.props.totalFrames}
142 |
143 |
144 |
145 |
146 |
147 | );
148 | }
149 | }
150 |
151 | PreviewScrubber.defaultProps = {
152 | totalFrames: 0,
153 | progress: 0,
154 | max: 1
155 | }
156 |
157 | export default PreviewScrubber
158 |
--------------------------------------------------------------------------------
/src/views/preview/viewer/PreviewViewer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, css } from 'aphrodite'
3 | import Bodymovin from '../../../components/bodymovin/bodymovin'
4 |
5 | const styles = StyleSheet.create({
6 | container: {
7 | width: '100%',
8 | height: '100%',
9 | borderRadius:'2px',
10 | position: 'absolute',
11 | backgroundColor:'#333'
12 | }
13 | })
14 |
15 | class PreviewViewer extends React.Component {
16 |
17 | constructor() {
18 | super()
19 |
20 | this.animationLoaded = this.animationLoaded.bind(this)
21 | }
22 |
23 | componentWillReceiveProps(props) {
24 | if(props.progress !== this.props.progress && this.bm_instance.animation) {
25 | try{
26 | this.bm_instance.goToAndStop(parseInt(this.bm_instance.animation.totalFrames * props.progress, 10), true)
27 | } catch(err) {
28 | console.log('errr: ', err)
29 | }
30 | }
31 | if(this.props.animationData !== props.animationData){
32 | this.selectRenderer()
33 | }
34 | }
35 |
36 | animationLoaded() {
37 | this.props.setTotalFrames(this.bm_instance.animation.totalFrames)
38 | }
39 |
40 | snapshot() {
41 | return this.bm_instance.element.innerHTML
42 | }
43 |
44 | selectRenderer() {
45 |
46 | }
47 |
48 | render() {
49 | return (
50 | this.bm_instance = elem} renderer={this.props.renderer} path={this.props.path} autoplay={false} animationLoaded={this.animationLoaded} >
51 |
52 |
53 | );
54 | }
55 | }
56 |
57 | export default PreviewViewer
58 |
--------------------------------------------------------------------------------
/src/views/render/Render.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {connect} from 'react-redux'
3 | import { StyleSheet, css } from 'aphrodite'
4 | import {stopRender} from '../../redux/actions/renderActions'
5 | import {goToComps} from '../../redux/actions/compositionActions'
6 | import render_selector from '../../redux/selectors/render_selector'
7 | import RenderItem from './list/RenderItem'
8 | import BaseButton from '../../components/buttons/Base_button'
9 | import Variables from '../../helpers/styles/variables'
10 | import {goToFolder} from '../../helpers/CompositionsProvider'
11 | import Bodymovin from '../../components/bodymovin/bodymovin'
12 | import fluido from '../../assets/animations/fluido.json'
13 |
14 | const styles = StyleSheet.create({
15 | wrapper: {
16 | width: '100%',
17 | height: '100%',
18 | padding: '10px',
19 | backgroundColor: '#474747'
20 | },
21 | container: {
22 | width: '100%',
23 | height: '100%',
24 | fontSize: '12px',
25 | color: Variables.colors.white,
26 | display: 'flex',
27 | flexDirection: 'column'
28 | },
29 | header: {
30 | width: '100%',
31 | color: Variables.colors.white,
32 | flexGrow: 0,
33 | marginBottom: '10px',
34 | height: '40px'
35 | },
36 | message: {
37 | overflow: 'hidden',
38 | textOverflow: 'ellipsis',
39 | whiteSpace: 'nowrap',
40 | color: Variables.colors.white,
41 | display: 'inline-block',
42 | fontSize: '12px',
43 | fontFamily: 'Roboto-Bold',
44 | verticalAlign: 'middle'
45 | },
46 | headerAnim: {
47 | width: '50px',
48 | height: '100%',
49 | display: 'inline-block',
50 | verticalAlign: 'middle'
51 | },
52 | renderBar: {
53 | borderRadius:'4px',
54 | height:'8px',
55 | width: '100%',
56 | overflow: 'hidden',
57 | position:'relative',
58 | flexGrow: 0,
59 | marginBottom: '20px'
60 | },
61 | renderBarBackground: {
62 | borderRadius:'4px',
63 | height:'100%',
64 | width: '100%',
65 | backgroundColor: '#303030'
66 | },
67 | renderBarProgress: {
68 | borderRadius:'4px',
69 | height:'100%',
70 | width: '100%',
71 | position: 'absolute',
72 | top:0,
73 | left:0,
74 | background: 'linear-gradient(left, rgb(0,142,211) 15%,rgb(0,182,72) 85%)'
75 | },
76 | compsListContainer: {
77 | width: '100%',
78 | background: 'black',
79 | flexGrow: 1,
80 | overflow: 'hidden',
81 | position: 'relative'
82 | },
83 | compsList: {
84 | width: '100%',
85 | height: '100%',
86 | position: 'absolute',
87 | top: '0',
88 | left: '0',
89 | overflow: 'auto'
90 | },
91 | bottomNavigation: {
92 | borderRadius:'4px',
93 | width: '100%',
94 | flexGrow: 0,
95 | height: '40px',
96 | marginBottom: '20px',
97 | marginTop: '20px',
98 | textAlign: 'center'
99 | }
100 | })
101 |
102 | class Render extends React.Component {
103 |
104 | constructor() {
105 | super()
106 | this.endRender = this.endRender.bind(this)
107 | this.getItem = this.getItem.bind(this)
108 | }
109 |
110 | getItem(item) {
111 | return (
)
115 | }
116 |
117 | getItems() {
118 | return this.props.renderingItems.map(this.getItem)
119 | }
120 |
121 | endRender() {
122 | if(!this.props.render.finished) {
123 | this.props.stopRender()
124 | } else {
125 | this.props.goToComps()
126 | }
127 | //browserHistory.push('/')
128 | }
129 |
130 | navigateToFolder(item) {
131 | goToFolder(item.destination)
132 | }
133 |
134 |
135 | render() {
136 | let progress = this.props.render.progress
137 | let barStyle = {'transform':'translateX(-' + 100 * (1 - progress) + '%)'}
138 | let finishText = this.props.render.finished ? 'Done' : 'Cancel'
139 | return (
140 |
141 |
142 |
143 |
144 |
145 |
146 |
{this.props.render.message}
147 |
148 |
152 |
153 |
154 | {this.getItems()}
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 | );
163 | }
164 | }
165 |
166 | function mapStateToProps(state) {
167 | return render_selector(state)
168 | }
169 |
170 | const mapDispatchToProps = {
171 | stopRender: stopRender,
172 | goToComps: goToComps
173 | }
174 |
175 | export default connect(mapStateToProps, mapDispatchToProps)(Render)
176 |
--------------------------------------------------------------------------------
/src/views/render/list/RenderItem.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, css } from 'aphrodite'
3 | import status_button from '../../../assets/svg/cancel_button.svg'
4 | import complete_icon from '../../../assets/svg/complete_icon.svg'
5 | import Variables from '../../../helpers/styles/variables'
6 | import BodymovinFolder from '../../../components/bodymovin/bodymovin_folder'
7 |
8 | const styles = StyleSheet.create({
9 | compElement: {
10 | width: '100%',
11 | height: '33px',
12 | backgroundColor: Variables.colors.gray_darkest,
13 | position: 'relative'
14 | },
15 | compElementProgress: {
16 | width: '100%',
17 | height: '100%',
18 | background: Variables.gradients.blueGreen,
19 | opacity: 0.05,
20 | position: 'absolute',
21 | top: 0,
22 | left: 0
23 | },
24 | compElementContent: {
25 | width: '100%',
26 | height: '100%',
27 | position: 'absolute',
28 | top: 0,
29 | left: 0,
30 | display: 'flex',
31 | alignItems: 'center'
32 | },
33 | compElementContentFolder: {
34 | width: '50px',
35 | height: '100%',
36 | flexGrow: 0,
37 | padding: '2px 20px 2px 0px'
38 | },
39 | compElementContentFolder__button: {
40 | background: 'none',
41 | padding: 0,
42 | width: '100%',
43 | height: '100%',
44 | cursor: 'pointer'
45 | },
46 | compElementContentFolder__image: {
47 | width: '100%',
48 | height: '100%'
49 | },
50 | compElementContentToggle: {
51 | width: '30px',
52 | height: '100%',
53 | flexGrow: 0,
54 | padding: '5px'
55 | },
56 | compElementContentToggleImage: {
57 | width: '100%',
58 | height: '100%'
59 | },
60 | compElementContentName: {
61 | width: '100%',
62 | flexGrow: 1,
63 | padding: '0 4px',
64 | whiteSpace: 'nowrap',
65 | textOverflow: 'ellipsis',
66 | overflow: 'hidden'
67 | }
68 | })
69 |
70 | let RenderItem = (props) => {
71 | return (
72 |
73 |
74 |
{props.item.name}
75 | {props.item.renderStatus === 0 &&
76 |
79 |
}
80 | {props.item.renderStatus === 1 &&
81 |

82 |
}
83 |
84 |
props.navigateToFolder(props.item)}>
85 |
86 |
87 |
88 |
89 | )
90 | }
91 |
92 | export default RenderItem
--------------------------------------------------------------------------------
/src/views/settings/collapsable/SettingsCollapsableItem.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, css } from 'aphrodite'
3 | import BodymovinToggle from '../../../components/bodymovin/bodymovin_toggle'
4 | import expander from '../../../assets/animations/expander.json'
5 | import Variables from '../../../helpers/styles/variables'
6 | import textEllipsis from '../../../helpers/styles/textEllipsis'
7 |
8 | const styles = StyleSheet.create({
9 | wrapper: {
10 | width: '100%',
11 | height: 'auto',
12 | backgroundColor: Variables.colors.gray_darkest,
13 | },
14 | composition: {
15 | width: '100%',
16 | fontSize: '12px',
17 | color: Variables.colors.white,
18 | height: '40px',
19 | padding: '4px 0',
20 | display: 'flex',
21 | alignItems: 'center',
22 | cursor: 'pointer'
23 | },
24 | composition__active: {
25 | background: Variables.gradients.blueGreen
26 | },
27 | item: {
28 | flexGrow: 0,
29 | flexShrink: 0,
30 | backgroundColor:'transparent'
31 | },
32 | radio: {
33 | width: '60px',
34 | height: '20px',
35 | padding:'2px',
36 | display:'inline-block'
37 | },
38 | title: {
39 | width: '60px',
40 | padding:'2px',
41 | display:'inline-block'
42 | },
43 | name: {
44 | flexGrow: 1,
45 | flexShrink: 1,
46 | padding: '0 4px'
47 | },
48 | 'name--title': {
49 | color: '#fff',
50 | fontSize: '14px',
51 | marginRight: '10px'
52 | },
53 | 'name--desc': {
54 | color: '#ccc',
55 | fontSize: '12px'
56 | },
57 | disabled: {
58 | opacity: .3
59 | },
60 | children_container: {
61 | padding: '0 0 0 25px'
62 | }
63 | })
64 |
65 | class SettingsCollapsableItem extends React.PureComponent {
66 |
67 | constructor(props) {
68 | super(props)
69 | this.state = {
70 | toggle: 'off'
71 | }
72 | }
73 |
74 | renderItems() {
75 |
76 | }
77 |
78 | toggleOptions = () => {
79 | this.setState({
80 | toggle: this.state.toggle === 'on' ? 'off' : 'on'
81 | })
82 | }
83 |
84 | render(){
85 | return (
87 |
88 |
89 |
90 |
91 |
92 | {this.props.title}
93 | {this.props.description}
94 |
95 |
96 | {this.state.toggle === 'on' &&
97 | {this.props.children}
98 |
}
99 | )
100 | }
101 | }
102 |
103 | export default SettingsCollapsableItem
--------------------------------------------------------------------------------
/src/views/settings/list/SettingsListItem.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, css } from 'aphrodite'
3 | import BodymovinCheckbox from '../../../components/bodymovin/bodymovin_checkbox'
4 | import checkbox from '../../../assets/animations/checkbox.json'
5 | import Variables from '../../../helpers/styles/variables'
6 |
7 | const styles = StyleSheet.create({
8 | wrapper: {
9 | width: '100%',
10 | paddingBottom: '10px',
11 | minHeight: '40px',
12 | backgroundColor: Variables.colors.gray_darkest,
13 | },
14 | composition: {
15 | width: '100%',
16 | fontSize: '12px',
17 | color: Variables.colors.white,
18 | padding: '4px 0',
19 | height: '100%',
20 | display: 'flex',
21 | alignItems: 'end'
22 | },
23 | composition__active: {
24 | background: Variables.gradients.blueGreen
25 | },
26 | item: {
27 | flexGrow: 0,
28 | flexShrink: 0,
29 | backgroundColor:'transparent'
30 | },
31 | radio: {
32 | width: '60px',
33 | height: '20px',
34 | padding:'2px',
35 | cursor: 'pointer'
36 | },
37 | name: {
38 | flexGrow: 1,
39 | flexShrink: 1,
40 | padding: '0 4px'
41 | },
42 | 'name--title': {
43 | color: '#fff',
44 | fontSize: '14px',
45 | marginRight: '10px',
46 | paddingBottom: '4px',
47 | },
48 | 'name--desc': {
49 | color: '#ccc',
50 | fontSize: '12px',
51 | lineHeight: '14px'
52 | },
53 | inputBox: {
54 | border: '1px solid ' + Variables.colors.white,
55 | backgroundColor: '#333',
56 | borderRadius: '6px',
57 | maxWidth:'50px',
58 | marginRight:'20px' ,
59 | padding: '3px'
60 | },
61 | inputInput: {
62 | background: 'none',
63 | width:'100%',
64 | border: 'none',
65 | ':focus': {
66 | border: 'none',
67 | outline: 'none'
68 | },
69 | color: Variables.colors.white
70 | },
71 | disabled: {
72 | opacity: .3
73 | }
74 | })
75 |
76 | class SettingsListItem extends React.PureComponent {
77 |
78 | render(){
79 | return (
81 |
82 |
83 |
84 |
85 |
86 |
{this.props.title}
87 |
{this.props.description}
88 |
89 | {this.props.needsInput &&
90 |
91 |
}
92 |
93 | )
94 | }
95 | }
96 |
97 | export default SettingsListItem
--------------------------------------------------------------------------------