├── .eslintrc.js ├── LICENSE ├── README.md ├── React.15 ├── Basic │ ├── .babelrc │ ├── README.md │ ├── __tests__ │ │ ├── .setup.js │ │ └── app.ctrl.test.jsx │ ├── js │ │ └── server.js │ ├── package.json │ ├── ui-src │ │ ├── app.jsx │ │ ├── components │ │ │ ├── app.ctrl.jsx │ │ │ ├── app.notes.jsx │ │ │ └── app.text.js │ │ ├── css │ │ │ └── index.css │ │ ├── img │ │ │ └── favicon.ico │ │ └── index.html │ ├── webpack.config.js │ └── webpack.config.json ├── BasicIsometric │ ├── README.md │ ├── js │ │ └── server.js │ ├── package.json │ ├── ui-src │ │ ├── app.jsx │ │ ├── appiso.js │ │ ├── components │ │ │ └── app.ctrl.jsx │ │ ├── css │ │ │ └── index.css │ │ └── img │ │ │ └── favicon.ico │ ├── views │ │ └── index.ejs │ ├── webpack.config.js │ └── webpack.config.json ├── GoogleMaps │ ├── README.md │ ├── js │ │ └── server.js │ ├── package.json │ ├── ui-src │ │ ├── app.jsx │ │ ├── components │ │ │ ├── app.ctrl.jsx │ │ │ ├── common │ │ │ │ ├── app.colors.js │ │ │ │ ├── app.style.jsx │ │ │ │ └── nav1.bar.jsx │ │ │ └── dashboard │ │ │ │ ├── dashboard.page.jsx │ │ │ │ ├── map.ctrl.jsx │ │ │ │ └── mapStyle.js │ │ ├── css │ │ │ ├── Draft.css │ │ │ └── index.css │ │ ├── img │ │ │ └── favicon.ico │ │ ├── index.html │ │ └── store │ │ │ ├── App.Store.js │ │ │ ├── app │ │ │ ├── app.actions.js │ │ │ └── app.reducer.js │ │ │ └── map │ │ │ ├── map.actions.js │ │ │ └── map.reducer.js │ ├── webpack.config.js │ └── webpack.config.json ├── ReduxElectron │ ├── README.md │ ├── config.json │ ├── data │ │ └── basic.json │ ├── js │ │ └── mainipc.js │ ├── main.js │ ├── package.json │ ├── ui-src │ │ ├── app.jsx │ │ ├── components │ │ │ ├── app.ctrl.jsx │ │ │ └── app.notes.jsx │ │ ├── css │ │ │ └── index.css │ │ ├── img │ │ │ └── favicon.ico │ │ ├── index.html │ │ └── store │ │ │ ├── Actions.js │ │ │ ├── App.Store.js │ │ │ └── ipc.api.js │ ├── webpack.config.js │ ├── webpack.config.json │ ├── windowstate.json │ └── yarn.lock ├── ReduxFetch │ ├── .babelrc │ ├── README.md │ ├── __tests__ │ │ ├── .setup.js │ │ ├── app.ctrl.test.jsx │ │ └── server.test.js │ ├── cert.csr │ ├── certificate.pem │ ├── data │ │ └── basic.json │ ├── js │ │ ├── routes.js │ │ ├── routes │ │ │ └── GetSetData.js │ │ └── server.js │ ├── package.json │ ├── private.key │ ├── ui-src │ │ ├── app.jsx │ │ ├── components │ │ │ ├── app.ctrl.jsx │ │ │ ├── app.notes.jsx │ │ │ └── app.text.js │ │ ├── css │ │ │ └── index.css │ │ ├── img │ │ │ └── favicon.ico │ │ ├── index.html │ │ └── store │ │ │ ├── App.Store.js │ │ │ └── api.Actions.js │ ├── webpack.config.js │ └── webpack.config.json ├── ReduxPages │ ├── README.md │ ├── js │ │ └── server.js │ ├── package.json │ ├── ui-src │ │ ├── app.jsx │ │ ├── components │ │ │ ├── app.ctrl.jsx │ │ │ ├── cache │ │ │ │ └── cache.page.jsx │ │ │ ├── common │ │ │ │ ├── app.colors.js │ │ │ │ ├── app.style.jsx │ │ │ │ └── nav.bar.jsx │ │ │ ├── event │ │ │ │ └── event.page.jsx │ │ │ ├── home │ │ │ │ └── home.page.jsx │ │ │ ├── object │ │ │ │ └── object.page.jsx │ │ │ └── radium │ │ │ │ ├── button.jsx │ │ │ │ ├── computed-well.jsx │ │ │ │ ├── hover.jsx │ │ │ │ └── radium.page.jsx │ │ ├── css │ │ │ └── index.css │ │ ├── img │ │ │ └── favicon.ico │ │ ├── index.html │ │ ├── lib │ │ │ └── cache.js │ │ └── store │ │ │ ├── App.Store.js │ │ │ └── app │ │ │ ├── app.actions.js │ │ │ └── app.reducer.js │ ├── webpack.config.js │ ├── webpack.config.json │ └── yarn.lock └── ReduxSocketIO │ ├── README.md │ ├── data │ └── basic.json │ ├── js │ ├── mainsocket.js │ ├── server.js │ └── socket │ │ └── GetSetData.js │ ├── package.json │ ├── ui-src │ ├── app.jsx │ ├── components │ │ ├── app.ctrl.jsx │ │ └── app.notes.jsx │ ├── css │ │ └── index.css │ ├── img │ │ └── favicon.ico │ ├── index.html │ └── store │ │ ├── Actions.js │ │ ├── App.Store.js │ │ └── ws.api.js │ ├── webpack.config.js │ ├── webpack.config.json │ └── yarn.lock ├── React.Common ├── README.md ├── data │ ├── AppData.json │ ├── ImageList.json │ ├── TreeView.json │ └── inputs.json ├── js │ ├── routes.js │ ├── routes │ │ ├── GetPicList.js │ │ └── GetSetData.js │ └── server.js ├── package.json ├── ui-src │ ├── app.jsx │ ├── components │ │ ├── Button │ │ │ ├── app.text.js │ │ │ └── button.page.jsx │ │ ├── DropDowns │ │ │ ├── app.text.js │ │ │ ├── dropdown.menu.jsx │ │ │ ├── dropdown.page.jsx │ │ │ ├── dropdown.select.jsx │ │ │ └── multi.select.jsx │ │ ├── FormInput │ │ │ ├── app.text.js │ │ │ └── input.page.jsx │ │ ├── Gallery │ │ │ ├── app.text.js │ │ │ └── gallery.page.jsx │ │ ├── List │ │ │ ├── app.text.js │ │ │ └── list.page.jsx │ │ ├── PageIndicator │ │ │ ├── indicator.page.jsx │ │ │ ├── indicator.pop.jsx │ │ │ ├── indicator.style.js │ │ │ └── indicator.text.js │ │ ├── ProgressBar │ │ │ ├── app.text.js │ │ │ └── progress.page.jsx │ │ ├── Sliders │ │ │ ├── app.text.js │ │ │ └── sliders.page.jsx │ │ ├── Tooltip │ │ │ ├── app.text.js │ │ │ └── tooltip.page.jsx │ │ ├── TreeViews │ │ │ ├── app.text.js │ │ │ ├── jumplist │ │ │ │ └── jump.ctrl.jsx │ │ │ ├── treeview.page.jsx │ │ │ └── treeview │ │ │ │ ├── tree.ctrl.jsx │ │ │ │ ├── tree.detail.jsx │ │ │ │ ├── tree.edit.jsx │ │ │ │ ├── tree.list.jsx │ │ │ │ ├── tree.menu.jsx │ │ │ │ └── tree.new.jsx │ │ ├── app.ctrl.jsx │ │ └── common │ │ │ ├── Button │ │ │ └── jButton.jsx │ │ │ ├── DropDowns │ │ │ ├── Icon.jsx │ │ │ ├── jDropMenu.jsx │ │ │ ├── jDropSelect.jsx │ │ │ └── jMultiSelect.jsx │ │ │ ├── FormInput │ │ │ └── jInput.jsx │ │ │ ├── Gallery │ │ │ ├── gallery.style.js │ │ │ ├── jGallery.jsx │ │ │ ├── jThumbs.jsx │ │ │ ├── listitem.jsx │ │ │ └── shortcuts.jsx │ │ │ ├── List │ │ │ └── jList.jsx │ │ │ ├── PageIndicator │ │ │ └── jPageIndicator.jsx │ │ │ ├── ProgressBar │ │ │ └── jProgressBar.jsx │ │ │ ├── Sliders │ │ │ ├── jRangeSelector.jsx │ │ │ └── jSlider.jsx │ │ │ ├── Tooltip │ │ │ └── jTooltip.jsx │ │ │ ├── TreeViews │ │ │ ├── jTreeView.jsx │ │ │ └── jTreeViewB.jsx │ │ │ ├── app.colors.js │ │ │ ├── app.notes.jsx │ │ │ ├── app.style.jsx │ │ │ └── nav.bar.jsx │ ├── css │ │ ├── index.css │ │ └── rangeInput.css │ ├── img │ │ ├── 1x1TransShim.gif │ │ ├── SLogoS5-48_C.png │ │ ├── favicon.ico │ │ ├── flow.png │ │ ├── leaf.ico │ │ ├── snow.ico │ │ └── sun.ico │ ├── index.html │ └── store │ │ ├── App.Store.js │ │ ├── api │ │ └── api.Actions.js │ │ ├── app │ │ ├── app.actions.js │ │ └── app.reducer.js │ │ ├── gallery │ │ └── gallery.Reducer.js │ │ ├── input │ │ ├── input.Actions.js │ │ └── input.Reducer.js │ │ └── treeview │ │ ├── tree.Actions.js │ │ └── tree.Reducer.js ├── webpack.config.js ├── webpack.config.json └── yarn.lock └── package.json /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Janaka Stevens 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReactPatterns 2 | 3 | A collection of simple react projects providing reusable components, startup and test examples. Its my react playground. 4 | I am using webpack 2 and babel for the build tool chain. 5 | I have added linting with eslint. The linting rules are in .eslintrc.js. 6 | 7 | **React.15** 8 | * Basic 9 | * Basic Isometric/Universal 10 | * GoogleMaps 11 | * Redux Electron 12 | * Redux Fetch ajax 13 | * Redux Pages 14 | * Radium 15 | * Window Events 16 | * Window Object 17 | * Redux SocketIO 18 | 19 | **React.Common** 20 | * Button 21 | * DropDowns 22 | * Form Input 23 | * Gallery 24 | * List 25 | * PageIndicator 26 | * ProgressBar 27 | * Sliders 28 | * Tooltip 29 | * TreeViews 30 | 31 | # The basics 32 | 33 | Open two terminals at the desired project root. I use iTerm on Mac, ConEmu on Windows 10. 34 | First time do "npm install". On the React.15 projects in one terminal "npm run ww". 35 | In the other terminal "npm start". 36 | In your browser localhost:3500. All projects use the same port. 37 | If you want to do it with one terminal session you can run "npm run nw" for no watch. 38 | 39 | 40 | There is a code viewer running on page 2 of examples at http://jmarkstevens.com/. 41 | -------------------------------------------------------------------------------- /React.15/Basic/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react", "stage-0"] 3 | } -------------------------------------------------------------------------------- /React.15/Basic/README.md: -------------------------------------------------------------------------------- 1 | # ReactPatterns Basic 2 | 3 | Just the basics for react 15. 4 | 5 | # Getting started 6 | 7 | cd into the root directory of the project. If the first time "npm install". "npm run ww" for webpack with watch. 8 | "npm run nw" for webpack no watch. "npm start" to start the node server. "localhost:3500" in the browser. 9 | "npm test" for unit testing with Jest and Enzyme. 10 | -------------------------------------------------------------------------------- /React.15/Basic/__tests__/.setup.js: -------------------------------------------------------------------------------- 1 | require('babel-register')(); 2 | 3 | var jsdom = require('jsdom').jsdom; 4 | 5 | var exposedProperties = ['window', 'navigator', 'document']; 6 | 7 | global.document = jsdom(''); 8 | global.window = document.defaultView; 9 | Object.keys(document.defaultView).forEach((property) => { 10 | if (typeof global[property] === 'undefined') { 11 | exposedProperties.push(property); 12 | global[property] = document.defaultView[property]; 13 | } 14 | }); 15 | 16 | global.navigator = { 17 | userAgent: 'node.js' 18 | }; 19 | 20 | documentRef = document; 21 | -------------------------------------------------------------------------------- /React.15/Basic/__tests__/app.ctrl.test.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | import {shallow, mount} from 'enzyme'; 5 | import {expect} from 'chai'; 6 | 7 | import AppCtrl from '../ui-src/components/app.ctrl'; 8 | 9 | describe('shallow() ', () => { 10 | const wrapper = shallow(); 11 | it('checks div count', () => { 12 | expect(wrapper.find('div').length).to.equal(1); 13 | }); 14 | it('checks br count', () => { 15 | expect(wrapper.find('br').length).to.equal(0); 16 | }); 17 | it('checks text', () => { 18 | expect(wrapper.text()).to.equal('Hello World'); 19 | }); 20 | it('checks state world', () => { 21 | expect(wrapper.state('world')).to.equal('Hello World'); 22 | }); 23 | }); 24 | 25 | describe('mount() ', () => { 26 | const wrapper = mount(); 27 | it('checks text', () => { 28 | expect(wrapper.text()).to.equal('Hello WorldHide notesThis is a minimal starter project when not using flux.\n The only thing added is the hello world which demonstrates the use of state.'); 29 | }); 30 | it('checks state world', () => { 31 | expect(wrapper.state('world')).to.equal('Hello World'); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /React.15/Basic/js/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | const favicon = require('serve-favicon'); 5 | const path = require('path'); 6 | const port = Number(process.env.BASICPORT || 3500); 7 | 8 | const app = express(); 9 | app.listen(port); 10 | 11 | app.use('/', express.static('ui-dist')); 12 | app.use(favicon(path.join(__dirname, '..', 'ui-dist', 'img', 'favicon.ico'))); 13 | app.get('/', function(req, res){ res.sendfile(__dirname + '/index.html', [], null); }); 14 | -------------------------------------------------------------------------------- /React.15/Basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReactPatterns.15-Basic", 3 | "version": "1.0.0", 4 | "description": "A collection of simple react projects providing reusable components, startup and test examples.", 5 | "license": "MIT", 6 | "author": { 7 | "name": "Janaka Stevens", 8 | "email": "jmstevens@calitek.com" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/calitek/ReactPatterns.git" 13 | }, 14 | "scripts": { 15 | "start": "node js/server.js", 16 | "test": "mocha __tests__/.setup.js __tests__/**/*.test.js?", 17 | "testw": "npm test -- --watch", 18 | "ww": "webpack --progress --profile --colors --env.noMinimize --watch", 19 | "nw": "webpack --progress --profile --colors --env.noMinimize" 20 | }, 21 | "dependencies": { 22 | "express": "latest", 23 | "serve-favicon": "latest" 24 | }, 25 | "devDependencies": { 26 | "react": "^15.4.0", 27 | "react-dom": "^15.4.0", 28 | 29 | "babel-core": "latest", 30 | "babel-loader": "^6.1.0", 31 | "babel-preset-es2015": "latest", 32 | "babel-preset-react": "latest", 33 | "babel-preset-stage-0": "latest", 34 | "css-loader": "latest", 35 | "extract-text-webpack-plugin": "^2.0.0-rc.3", 36 | "file-loader": "latest", 37 | "loader-utils": "latest", 38 | "style-loader": "^0.13.1", 39 | "webpack": "latest", 40 | 41 | "babel-register": "latest", 42 | "chai": "latest", 43 | "chai-http": "latest", 44 | "enzyme": "latest", 45 | "jsdom": "latest", 46 | "mocha": "latest", 47 | "react-addons-test-utils": "^15.4.0", 48 | "sinon": "latest" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /React.15/Basic/ui-src/app.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import './index.html'; 4 | import './css/index.css'; 5 | import './img/favicon.ico'; 6 | 7 | import React from 'react'; 8 | import ReactDom from 'react-dom'; 9 | 10 | import AppCtrl from './components/app.ctrl'; 11 | 12 | window.ReactDom = ReactDom; 13 | 14 | ReactDom.render( , document.getElementById('react') ); 15 | -------------------------------------------------------------------------------- /React.15/Basic/ui-src/components/app.ctrl.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import AppNotes from './app.notes'; 4 | 5 | let AppCtrlSty = { 6 | height: '100%', 7 | padding: '0 10px 0 0' 8 | }; 9 | 10 | export default class AppCtrl extends React.Component { 11 | state = {world: ''}; 12 | componentWillMount = () => { this.sayHello(); }; 13 | sayHello = () => { this.setState({world: 'Hello World'}); }; 14 | render() { 15 | return ( 16 |
17 | {this.state.world} 18 | 19 |
20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /React.15/Basic/ui-src/components/app.notes.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import AppText from './app.text'; 4 | 5 | const AppNotesSty = { 6 | marginLeft: 'auto', 7 | marginRight: 'auto', 8 | marginTop: '30px', 9 | maxWidth: '500px', 10 | textIndent: '20px' 11 | }; 12 | 13 | const textSty = { 14 | color: '#FFF', 15 | fontSize: '1.0em', 16 | textAlign: 'left' 17 | }; 18 | 19 | const btnDivSty = {textAlign: 'center'}; 20 | 21 | const standardBtnSty = { 22 | backgroundColor: '#9a6', 23 | borderBottomColor: '#cea', 24 | borderLeftColor: '#93a363', 25 | borderRightColor: '#cea', 26 | borderTopColor: '#93a363', 27 | borderRadius: '6px', 28 | color: '#eeffee', 29 | cursor: 'pointer', 30 | lineHeight: '100%', 31 | outline: 'none', 32 | verticalAlign: 'middle', 33 | whiteSpace: 'nowrap' 34 | }; 35 | 36 | export default class AppNotes extends React.Component { 37 | state = {show: true}; 38 | onClick = () => { this.setState({show: !this.state.show}); }; 39 | render() { 40 | if (AppText.p1Text.trim().length === 0) return null; 41 | let showNotes = this.state.show; 42 | let btnText = showNotes ? 'Hide notes' : 'Show notes'; 43 | let notesDivSty = showNotes ? {display: 'block'} : {display: 'none'}; 44 | return ( 45 |
46 |
47 | 48 |
49 |
50 |

{AppText.p1Text}

51 |
52 |
53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /React.15/Basic/ui-src/components/app.text.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | p1Text: ` 3 | This is a minimal starter project when not using flux. 4 | The only thing added is the hello world which demonstrates the use of state. 5 | ` 6 | }; 7 | -------------------------------------------------------------------------------- /React.15/Basic/ui-src/css/index.css: -------------------------------------------------------------------------------- 1 | .bodyStyle { 2 | background-color: #00303f; 3 | color: #eae3ea; 4 | display: block; 5 | overflow: hidden; 6 | width: 100%; 7 | } 8 | 9 | .header { 10 | height: 30px; 11 | margin: 0; 12 | padding: 10px 0; 13 | text-align: center; 14 | } 15 | 16 | .Title {font-size: 1.3em;} 17 | 18 | .content { 19 | height: calc(100% - 52px); 20 | max-width: 1366px; 21 | margin-left: auto; 22 | margin-right: auto; 23 | padding: 0 5px; 24 | } 25 | 26 | * { outline: none; } 27 | 28 | .a{display:block} 29 | 30 | .FlexBox { 31 | display: -webkit-box; 32 | display: -moz-box; 33 | display: -ms-flexbox; 34 | display: flex; 35 | } 36 | 37 | .FlexBoxJustAround { 38 | display: -webkit-box; 39 | display: -moz-box; 40 | display: -ms-flexbox; 41 | display: flex; 42 | justify-content: space-around; 43 | } 44 | 45 | .FlexBoxJustBetween { 46 | display: -webkit-box; 47 | display: -moz-box; 48 | display: -ms-flexbox; 49 | display: flex; 50 | justify-content: space-between; 51 | } 52 | 53 | .FlexBoxWrap { 54 | display: -webkit-box; 55 | display: -moz-box; 56 | display: -ms-flexbox; 57 | display: flex; 58 | flex-wrap: wrap; 59 | } 60 | 61 | .FlexJustify { 62 | -webkit-box-pack: justify; 63 | justify-content: space-between; 64 | } 65 | 66 | .FlexBoxStretch { 67 | display: -webkit-box; 68 | display: -moz-box; 69 | display: -ms-flexbox; 70 | display: flex; 71 | align-content: stretch; 72 | } 73 | 74 | .FlexItem { 75 | flex-grow: 1; 76 | } 77 | 78 | .HighZ {z-index: 200;} 79 | -------------------------------------------------------------------------------- /React.15/Basic/ui-src/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.15/Basic/ui-src/img/favicon.ico -------------------------------------------------------------------------------- /React.15/Basic/ui-src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ReactPatterns-Basic 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | ReactPatterns-Basic 16 |
17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /React.15/Basic/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 3 | const webpack = require('webpack'); 4 | const configJson = require('./webpack.config.json'); 5 | 6 | module.exports = (env) => { 7 | 8 | const noMinimize = env.noMinimize; 9 | var plugins = []; 10 | 11 | plugins.push(new ExtractTextPlugin({filename: 'app.css', allChunks: true})); 12 | plugins.push(new webpack.optimize.CommonsChunkPlugin({name: 'lib'})); 13 | if (noMinimize) { 14 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('development')}})); 15 | } else { 16 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('production')}})); 17 | plugins.push(new webpack.optimize.UglifyJsPlugin({include: /lib\.js/, minimize: true})); 18 | } 19 | 20 | const ROOT_PATH = path.resolve(__dirname); 21 | const SRC_PATH = path.resolve(ROOT_PATH, './ui-src'); 22 | const DIST_PATH = path.resolve(ROOT_PATH, './ui-dist'); 23 | 24 | 25 | return { 26 | context: SRC_PATH, 27 | entry: { 28 | app: './app.jsx', 29 | lib: configJson.lib 30 | }, 31 | 32 | output: { 33 | path: DIST_PATH, 34 | filename: '[name].js' 35 | }, 36 | 37 | module: { 38 | rules: [ 39 | { 40 | test: /\.jsx?$/, 41 | loader: 'babel-loader', 42 | query: {presets:['es2015', 'react', 'stage-0']}, 43 | exclude: /(node_modules)/, 44 | }, 45 | { 46 | test: /\.css$/, 47 | use: ExtractTextPlugin.extract({ 48 | fallback: 'style-loader', 49 | use: 'css-loader' 50 | }) 51 | }, 52 | { 53 | test: /\.(png|jpg|ico|gif)$/, 54 | loader: 'file-loader?name=img/[name].[ext]' 55 | }, 56 | { 57 | test: /\.(html)$/, 58 | loader: 'file-loader?name=[name].[ext]' 59 | } 60 | ] 61 | }, 62 | plugins, 63 | resolve: { 64 | extensions: ['.js', '.jsx'], 65 | modules: ['node_modules'] 66 | } 67 | }; 68 | }; 69 | -------------------------------------------------------------------------------- /React.15/Basic/webpack.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": [ 3 | "react", 4 | "react-dom" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /React.15/BasicIsometric/README.md: -------------------------------------------------------------------------------- 1 | # ReactPatterns BasicIsometric 2 | 3 | A basic isometric project. 4 | 5 | # Getting started 6 | 7 | cd into the root directory of the project. If the first time "npm install". "npm run ww" for webpack with watch. 8 | "npm run nw" for webpack no watch. "npm start" to start the node server. "localhost:3500" in the browser. 9 | -------------------------------------------------------------------------------- /React.15/BasicIsometric/js/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | const favicon = require('serve-favicon'); 5 | const path = require('path'); 6 | const port = Number(3500); 7 | 8 | const app = express(); 9 | app.listen(port); 10 | 11 | // require('node-jsx').install(); 12 | const React = require('react'); 13 | const ReactDOMServer = require('react-dom/server'); 14 | require('babel-register')({presets:['es2015', 'react', 'stage-0']}); 15 | const AppInput = require('../ui-src/appiso'); 16 | // const ReactApp = AppCtrlInput.default; 17 | const ReactApp = React.createFactory(AppInput.AppCtrl); 18 | // console.log('ReactApp: ', ReactApp); 19 | 20 | app.use('/', express.static('./')); 21 | app.use(favicon(path.join(__dirname, '..', 'ui-src', 'img', 'favicon.ico'))); 22 | app.set('view engine', 'ejs'); 23 | 24 | app.get('/', function(req, res){ 25 | const reactHtml = ReactDOMServer.renderToString(ReactApp()); 26 | // console.log('reactHtml: ', reactHtml); 27 | res.render('index.ejs', {reactOutput: reactHtml}); 28 | // res.sendfile(__dirname + '/index.html', [], null); 29 | }); 30 | -------------------------------------------------------------------------------- /React.15/BasicIsometric/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReactPatterns-BasicIsometric", 3 | "version": "1.0.0", 4 | "description": "A collection of simple react projects providing reusable components, startup and test examples.", 5 | "license": "MIT", 6 | "author": { 7 | "name": "Janaka Stevens", 8 | "email": "jmstevens@calitek.com" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/calitek/ReactPatterns.git" 13 | }, 14 | "scripts": { 15 | "start": "node js/server.js", 16 | "ww": "webpack --progress --profile --colors --env.noMinimize --watch", 17 | "nw": "webpack --progress --profile --colors --env.noMinimize", 18 | "dist": "NODE_ENV=production webpack --progress --profile --colors" 19 | }, 20 | "dependencies": { 21 | "babel-register": "latest", 22 | "ejs": "^2.4.1", 23 | "express": "latest", 24 | "serve-favicon": "latest" 25 | }, 26 | "devDependencies": { 27 | "react": "^15.0.0", 28 | "react-dom": "^15.0.0", 29 | 30 | "babel-core": "latest", 31 | "babel-loader": "^6.1.0", 32 | "babel-preset-es2015": "latest", 33 | "babel-preset-react": "latest", 34 | "babel-preset-stage-0": "latest", 35 | "css-loader": "latest", 36 | "extract-text-webpack-plugin": "^2.0.0-rc.3", 37 | "file-loader": "latest", 38 | "style-loader": "^0.13.1", 39 | "webpack": "latest" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /React.15/BasicIsometric/ui-src/app.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import './css/index.css'; 4 | import './img/favicon.ico'; 5 | 6 | import React from 'react'; 7 | import ReactDom from 'react-dom'; 8 | 9 | import AppCtrl from './components/app.ctrl'; 10 | 11 | ReactDom.render(, document.getElementById('react')); 12 | -------------------------------------------------------------------------------- /React.15/BasicIsometric/ui-src/appiso.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import AppCtrl from './components/app.ctrl'; 4 | 5 | exports.AppCtrl = AppCtrl 6 | -------------------------------------------------------------------------------- /React.15/BasicIsometric/ui-src/components/app.ctrl.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | let AppCtrlSty = { 4 | height: '100%', 5 | padding: '0 10px 0 0' 6 | }; 7 | 8 | export default class AppCtrl extends React.Component { 9 | state = {world: ''}; 10 | componentDidMount = () => { this.sayHello(); }; 11 | sayHello = () => { this.setState({world: 'Hello World'}); }; 12 | render() { 13 | return ( 14 |
15 | React Basic Isometric 16 |

17 | {this.state.world} 18 |
19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /React.15/BasicIsometric/ui-src/css/index.css: -------------------------------------------------------------------------------- 1 | .bodyStyle { 2 | background-color: #00303f; 3 | color: #eae3ea; 4 | display: block; 5 | overflow: hidden; 6 | width: 100%; 7 | } 8 | 9 | .header { 10 | height: 30px; 11 | margin: 0; 12 | padding: 10px 0; 13 | text-align: center; 14 | } 15 | 16 | .Title {font-size: 1.3em;} 17 | 18 | .content { 19 | height: calc(100% - 52px); 20 | max-width: 1366px; 21 | margin-left: auto; 22 | margin-right: auto; 23 | padding: 0 5px; 24 | } 25 | 26 | * { outline: none; } 27 | 28 | .a{display:block} 29 | 30 | .FlexBox { 31 | display: -webkit-box; 32 | display: -moz-box; 33 | display: -ms-flexbox; 34 | display: flex; 35 | } 36 | 37 | .FlexBoxJustAround { 38 | display: -webkit-box; 39 | display: -moz-box; 40 | display: -ms-flexbox; 41 | display: flex; 42 | justify-content: space-around; 43 | } 44 | 45 | .FlexBoxJustBetween { 46 | display: -webkit-box; 47 | display: -moz-box; 48 | display: -ms-flexbox; 49 | display: flex; 50 | justify-content: space-between; 51 | } 52 | 53 | .FlexBoxWrap { 54 | display: -webkit-box; 55 | display: -moz-box; 56 | display: -ms-flexbox; 57 | display: flex; 58 | flex-wrap: wrap; 59 | } 60 | 61 | .FlexJustify { 62 | -webkit-box-pack: justify; 63 | justify-content: space-between; 64 | } 65 | 66 | .FlexBoxStretch { 67 | display: -webkit-box; 68 | display: -moz-box; 69 | display: -ms-flexbox; 70 | display: flex; 71 | align-content: stretch; 72 | } 73 | 74 | .FlexItem { 75 | flex-grow: 1; 76 | } 77 | 78 | .HighZ {z-index: 200;} 79 | -------------------------------------------------------------------------------- /React.15/BasicIsometric/ui-src/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.15/BasicIsometric/ui-src/img/favicon.ico -------------------------------------------------------------------------------- /React.15/BasicIsometric/views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ReactPatterns-Basic 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | ReactPatterns-Basic Isometric 16 |
17 | 18 |
<%- reactOutput %>
19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /React.15/BasicIsometric/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 3 | const webpack = require('webpack'); 4 | const configJson = require('./webpack.config.json'); 5 | 6 | module.exports = (env) => { 7 | 8 | const noMinimize = env.noMinimize; 9 | var plugins = []; 10 | 11 | plugins.push(new ExtractTextPlugin({filename: 'app.css', allChunks: true})); 12 | plugins.push(new webpack.optimize.CommonsChunkPlugin({name: 'lib'})); 13 | if (noMinimize) { 14 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('development')}})); 15 | } else { 16 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('production')}})); 17 | plugins.push(new webpack.optimize.UglifyJsPlugin({include: /lib\.js/, minimize: true})); 18 | } 19 | 20 | const ROOT_PATH = path.resolve(__dirname); 21 | const SRC_PATH = path.resolve(ROOT_PATH, './ui-src'); 22 | const DIST_PATH = path.resolve(ROOT_PATH, './ui-dist'); 23 | 24 | 25 | return { 26 | context: SRC_PATH, 27 | entry: { 28 | app: './app.jsx', 29 | lib: configJson.lib 30 | }, 31 | 32 | output: { 33 | path: DIST_PATH, 34 | filename: '[name].js' 35 | }, 36 | 37 | module: { 38 | rules: [ 39 | { 40 | test: /\.jsx?$/, 41 | loader: 'babel-loader', 42 | query: {presets:['es2015', 'react', 'stage-0']}, 43 | exclude: /(node_modules)/, 44 | }, 45 | { 46 | test: /\.css$/, 47 | use: ExtractTextPlugin.extract({ 48 | fallback: 'style-loader', 49 | use: 'css-loader' 50 | }) 51 | }, 52 | { 53 | test: /\.(png|jpg|ico|gif)$/, 54 | loader: 'file-loader?name=img/[name].[ext]' 55 | }, 56 | { 57 | test: /\.(html)$/, 58 | loader: 'file-loader?name=[name].[ext]' 59 | } 60 | ] 61 | }, 62 | plugins, 63 | resolve: { 64 | extensions: ['.js', '.jsx'], 65 | modules: ['node_modules'] 66 | } 67 | }; 68 | }; 69 | -------------------------------------------------------------------------------- /React.15/BasicIsometric/webpack.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": [ 3 | "react", 4 | "react-dom" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/README.md: -------------------------------------------------------------------------------- 1 | # ReactPatterns GoogleMaps 2 | 3 | Just the basics for google maps. 4 | You will need your own api key from google. 5 | Features include saving state when going to another page 6 | Uses the google maps api directly. 7 | 8 | # Getting started 9 | 10 | cd into the root directory of the project. If the first time "npm install". "npm run ww" for webpack with watch. 11 | "npm run nw" for webpack no watch. "npm start" to start the node server. "localhost:3500" in the browser. 12 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/js/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | const app = express(); 5 | const server = require('http').Server(app); 6 | 7 | const fs = require('fs'); 8 | 9 | const path = require('path'); 10 | const port = Number(process.env.GOOGLEMAPSPORT || 3500); 11 | 12 | server.listen(port); 13 | 14 | const favicon = require('serve-favicon'); 15 | app.use(favicon(path.join(__dirname, '..', 'ui-dist', 'img', 'favicon.ico'))); 16 | 17 | const rootDir = path.join(__dirname, '..', 'ui-dist'); 18 | 19 | app.use(express.static(rootDir)); 20 | app.get('/', function(req, res) { 21 | res.sendFile(rootDir + '/index.html'); 22 | }); 23 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReactPatterns-GoogleMaps", 3 | "version": "1.0.0", 4 | "description": "A website.", 5 | "license": "MIT", 6 | "author": { 7 | "name": "J Mark Stevens", 8 | "email": "jmstevens@jmarkstevens.com" 9 | }, 10 | "scripts": { 11 | "start": "nodemon --watch js js/server.js", 12 | "ww": "webpack --progress --profile --colors --env.noMinimize --watch", 13 | "nw": "webpack --progress --profile --colors --env.noMinimize" 14 | }, 15 | "dependencies": { 16 | "express": "latest", 17 | "serve-favicon": "latest" 18 | }, 19 | "devDependencies": { 20 | "babel-core": "latest", 21 | "babel-loader": "latest", 22 | "babel-preset-es2015": "latest", 23 | "babel-preset-react": "latest", 24 | "babel-preset-stage-0": "latest", 25 | "css-loader": "latest", 26 | "extract-text-webpack-plugin": "latest", 27 | "file-loader": "latest", 28 | "loader-utils": "latest", 29 | "react": "^15", 30 | "react-dom": "^15", 31 | "react-redux": "latest", 32 | "redux": "latest", 33 | "redux-logger": "latest", 34 | "style-loader": "latest", 35 | "webpack": "latest" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/app.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import './index.html'; 4 | import './css/Draft.css'; 5 | import './css/index.css'; 6 | import './img/favicon.ico'; 7 | 8 | import React from 'react'; 9 | import ReactDom from 'react-dom'; 10 | import {Provider} from 'react-redux'; 11 | 12 | import AppCtrl from './components/app.ctrl'; 13 | import AppStore from './store/App.Store'; 14 | 15 | window.ReactDom = ReactDom; 16 | 17 | ReactDom.render(, document.getElementById('react')); 18 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/components/app.ctrl.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | 4 | import NavBar from './common/nav1.bar'; 5 | 6 | import DashboardPage from './dashboard/dashboard.page'; 7 | 8 | let AppCtrlSty = { 9 | height: '100%', 10 | overflow: 'hidden', 11 | padding: '0px', 12 | width: '100%' 13 | }; 14 | 15 | let allPageSty = { 16 | height: '100%', 17 | margin: '0px', 18 | overflow: 'hidden', 19 | padding: '0px', 20 | width: '100%' 21 | }; 22 | 23 | class AppCtrl extends React.Component { 24 | state = {markers: []}; 25 | componentDidMount() { 26 | let _this = this; 27 | window.setTimeout(() => _this.setMarkers(_this), 2000); 28 | } 29 | setMarkers = _this => { 30 | let merlinLocation = {lat: 32.939095, lng: -117.043607}; 31 | let homeLocation = {lat: 33.264611, lng: -117.083043}; 32 | let nyLocation = {lat: 40.708314, lng: -74.101025}; 33 | let flLocation = {lat: 26.247621, lng: -80.110884}; 34 | return _this.setState({ 35 | markers: [{position: merlinLocation}, {position: homeLocation}, {position: nyLocation}, {position: flLocation}] 36 | }); 37 | }; 38 | render() { 39 | let page = this.props.appState.currentPage; 40 | let hideDashboard = page != 'dashboard'; 41 | return ( 42 |
43 | 44 | 45 |
46 | ); 47 | } 48 | } 49 | 50 | function mapStateToProps(store) { 51 | return {appState: store.appState}; 52 | } 53 | 54 | export default connect(mapStateToProps)(AppCtrl); 55 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/components/common/app.colors.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | morning_sky: '#cae4db', 3 | honey: '#dcae1d', 4 | cerulean: '#00303f', 5 | mist: '#7a9d96', 6 | 7 | bluebell: '#155765', 8 | olive: '#57652a', 9 | ornate: '#ab9353', 10 | plum: '#4d2c3d', 11 | 12 | gold: '#cda34f', 13 | daisy: '#e9e7da', 14 | stem: '#636b46', 15 | greenery: '#373f27', 16 | 17 | aqua: '#6bbaa7', 18 | sunshine: '#fba100', 19 | lavender: '#6c648b', 20 | dusty_rose: '#b6a19e', 21 | 22 | rust: '#b56357', 23 | mint: '#b4dbc0', 24 | slate: '#eae3ea', 25 | sea_foam: '#a7b3a5', 26 | 27 | white: '#fff', 28 | black: '#000', 29 | 30 | siOrangeDark: '#b7620b', 31 | siOrangeLite: '#d18b1f', 32 | siYellow: '#f9e075', 33 | siWhiteWhite: '#fefefe', 34 | siWhiteF1: '#f1f1f1', 35 | siWhite: '#d9d9d9', 36 | siBlack: '#363636', 37 | }; 38 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/components/common/nav1.bar.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | import {bindActionCreators} from 'redux'; 4 | 5 | import {appNavMenuAction} from '../../store/app/app.actions'; 6 | import AppColors from './app.colors'; 7 | 8 | let NavBarSty = { 9 | background: AppColors.siWhiteWhite, 10 | lineHeight: '3.2em', 11 | overflow: 'hidden', 12 | padding: '0px' 13 | }; 14 | 15 | let spanSty = { 16 | color: AppColors.siBlack, 17 | cursor: 'pointer', 18 | fontFamily: "'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', 'sans-serif'", 19 | fontSize: '1.5em', 20 | fontWeight: '500', 21 | display: 'inline-block', 22 | WebkitTransform: 'scale(1.5,1)', 23 | MozTransform: 'scale(1.5,1)', 24 | MsTransform: 'scale(1.5,1)', 25 | OTransform: 'scale(1.5,1)', 26 | transform: 'scale(1.5,1)' 27 | }; 28 | 29 | const sinetImgSty = { 30 | display: 'block', 31 | height: '40px', 32 | margin: 'auto 10px', 33 | width: '105px' 34 | }; 35 | 36 | const spanSpacerSty = {padding: '0 3em'}; 37 | 38 | const NavBar = props => { 39 | const onMouseEnter = event => { 40 | if (props.navEnter) props.navEnter(event.target.id); 41 | }; 42 | const onMouseLeave = event => { 43 | if (props.navLeave) props.navLeave(event.target.id); 44 | }; 45 | const navClick = event => { 46 | props.appNavMenuAction(event.target.id); 47 | if (props.navEnter) props.navEnter(''); 48 | }; 49 | let SelectedSty = Object.assign({}, spanSty); 50 | SelectedSty.color = AppColors.siOrangeLite; 51 | 52 | let dashboardSty = props.fromPage === 'dashboard' ? SelectedSty : Object.assign({}, spanSty); 53 | let hideMapPageSty = props.fromPage === 'hideMapPage' ? SelectedSty : Object.assign({}, spanSty); 54 | 55 | return ( 56 | 79 | ); 80 | }; 81 | 82 | function mapStateToProps(store) { 83 | return {appState: store.appState}; 84 | } 85 | 86 | function mapDispatchToProps(dispatch) { 87 | return bindActionCreators({appNavMenuAction}, dispatch); 88 | } 89 | 90 | export default connect(mapStateToProps, mapDispatchToProps)(NavBar); 91 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/components/dashboard/dashboard.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import MapCtrl from './map.ctrl'; 4 | 5 | const DashboardPageSty = { 6 | border: 'solid 1px darkslategrey', 7 | height: 'calc(100% - 2px)', 8 | overflow: 'hidden', 9 | padding: '0px', 10 | width: '100%' 11 | }; 12 | 13 | export default class DashboardPage extends React.Component { 14 | render() { 15 | if (this.props.hide) return null; 16 | return ( 17 |
18 |
19 |
20 |
21 | 22 |
23 |
24 |
25 |
26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/components/dashboard/map.ctrl.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | import {bindActionCreators} from 'redux'; 4 | 5 | import {mapStyle} from './mapStyle'; 6 | 7 | import {mapChangeCenterAction, mapChangeZoomAction, mapInitializedAction} from '../../store/map/map.actions'; 8 | 9 | const GoogleMapsPageSty = { 10 | border: 'solid 1px darkslategrey', 11 | height: '100%', 12 | overflow: 'hidden', 13 | padding: '0px', 14 | width: '100%' 15 | }; 16 | 17 | const MapSty = { 18 | marginLeft: 'auto', 19 | marginRight: 'auto', 20 | width: 'auto' 21 | }; 22 | 23 | function loadJS(src) { 24 | var ref = window.document.getElementsByTagName('script')[0]; 25 | var script = window.document.createElement('script'); 26 | script.src = src; 27 | script.async = true; 28 | ref.parentNode.insertBefore(script, ref); 29 | } 30 | 31 | class GoogleMapsPage extends React.Component { 32 | state = {mapStyle: MapSty}; 33 | static map; 34 | static mapRef; 35 | markers = []; 36 | componentDidMount() { 37 | window.initMap = this.initMap; 38 | if (typeof google !== 'undefined') { 39 | google.maps = null; 40 | } 41 | loadJS('https://maps.googleapis.com/maps/api/js?key=AIzaSyDcsh25a_J-Plt-TjiPNXDvZ-qMnuzt3vc&callback=initMap'); 42 | } 43 | componentWillReceiveProps(nextProps) { 44 | if (!this.props.hide && nextProps.markers.length > this.props.markers.length) { 45 | this.setMarkers(nextProps.markers); 46 | } 47 | } 48 | setMarkers = newMarkers => { 49 | let _this = this; 50 | for (let i = 0; i < newMarkers.length; i++) { 51 | let newMarker = new google.maps.Marker({ 52 | position: newMarkers[i].position, 53 | map: _this.map 54 | }); 55 | _this.markers.push(newMarker); 56 | } 57 | }; 58 | initMap = () => { 59 | let _this = this; 60 | this.map = new google.maps.Map(this.mapRef, { 61 | center: this.props.mapState.mapCenter, 62 | zoom: this.props.mapState.mapZoom, 63 | styles: mapStyle, 64 | mapTypeId: 'hybrid', 65 | gestureHandling: 'cooperative' 66 | }); 67 | this.map.addListener('zoom_changed', function() { 68 | _this.props.mapChangeZoomAction(_this.map.getZoom()); 69 | }); 70 | this.map.addListener('center_changed', function() { 71 | const mapCenter = _this.map.getCenter(); 72 | _this.props.mapChangeCenterAction({lat: mapCenter.lat(), lng: mapCenter.lng()}); 73 | }); 74 | if (this.props.markers.length) this.setMarkers(this.props.markers); 75 | }; 76 | 77 | setMapRef = ref => { 78 | this.mapRef = ref; 79 | if (!this.state.mapStyle.height) { 80 | let msty = Object.assign({}, MapSty); 81 | msty.height = (window.innerHeight - 50) * 0.6 + 'px'; 82 | msty.width = window.innerWidth * 0.7 + 'px'; 83 | this.setState({mapStyle: msty}); 84 | } 85 | }; 86 | render() { 87 | return ( 88 |
89 |
this.setMapRef(ref)} style={this.state.mapStyle} /> 90 |
91 | ); 92 | } 93 | } 94 | 95 | function mapStateToProps(store) { 96 | return {mapState: store.mapState}; 97 | } 98 | 99 | function mapDispatchToProps(dispatch) { 100 | return bindActionCreators({mapChangeCenterAction, mapChangeZoomAction, mapInitializedAction}, dispatch); 101 | } 102 | 103 | export default connect(mapStateToProps, mapDispatchToProps)(GoogleMapsPage); 104 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/components/dashboard/mapStyle.js: -------------------------------------------------------------------------------- 1 | export const mapStyle = [ 2 | {elementType: 'geometry', stylers: [{color: '#eeffee'}]}, 3 | {elementType: 'labels.text.stroke', stylers: [{color: '#242f3e'}]}, 4 | {elementType: 'labels.text.fill', stylers: [{color: '#746855'}]}, 5 | { 6 | featureType: 'administrative.locality', 7 | elementType: 'labels.text.fill', 8 | stylers: [{color: '#d59563'}] 9 | }, 10 | { 11 | featureType: 'poi', 12 | elementType: 'labels.text.fill', 13 | stylers: [{color: '#d59563'}] 14 | }, 15 | { 16 | featureType: 'poi.park', 17 | elementType: 'geometry', 18 | stylers: [{color: '#263c3f'}] 19 | }, 20 | { 21 | featureType: 'poi.park', 22 | elementType: 'labels.text.fill', 23 | stylers: [{color: '#6b9a76'}] 24 | }, 25 | { 26 | featureType: 'road', 27 | elementType: 'geometry', 28 | stylers: [{color: '#38414e'}] 29 | }, 30 | { 31 | featureType: 'road', 32 | elementType: 'geometry.stroke', 33 | stylers: [{color: '#212a37'}] 34 | }, 35 | { 36 | featureType: 'road', 37 | elementType: 'labels.text.fill', 38 | stylers: [{color: '#9ca5b3'}] 39 | }, 40 | { 41 | featureType: 'road.highway', 42 | elementType: 'geometry', 43 | stylers: [{color: '#746855'}] 44 | }, 45 | { 46 | featureType: 'road.highway', 47 | elementType: 'geometry.stroke', 48 | stylers: [{color: '#1f2835'}] 49 | }, 50 | { 51 | featureType: 'road.highway', 52 | elementType: 'labels.text.fill', 53 | stylers: [{color: '#f3d19c'}] 54 | }, 55 | { 56 | featureType: 'transit', 57 | elementType: 'geometry', 58 | stylers: [{color: '#2f3948'}] 59 | }, 60 | { 61 | featureType: 'transit.station', 62 | elementType: 'labels.text.fill', 63 | stylers: [{color: '#d59563'}] 64 | }, 65 | { 66 | featureType: 'water', 67 | elementType: 'geometry', 68 | stylers: [{color: '#17263c'}] 69 | }, 70 | { 71 | featureType: 'water', 72 | elementType: 'labels.text.fill', 73 | stylers: [{color: '#515c6d'}] 74 | }, 75 | { 76 | featureType: 'water', 77 | elementType: 'labels.text.stroke', 78 | stylers: [{color: '#17263c'}] 79 | } 80 | ]; 81 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/css/index.css: -------------------------------------------------------------------------------- 1 | .editor :global(.public-DraftEditor-content) { 2 | max-height: 8em; 3 | overflow: auto; 4 | } 5 | 6 | .bodyStyle { 7 | background-color: ##fefefe; 8 | color: #363636; 9 | display: block; 10 | height: 100vh; 11 | overflow-x: hidden; 12 | overflow-y: hidden; 13 | width: 100%; 14 | } 15 | 16 | .Title {font-size: 1.3em;} 17 | 18 | .content { 19 | height: 100%; 20 | overflow: hidden; 21 | padding: 0; 22 | } 23 | 24 | * { outline: none; } 25 | 26 | .a{display:block} 27 | iframe{border-width:0} 28 | 29 | .FlexBox { 30 | display: -webkit-box; 31 | display: -moz-box; 32 | display: -ms-flexbox; 33 | display: flex; 34 | } 35 | 36 | .FlexBoxJustAround { 37 | display: -webkit-box; 38 | display: -moz-box; 39 | display: -ms-flexbox; 40 | display: flex; 41 | justify-content: space-around; 42 | } 43 | 44 | .FlexBoxJustAroundWrap { 45 | display: -webkit-box; 46 | display: -moz-box; 47 | display: -ms-flexbox; 48 | display: flex; 49 | justify-content: space-around; 50 | flex-wrap: wrap; 51 | } 52 | 53 | .FlexBoxJustBetween { 54 | display: -webkit-box; 55 | display: -moz-box; 56 | display: -ms-flexbox; 57 | display: flex; 58 | justify-content: space-between; 59 | } 60 | 61 | .FlexBoxWrap { 62 | display: -webkit-box; 63 | display: -moz-box; 64 | display: -ms-flexbox; 65 | display: flex; 66 | flex-wrap: wrap; 67 | } 68 | 69 | .FlexJustify { 70 | -webkit-box-pack: justify; 71 | -moz-box-pack: justify; 72 | -ms-box-pack: justify; 73 | justify-content: space-between; 74 | } 75 | 76 | .FlexBoxStretch { 77 | display: -webkit-box; 78 | display: -moz-box; 79 | display: -ms-flexbox; 80 | display: flex; 81 | align-content: stretch; 82 | } 83 | 84 | .FlexItem { 85 | flex-grow: 1; 86 | } 87 | 88 | .HighZ {z-index: 200;} 89 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.15/GoogleMaps/ui-src/img/favicon.ico -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GoogleMaps 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/store/App.Store.js: -------------------------------------------------------------------------------- 1 | import {createStore, combineReducers, applyMiddleware} from 'redux'; 2 | import logger from 'redux-logger'; 3 | 4 | import appState from './app/app.Reducer'; 5 | import mapState from './map/map.Reducer'; 6 | 7 | const reducer = combineReducers({appState, mapState}); 8 | let middleware = []; 9 | 10 | const useLogger = 0; 11 | if (useLogger) middleware.push(logger); 12 | 13 | const store = createStore(reducer, applyMiddleware(...middleware)); 14 | 15 | export default store; 16 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/store/app/app.actions.js: -------------------------------------------------------------------------------- 1 | 2 | export function appNavMenuAction(newPage) { 3 | return {type: 'AppNavMenuAction', newPage}; 4 | } 5 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/store/app/app.reducer.js: -------------------------------------------------------------------------------- 1 | const pages = ['dashboard']; 2 | const initialAppState = { 3 | currentPage: pages[0], 4 | }; 5 | 6 | export default function handleActions(state = initialAppState, action) { 7 | let _appState = Object.assign({}, state); 8 | switch (action.type) { 9 | case 'AppNavMenuAction': 10 | _appState.currentPage = action.newPage; 11 | return _appState; 12 | default: 13 | return state; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/store/map/map.actions.js: -------------------------------------------------------------------------------- 1 | 2 | export function mapChangeZoomAction(newZoom) { 3 | return {type: 'MapChangeZoomAction', newZoom}; 4 | } 5 | 6 | export function mapChangeCenterAction(newCenter) { 7 | return {type: 'MapChangeCenterAction', newCenter}; 8 | } 9 | 10 | export function mapInitializedAction() { 11 | return {type: 'MapInitializedAction'}; 12 | } 13 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/ui-src/store/map/map.reducer.js: -------------------------------------------------------------------------------- 1 | const initialMapState = { 2 | mapZoom: 3, 3 | mapCenter: {lat: 38.0000, lng: -97.0000}, 4 | mapInitialized: false 5 | }; 6 | 7 | export default function handleActions(state = initialMapState, action) { 8 | let _mapState = Object.assign({}, state); 9 | switch (action.type) { 10 | case 'MapChangeZoomAction': 11 | _mapState.mapZoom = action.newZoom; 12 | return _mapState; 13 | case 'MapChangeCenterAction': 14 | _mapState.mapCenter = action.newCenter; 15 | return _mapState; 16 | case 'MapInitializedAction': 17 | _mapState.mapInitialized = true; 18 | return _mapState; 19 | default: 20 | return state; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 3 | const webpack = require('webpack'); 4 | const configJson = require('./webpack.config.json'); 5 | 6 | module.exports = (env) => { 7 | 8 | const noMinimize = env.noMinimize; 9 | var plugins = []; 10 | 11 | plugins.push(new ExtractTextPlugin({filename: 'app.css', allChunks: true})); 12 | plugins.push(new webpack.optimize.CommonsChunkPlugin({name: 'lib'})); 13 | if (noMinimize) { 14 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('development')}})); 15 | } else { 16 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('production')}})); 17 | plugins.push(new webpack.optimize.UglifyJsPlugin({compress: {warnings: false, pure_funcs: ['console.log']},})); 18 | } 19 | 20 | const ROOT_PATH = path.resolve(__dirname); 21 | const SRC_PATH = path.resolve(ROOT_PATH, './ui-src'); 22 | const DIST_PATH = path.resolve(ROOT_PATH, './ui-dist'); 23 | 24 | 25 | return { 26 | context: SRC_PATH, 27 | entry: { 28 | app: './app.jsx', 29 | lib: configJson.lib 30 | }, 31 | 32 | output: { 33 | path: DIST_PATH, 34 | filename: '[name].js' 35 | }, 36 | 37 | module: { 38 | rules: [ 39 | { 40 | test: /\.jsx?$/, 41 | loader: 'babel-loader', 42 | query: {presets:['es2015', 'react', 'stage-0']}, 43 | exclude: /(node_modules)/, 44 | }, 45 | { 46 | test: /\.css$/, 47 | use: ExtractTextPlugin.extract({ 48 | fallback: 'style-loader', 49 | use: 'css-loader' 50 | }) 51 | }, 52 | { 53 | test: /\.(png|jpg|ico|gif)$/, 54 | loader: 'file-loader?name=img/[name].[ext]' 55 | }, 56 | { 57 | test: /\.(html|pdf)$/, 58 | loader: 'file-loader?name=[name].[ext]' 59 | } 60 | ] 61 | }, 62 | plugins, 63 | resolve: { 64 | extensions: ['.js', '.jsx'], 65 | modules: ['node_modules'] 66 | } 67 | }; 68 | }; 69 | -------------------------------------------------------------------------------- /React.15/GoogleMaps/webpack.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": [ 3 | "react", 4 | "react-dom", 5 | "react-redux", 6 | "redux", 7 | "redux-logger" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/README.md: -------------------------------------------------------------------------------- 1 | # ReactPatterns ReduxElectron 2 | 3 | A basic demonstration of redux with Electron. This would be the starting point for a simple data handling app. 4 | The 15 version uses more es6 and refines the reflux usage a bit. 5 | 6 | # Getting started 7 | 8 | cd into the root directory of the project. If the first time "npm install". "npm run ww" for webpack with watch. 9 | "npm run nw" for webpack no watch. "npm start" to start the node server. "localhost:3500" in the browser. 10 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "winProjectRoot": "K:/Projects/ReactPatterns/React.15.Webpack/ReduxElectron" 3 | } 4 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/data/basic.json: -------------------------------------------------------------------------------- 1 | { 2 | "Project": "Redux with Electron", 3 | "React version": "15", 4 | "currentDateTime": "2/20/2017, 1:10:55 PM" 5 | } -------------------------------------------------------------------------------- /React.15/ReduxElectron/js/mainipc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | 5 | const rootDataPath = './data'; 6 | 7 | const getData = function(event, doneCallBack) { 8 | const filePath = rootDataPath + '/basic.json'; 9 | const jsonReadCallBack = function(err, data){ 10 | if (err) doneCallBack('Data readFile error ' + filePath); 11 | else { 12 | const jsonData = JSON.parse(data.toString()); 13 | doneCallBack(event, jsonData); 14 | } 15 | }; 16 | fs.readFile(filePath, jsonReadCallBack); 17 | }; 18 | 19 | const setData = function(data, event, doneCallBack) { 20 | const filePath = rootDataPath + '/basic.json'; 21 | const writeFileCallBack = function (err) { 22 | if (err) console.log('error saving Data.json file '); 23 | else doneCallBack(event); 24 | }; 25 | fs.writeFile(filePath, JSON.stringify(data, null, 2), writeFileCallBack); 26 | }; 27 | 28 | module.exports = function(socket) { 29 | console.log('mainipc called.'); 30 | 31 | const getDataDone = function(event, data){ event.sender.send('server:GotData', data); }; 32 | const onGetData = function(event){ getData(event, getDataDone); }; 33 | socket.on('client:GetData', onGetData); 34 | 35 | const setDataDone = function(event){ event.sender.send('server:SetDataDone'); }; 36 | const onSetData = function(event, data){ setData(data, event, setDataDone); }; 37 | socket.on('client:SetData', onSetData); 38 | }; 39 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const electron = require('electron'); 4 | const {app} = electron; 5 | const {BrowserWindow} = electron; 6 | var fs = require('fs'); 7 | 8 | const useDevTools = 0; 9 | 10 | const {ipcMain} = electron; 11 | require('./js/mainipc')(ipcMain); 12 | 13 | var mainWindow = null; 14 | 15 | app.on('window-all-closed', function() { app.quit(); }); 16 | 17 | app.on('ready', function() { 18 | mainWindow = new BrowserWindow({width: 800, height: 600}); 19 | 20 | var windowStatePath = './windowstate.json'; 21 | var windowState = {}; 22 | if (useDevTools) mainWindow.openDevTools(); 23 | var jsonReadCallBack = function(err, data){ 24 | if (err) console.log('error opening windowstate'); 25 | else { 26 | windowState = JSON.parse(data.toString()); 27 | mainWindow.setSize(windowState.size[0], windowState.size[1]); 28 | mainWindow.setPosition(windowState.position[0], windowState.position[1]); 29 | } 30 | }; 31 | fs.readFile(windowStatePath, jsonReadCallBack); 32 | 33 | mainWindow.loadURL('file://' + __dirname + '/ui-dist/index.html'); 34 | mainWindow.on('close', function() { 35 | windowState.size = mainWindow.getSize(); 36 | windowState.position = mainWindow.getPosition(); 37 | var writeFileCallBack = function (err) { 38 | if (err) console.log('error saving windowstate.json file '); 39 | mainWindow = null; 40 | }; 41 | fs.writeFile(windowStatePath, JSON.stringify(windowState, null, 2), writeFileCallBack); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReactPatterns.15-ReduxElectron", 3 | "version": "1.0.0", 4 | "main": "main.js", 5 | "description": "A collection of simple react projects providing reusable components, startup and test examples.", 6 | "license": "MIT", 7 | "author": { 8 | "name": "Janaka Stevens", 9 | "email": "jmstevens@calitek.com" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/calitek/ReactPatterns.git" 14 | }, 15 | "scripts": { 16 | "start": "electron .", 17 | "ww": "webpack --progress --profile --colors --env.noMinimize --watch", 18 | "nw": "webpack --progress --profile --colors --env.noMinimize" 19 | }, 20 | "dependencies": { 21 | "electron": "*" 22 | }, 23 | "devDependencies": { 24 | "react": "^15.4.0", 25 | "react-dom": "^15.4.0", 26 | "react-redux": "latest", 27 | "redux": "latest", 28 | 29 | "babel-core": "latest", 30 | "babel-loader": "^6.1.0", 31 | "babel-preset-es2015": "latest", 32 | "babel-preset-react": "latest", 33 | "babel-preset-stage-0": "latest", 34 | "css-loader": "latest", 35 | "extract-text-webpack-plugin": "^2.0.0-rc.3", 36 | "file-loader": "latest", 37 | "style-loader": "^0.13.1", 38 | "webpack": "latest" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/ui-src/app.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import './index.html'; 4 | import './css/index.css'; 5 | import './img/favicon.ico'; 6 | 7 | import React from 'react'; 8 | import ReactDom from 'react-dom'; 9 | import {Provider} from 'react-redux'; 10 | 11 | import AppCtrl from './components/app.ctrl'; 12 | import AppStore from './store/App.Store'; 13 | 14 | window.ReactDom = ReactDom; 15 | 16 | ReactDom.render( 17 | , 18 | document.getElementById('react') 19 | ); 20 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/ui-src/components/app.ctrl.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | 4 | import AppNotes from './app.notes'; 5 | 6 | let AppCtrlSty = { 7 | height: '100%', 8 | padding: '0 10px 0 0' 9 | }; 10 | 11 | const AppCtrl = (props) => { 12 | let data1 = props.Data1; 13 | return ( 14 |
15 | React Version: {data1['React version']}

16 | Project: {data1.Project}

17 | Current date/time: {data1.currentDateTime}

18 | 19 |
20 | ); 21 | }; 22 | 23 | function mapStateToProps(store) { 24 | return {Data1: store.data1}; 25 | } 26 | 27 | export default connect(mapStateToProps, null)(AppCtrl); 28 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/ui-src/components/app.notes.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | let AppNotesSty = { 4 | marginLeft: 'auto', 5 | marginRight: 'auto', 6 | marginTop: '30px', 7 | maxWidth: '500px', 8 | textIndent: '20px' 9 | }; 10 | 11 | let textSty = { 12 | color: '#000', 13 | fontSize: '1.0em', 14 | textAlign: 'left' 15 | }; 16 | 17 | let btnDivSty = {textAlign: 'center'}; 18 | 19 | let standardBtnSty = { 20 | backgroundColor: '#9a6', 21 | borderBottomColor: '#cea', 22 | borderLeftColor: '#93a363', 23 | borderRightColor: '#cea', 24 | borderTopColor: '#93a363', 25 | borderRadius: '6px', 26 | color: '#eeffee', 27 | cursor: 'pointer', 28 | lineHeight: '100%', 29 | outline: 'none', 30 | verticalAlign: 'middle', 31 | whiteSpace: 'nowrap' 32 | }; 33 | 34 | let p1Text = ` 35 | `; 36 | 37 | export default class AppNotes extends React.Component { 38 | state = {show: true}; 39 | onClick = () => { this.setState({show: !this.state.show}); }; 40 | render() { 41 | let showNotes = this.state.show; 42 | let btnText = showNotes ? 'Hide notes' : 'Show notes'; 43 | let notesDivSty = showNotes ? {display: 'block'} : {display: 'none'}; 44 | return ( 45 |
46 |
47 | 48 |
49 |
50 |

{p1Text}

51 |
52 |
53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/ui-src/css/index.css: -------------------------------------------------------------------------------- 1 | .bodyStyle { 2 | background-color: #00303f; 3 | color: #eae3ea; 4 | display: block; 5 | overflow: hidden; 6 | width: 100%; 7 | } 8 | 9 | .header { 10 | height: 30px; 11 | margin: 0; 12 | padding: 10px 0; 13 | text-align: center; 14 | } 15 | 16 | .Title {font-size: 1.3em;} 17 | 18 | .content { 19 | height: calc(100% - 52px); 20 | max-width: 1366px; 21 | margin-left: auto; 22 | margin-right: auto; 23 | padding: 0 5px; 24 | } 25 | 26 | * { outline: none; } 27 | 28 | .a{display:block} 29 | 30 | .FlexBox { 31 | display: -webkit-box; 32 | display: -moz-box; 33 | display: -ms-flexbox; 34 | display: flex; 35 | } 36 | 37 | .FlexBoxJustAround { 38 | display: -webkit-box; 39 | display: -moz-box; 40 | display: -ms-flexbox; 41 | display: flex; 42 | justify-content: space-around; 43 | } 44 | 45 | .FlexBoxJustBetween { 46 | display: -webkit-box; 47 | display: -moz-box; 48 | display: -ms-flexbox; 49 | display: flex; 50 | justify-content: space-between; 51 | } 52 | 53 | .FlexBoxWrap { 54 | display: -webkit-box; 55 | display: -moz-box; 56 | display: -ms-flexbox; 57 | display: flex; 58 | flex-wrap: wrap; 59 | } 60 | 61 | .FlexJustify { 62 | -webkit-box-pack: justify; 63 | justify-content: space-between; 64 | } 65 | 66 | .FlexBoxStretch { 67 | display: -webkit-box; 68 | display: -moz-box; 69 | display: -ms-flexbox; 70 | display: flex; 71 | align-content: stretch; 72 | } 73 | 74 | .FlexItem { 75 | flex-grow: 1; 76 | } 77 | 78 | .HighZ {z-index: 200;} 79 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/ui-src/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.15/ReduxElectron/ui-src/img/favicon.ico -------------------------------------------------------------------------------- /React.15/ReduxElectron/ui-src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ReactPatterns-ReduxElectron 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | ReactPatterns-ReduxElectron 16 |
17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/ui-src/store/Actions.js: -------------------------------------------------------------------------------- 1 | export function apiGetData() { return {type: 'ApiGetData'}; } 2 | 3 | export function apiGotData(data) { return {type: 'ApiGotData', data}; } 4 | 5 | export function apiSetData(data) { return {type: 'ApiSetData', data}; } 6 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/ui-src/store/App.Store.js: -------------------------------------------------------------------------------- 1 | import {createStore, applyMiddleware} from 'redux'; 2 | import {apiSetData} from './Actions'; 3 | import startWs, {wsMiddleware} from './ipc.api'; 4 | 5 | function handleData(state = {data1: {}}, action) { 6 | switch (action.type) { 7 | case 'ApiGotData': return Object.assign({}, state, {data1: action.data}); 8 | default: return state; 9 | } 10 | } 11 | 12 | const store = createStore(handleData, applyMiddleware(wsMiddleware)); 13 | 14 | startWs(store); 15 | 16 | const newData = { 17 | 'React version': '15', 18 | 'Project': 'Redux with Electron', 19 | 'currentDateTime': new Date().toLocaleString() 20 | }; 21 | 22 | store.dispatch(apiSetData(newData)); 23 | 24 | export default store; 25 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/ui-src/store/ipc.api.js: -------------------------------------------------------------------------------- 1 | import * as Actions from './Actions'; 2 | 3 | export function wsMiddleware() { 4 | return (next) => (action) => { 5 | if (ipc && action.type === 'ApiGetData') { 6 | ipc.send('client:GetData', {}); 7 | } else if (ipc && action.type === 'ApiSetData') { 8 | ipc.send('client:SetData', action.data); 9 | } 10 | 11 | return next(action); 12 | }; 13 | } 14 | 15 | export default function (store) { 16 | 17 | ipc.on('server:GotData', (event, data) => { 18 | store.dispatch(Actions.apiGotData(data)); 19 | }); 20 | 21 | ipc.on('server:SetDataDone', () => { 22 | store.dispatch(Actions.apiGetData()); 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 3 | const webpack = require('webpack'); 4 | const configJson = require('./webpack.config.json'); 5 | 6 | module.exports = (env) => { 7 | 8 | const noMinimize = env.noMinimize; 9 | var plugins = []; 10 | 11 | plugins.push(new ExtractTextPlugin({filename: 'app.css', allChunks: true})); 12 | plugins.push(new webpack.optimize.CommonsChunkPlugin({name: 'lib'})); 13 | if (noMinimize) { 14 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('development')}})); 15 | } else { 16 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('production')}})); 17 | plugins.push(new webpack.optimize.UglifyJsPlugin({include: /lib\.js/, minimize: true})); 18 | } 19 | 20 | const ROOT_PATH = path.resolve(__dirname); 21 | const SRC_PATH = path.resolve(ROOT_PATH, './ui-src'); 22 | const DIST_PATH = path.resolve(ROOT_PATH, './ui-dist'); 23 | 24 | 25 | return { 26 | context: SRC_PATH, 27 | entry: { 28 | app: './app.jsx', 29 | lib: configJson.lib 30 | }, 31 | 32 | output: { 33 | path: DIST_PATH, 34 | filename: '[name].js' 35 | }, 36 | 37 | module: { 38 | rules: [ 39 | { 40 | test: /\.jsx?$/, 41 | loader: 'babel-loader', 42 | query: {presets:['es2015', 'react', 'stage-0']}, 43 | exclude: /(node_modules)/, 44 | }, 45 | { 46 | test: /\.css$/, 47 | use: ExtractTextPlugin.extract({ 48 | fallback: 'style-loader', 49 | use: 'css-loader' 50 | }) 51 | }, 52 | { 53 | test: /\.(png|jpg|ico|gif)$/, 54 | loader: 'file-loader?name=img/[name].[ext]' 55 | }, 56 | { 57 | test: /\.(html)$/, 58 | loader: 'file-loader?name=[name].[ext]' 59 | } 60 | ] 61 | }, 62 | plugins, 63 | resolve: { 64 | extensions: ['.js', '.jsx'], 65 | modules: ['node_modules'] 66 | } 67 | }; 68 | }; 69 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/webpack.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": [ 3 | "react", 4 | "react-dom", 5 | "react-redux", 6 | "redux" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /React.15/ReduxElectron/windowstate.json: -------------------------------------------------------------------------------- 1 | { 2 | "size": [ 3 | 1365, 4 | 1335 5 | ], 6 | "position": [ 7 | 1943, 8 | 23 9 | ] 10 | } -------------------------------------------------------------------------------- /React.15/ReduxFetch/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react", "stage-0"] 3 | } -------------------------------------------------------------------------------- /React.15/ReduxFetch/README.md: -------------------------------------------------------------------------------- 1 | # ReactPatterns ReduxFetch 2 | 3 | A basic demonstration of Redux with fetch polyfill. This would be the starting point for a simple data handling app. 4 | The 15 version uses more es6 and refines the reflux usage a bit. 5 | 6 | # Getting started 7 | 8 | cd into the root directory of the project. If the first time "npm install". "npm run ww" for webpack with watch. 9 | "npm run nw" for webpack no watch. "npm start" to start the node server. "localhost:3500" in the browser. 10 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/__tests__/.setup.js: -------------------------------------------------------------------------------- 1 | require('babel-register')(); 2 | 3 | var jsdom = require('jsdom').jsdom; 4 | 5 | var exposedProperties = ['window', 'navigator', 'document']; 6 | 7 | global.document = jsdom(''); 8 | global.window = document.defaultView; 9 | Object.keys(document.defaultView).forEach((property) => { 10 | if (typeof global[property] === 'undefined') { 11 | exposedProperties.push(property); 12 | global[property] = document.defaultView[property]; 13 | } 14 | }); 15 | 16 | global.navigator = { 17 | userAgent: 'node.js' 18 | }; 19 | 20 | documentRef = document; 21 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/__tests__/app.ctrl.test.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | import {Provider} from 'react-redux'; 5 | import {mount} from 'enzyme'; 6 | import {expect} from 'chai'; 7 | import configureMockStore from 'redux-mock-store'; 8 | 9 | import AppCtrl from '../ui-src/components/app.ctrl'; 10 | 11 | const mockStore = configureMockStore(); 12 | 13 | describe('mount()', () => { 14 | let store = mockStore({data1: {}}); 15 | const wrapper = mount( 16 | 17 | 18 | 19 | ); 20 | expect(wrapper.find(AppCtrl).length).to.equal(1); 21 | const container = wrapper.find(AppCtrl); 22 | it('checks div count', () => { 23 | expect(container.find('div').length).to.equal(4); 24 | }); 25 | it('checks br count', () => { 26 | expect(container.find('br').length).to.equal(6); 27 | }); 28 | it('checks props.Data1', () => { 29 | expect(container.props('Data1')).to.be.empty; 30 | }); 31 | it('checks text contains', () => { 32 | expect(container.text()).to.contain('React Version'); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/__tests__/server.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import chai, {expect} from 'chai'; 4 | import chaiHttp from 'chai-http'; 5 | // import sinon from 'sinon'; 6 | 7 | chai.use(chaiHttp); 8 | 9 | describe('server test with chai-http', () => { 10 | it('checks get /', () => { 11 | chai.request('../js/server').get('/') 12 | .end(function (err, res) { 13 | expect(err).to.be.null; 14 | expect(res).to.have.status(200); 15 | }); 16 | }); 17 | it('checks get /routes/getData', () => { 18 | chai.request('../js/server').get('/routes/getData') 19 | .end(function (err, res) { 20 | expect(err).to.be.null; 21 | expect(res).to.have.status(200); 22 | expect(res).to.have.header('content-type', 'application/json; charset=utf-8'); 23 | expect(res).to.have.header('content-length', '93'); 24 | expect(res).to.be.json; 25 | console.log('res: ', res.headers); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/cert.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIB0TCCAToCAQAwejETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNVmFs 3 | bGV5IENlbnRlcjEQMA4GA1UEChMHQ2FsaXRlazEVMBMGA1UEAxMMSk1hcmtTdGV2 4 | ZW5zMSIwIAYJKoZIhvcNAQkBFhNvcGVuc3NsQGNhbGl0ZWsuY29tMIGfMA0GCSqG 5 | SIb3DQEBAQUAA4GNADCBiQKBgQCmxGXgGN9A+Op0AvzWFr8vWcGaXlRR5bA2Z6GU 6 | 0baHJoKRjaSX6vCxuiI+OoFk9R1yXIuFtuPGb+0Vi36hVabkn4yR9SfagueTdN+r 7 | KIi28q5bDV9ZF+D/nTsXKctDnmbMAtuLA4xe91RBLa7zSk5FA3Kq1a1OWjhUKmFB 8 | /dDOBQIDAQABoBcwFQYJKoZIhvcNAQkHMQgTBmZyaXNjbzANBgkqhkiG9w0BAQUF 9 | AAOBgQA8xSFREgQtMtLOlIdSCjbPuEzxQMJsPLNcKQq4Uov446VWA3x3mDt7KKKT 10 | MSs1a6zyzj3N1Rjz6+nG/9tHHpeZCD/bPUwg1q2E7MFtOgFW/v2h/ItIzfF5Ovrb 11 | Jmhxalt1Xn1vMRYRIMJ0aqlIKYRZLerUttxTlECDzbWsEBY+Jw== 12 | -----END CERTIFICATE REQUEST----- 13 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/certificate.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICazCCAdQCCQCvtmRxHlk/FTANBgkqhkiG9w0BAQUFADB6MRMwEQYDVQQIEwpD 3 | YWxpZm9ybmlhMRYwFAYDVQQHEw1WYWxsZXkgQ2VudGVyMRAwDgYDVQQKEwdDYWxp 4 | dGVrMRUwEwYDVQQDEwxKTWFya1N0ZXZlbnMxIjAgBgkqhkiG9w0BCQEWE29wZW5z 5 | c2xAY2FsaXRlay5jb20wHhcNMTYxMjI3MjI1NjU3WhcNMTcwMTI2MjI1NjU3WjB6 6 | MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1WYWxsZXkgQ2VudGVyMRAw 7 | DgYDVQQKEwdDYWxpdGVrMRUwEwYDVQQDEwxKTWFya1N0ZXZlbnMxIjAgBgkqhkiG 8 | 9w0BCQEWE29wZW5zc2xAY2FsaXRlay5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0A 9 | MIGJAoGBAKbEZeAY30D46nQC/NYWvy9ZwZpeVFHlsDZnoZTRtocmgpGNpJfq8LG6 10 | Ij46gWT1HXJci4W248Zv7RWLfqFVpuSfjJH1J9qC55N036soiLbyrlsNX1kX4P+d 11 | Oxcpy0OeZswC24sDjF73VEEtrvNKTkUDcqrVrU5aOFQqYUH90M4FAgMBAAEwDQYJ 12 | KoZIhvcNAQEFBQADgYEAOzaxEZFj74h1gaSFQXUHAwkFXcZSRy+9uES7a2csnKe4 13 | xn9s6Ym8HadPt0ANGFifNemcuPWQlxir1LG/Pb8ZTCiqbqobVK48J1n5+b4C6T8Q 14 | /H7WGb70AAcMUXa1H1H5HsDa96G6k31bGOHlkCjKdrVjwq//NDdB7thFrAkVNhk= 15 | -----END CERTIFICATE----- 16 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/data/basic.json: -------------------------------------------------------------------------------- 1 | { 2 | "React version": "15", 3 | "Project": "Redux with fetch polyfill", 4 | "currentDateTime": "2/17/2017, 11:40:41 AM" 5 | } -------------------------------------------------------------------------------- /React.15/ReduxFetch/js/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | const router = express.Router(); 5 | 6 | const getSetData = require('./routes/GetSetData'); 7 | 8 | router.get('/getData', function(req, res) { 9 | const getDataDone = function(data){ res.send(data); }; 10 | getSetData.getData(getDataDone); 11 | }); 12 | 13 | router.post('/setData', function(req, res) { 14 | const setDataDone = function(data){ res.send(data); }; 15 | getSetData.setData(req.body, setDataDone); 16 | }); 17 | 18 | module.exports = router; 19 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/js/routes/GetSetData.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | 5 | const rootDataPath = './data'; 6 | 7 | module.exports.getData = function(doneCallBack) { 8 | const filePath = rootDataPath + '/basic.json'; 9 | const jsonReadCallBack = function(err, data){ 10 | if (err) doneCallBack('Data readFile error ' + filePath); 11 | else { 12 | const jsonData = JSON.parse(data.toString()); 13 | doneCallBack(jsonData); 14 | } 15 | }; 16 | fs.readFile(filePath, jsonReadCallBack); 17 | }; 18 | 19 | module.exports.setData = function(data, doneCallBack) { 20 | const filePath = rootDataPath + '/basic.json'; 21 | const writeFileCallBack = function (err) { 22 | if (err) console.log('error saving Data.json file '); 23 | doneCallBack({setResponse: 'ok'}); 24 | }; 25 | fs.writeFile(filePath, JSON.stringify(data, null, 2), writeFileCallBack); 26 | }; 27 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/js/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bodyParser = require('body-parser'); 4 | const express = require('express'); 5 | const favicon = require('serve-favicon'); 6 | const https = require('https'); 7 | const http = require('http'); 8 | const fs = require('fs'); 9 | 10 | const path = require('path'); 11 | const port = Number(process.env.REDUXFETCHPORT || 3500); 12 | 13 | var options = { 14 | key: fs.readFileSync('./private.key'), 15 | cert: fs.readFileSync('./certificate.pem') 16 | }; 17 | const routes = require('./routes'); 18 | 19 | const app = express(); 20 | http.createServer(app).listen(port); 21 | https.createServer(options, app).listen(3600); 22 | 23 | app.use(bodyParser.json()); 24 | app.use(bodyParser.urlencoded({extended: false})); 25 | 26 | app.use('/', express.static('ui-dist')); 27 | app.use('/routes', routes); 28 | 29 | app.use(favicon(path.join(__dirname, '..', 'ui-dist', 'img', 'favicon.ico'))); 30 | app.get('/', function(req, res){ res.sendfile(__dirname + '/index.html', [], null); }); 31 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReactPatterns.15-ReduxFetch", 3 | "version": "1.0.0", 4 | "description": "A collection of simple react projects providing reusable components, startup and test examples.", 5 | "license": "MIT", 6 | "author": { 7 | "name": "Janaka Stevens", 8 | "email": "jmstevens@calitek.com" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/calitek/ReactPatterns.git" 13 | }, 14 | "scripts": { 15 | "start": "node js/server.js", 16 | "test": "mocha __tests__/.setup.js __tests__/**/*.test.js?", 17 | "testw": "npm test -- --watch", 18 | "ww": "webpack --progress --profile --colors --env.noMinimize --watch", 19 | "nw": "webpack --progress --profile --colors --env.noMinimize" 20 | }, 21 | "dependencies": { 22 | "body-parser": "latest", 23 | "express": "latest", 24 | "serve-favicon": "latest" 25 | }, 26 | "devDependencies": { 27 | "react": "^15.4.0", 28 | "react-dom": "^15.4.0", 29 | "react-redux": "latest", 30 | "redux": "latest", 31 | "redux-thunk": "latest", 32 | "whatwg-fetch": "latest", 33 | 34 | "babel-core": "latest", 35 | "babel-loader": "^6.1.0", 36 | "babel-preset-es2015": "latest", 37 | "babel-preset-react": "latest", 38 | "babel-preset-stage-0": "latest", 39 | "css-loader": "latest", 40 | "extract-text-webpack-plugin": "^2.0.0-rc.3", 41 | "file-loader": "latest", 42 | "style-loader": "^0.13.1", 43 | "webpack": "latest", 44 | 45 | "babel-register": "latest", 46 | "chai": "latest", 47 | "chai-http": "latest", 48 | "enzyme": "latest", 49 | "jsdom": "latest", 50 | "mocha": "latest", 51 | "react-addons-test-utils": "^15.4.0", 52 | "redux-mock-store": "latest", 53 | "sinon": "latest" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/private.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICWwIBAAKBgQCmxGXgGN9A+Op0AvzWFr8vWcGaXlRR5bA2Z6GU0baHJoKRjaSX 3 | 6vCxuiI+OoFk9R1yXIuFtuPGb+0Vi36hVabkn4yR9SfagueTdN+rKIi28q5bDV9Z 4 | F+D/nTsXKctDnmbMAtuLA4xe91RBLa7zSk5FA3Kq1a1OWjhUKmFB/dDOBQIDAQAB 5 | AoGAG22z/863cX0/OoN/SEsHeOc/U39uSOYJPHmA9vQjHEl2MjBkwOPQYLrnhOqk 6 | e5FhHX0hKYXyIqIoEWIXGrv2reGAqD0telMwpueCKYx+HfnwYELGookfCP4yjcYv 7 | rZEmvQ79/JVWhc4Sg1dHciEyIEI600bYLnl7l1RdFzVmLcECQQDcQzBXRO0/Iz65 8 | K6XfCT3qNV2SdDuzR9+G1hRRu2/uauO3PnzNfJwG48JXTYzyuSrRM6c/Er9uFht5 9 | UKK3CsY1AkEAwdM7Vfp/npAyn+P4ZiwHPv51ss3rNxqDEkvukVkBk4Y+2Km5apgC 10 | 3BobeQxpuR38YbhdKC39cEbG6DPCJ0WikQJAdrrlEPW/qVwXUHt9wxdZP6makfqD 11 | v+VLUYSOmWwfLvaBX2KYpa+472HQfXz5MFGuCez9B1vUwsO59ZAI1gBBzQJAaFff 12 | 3JRjOahlKIBgjBhtujLgh+alFuAV6bao8uRYneOqV5dfMwwslfMUESFmlPqYkL7g 13 | n63KfzQLBpw+jEfHkQJAItc+cyf7Xn2MyYT5kOoFVS94miUqCo/hRVrAB6acReHA 14 | CdycidnkJYkOlwRCl0D9ur1gBmYvuO+buTojI+Cb3g== 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/ui-src/app.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import './index.html'; 4 | import './css/index.css'; 5 | import './img/favicon.ico'; 6 | 7 | import React from 'react'; 8 | import ReactDom from 'react-dom'; 9 | import {Provider} from 'react-redux'; 10 | 11 | import AppCtrl from './components/app.ctrl'; 12 | import AppStore from './store/App.Store'; 13 | 14 | window.ReactDom = ReactDom; 15 | 16 | ReactDom.render( 17 | , 18 | document.getElementById('react') 19 | ); 20 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/ui-src/components/app.ctrl.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | 4 | import AppNotes from './app.notes'; 5 | 6 | let AppCtrlSty = { 7 | height: '100%', 8 | padding: '0 10px 0 0' 9 | }; 10 | 11 | function AppCtrl({Data1}) { 12 | let data1 = Data1; 13 | return ( 14 |
15 | React Version: {data1['React version']}

16 | Project: {data1.Project}

17 | Current date/time: {data1.currentDateTime}

18 | 19 |
20 | ); 21 | } 22 | 23 | function mapStateToProps(store) { 24 | return {Data1: store.data1}; 25 | } 26 | 27 | export default connect(mapStateToProps)(AppCtrl); 28 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/ui-src/components/app.notes.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import AppText from './app.text'; 4 | 5 | const AppNotesSty = { 6 | marginLeft: 'auto', 7 | marginRight: 'auto', 8 | marginTop: '30px', 9 | maxWidth: '500px', 10 | textIndent: '20px' 11 | }; 12 | 13 | const textSty = { 14 | color: '#FFF', 15 | fontSize: '1.0em', 16 | textAlign: 'left' 17 | }; 18 | 19 | const btnDivSty = {textAlign: 'center'}; 20 | 21 | const standardBtnSty = { 22 | backgroundColor: '#9a6', 23 | borderBottomColor: '#cea', 24 | borderLeftColor: '#93a363', 25 | borderRightColor: '#cea', 26 | borderTopColor: '#93a363', 27 | borderRadius: '6px', 28 | color: '#eeffee', 29 | cursor: 'pointer', 30 | lineHeight: '100%', 31 | outline: 'none', 32 | verticalAlign: 'middle', 33 | whiteSpace: 'nowrap' 34 | }; 35 | 36 | export default class AppNotes extends React.Component { 37 | state = {show: true}; 38 | onClick = () => { this.setState({show: !this.state.show}); }; 39 | render() { 40 | if (AppText.p1Text.trim().length === 0) return null; 41 | let showNotes = this.state.show; 42 | let btnText = showNotes ? 'Hide notes' : 'Show notes'; 43 | let notesDivSty = showNotes ? {display: 'block'} : {display: 'none'}; 44 | return ( 45 |
46 |
47 | 48 |
49 |
50 |

{AppText.p1Text}

51 |
52 |
53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/ui-src/components/app.text.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | p1Text: ` 3 | 4 | ` 5 | }; 6 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/ui-src/css/index.css: -------------------------------------------------------------------------------- 1 | .bodyStyle { 2 | background-color: #00303f; 3 | color: #eae3ea; 4 | display: block; 5 | overflow: hidden; 6 | width: 100%; 7 | } 8 | 9 | .header { 10 | height: 30px; 11 | margin: 0; 12 | padding: 10px 0; 13 | text-align: center; 14 | } 15 | 16 | .Title {font-size: 1.3em;} 17 | 18 | .content { 19 | height: calc(100% - 52px); 20 | max-width: 1366px; 21 | margin-left: auto; 22 | margin-right: auto; 23 | padding: 0 5px; 24 | } 25 | 26 | * { outline: none; } 27 | 28 | .a{display:block} 29 | 30 | .FlexBox { 31 | display: -webkit-box; 32 | display: -moz-box; 33 | display: -ms-flexbox; 34 | display: flex; 35 | } 36 | 37 | .FlexBoxJustAround { 38 | display: -webkit-box; 39 | display: -moz-box; 40 | display: -ms-flexbox; 41 | display: flex; 42 | justify-content: space-around; 43 | } 44 | 45 | .FlexBoxJustBetween { 46 | display: -webkit-box; 47 | display: -moz-box; 48 | display: -ms-flexbox; 49 | display: flex; 50 | justify-content: space-between; 51 | } 52 | 53 | .FlexBoxWrap { 54 | display: -webkit-box; 55 | display: -moz-box; 56 | display: -ms-flexbox; 57 | display: flex; 58 | flex-wrap: wrap; 59 | } 60 | 61 | .FlexJustify { 62 | -webkit-box-pack: justify; 63 | justify-content: space-between; 64 | } 65 | 66 | .FlexBoxStretch { 67 | display: -webkit-box; 68 | display: -moz-box; 69 | display: -ms-flexbox; 70 | display: flex; 71 | align-content: stretch; 72 | } 73 | 74 | .FlexItem { 75 | flex-grow: 1; 76 | } 77 | 78 | .HighZ {z-index: 200;} 79 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/ui-src/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.15/ReduxFetch/ui-src/img/favicon.ico -------------------------------------------------------------------------------- /React.15/ReduxFetch/ui-src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ReactPatterns-ReduxFetch 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | ReactPatterns-ReduxFetch 16 |
17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/ui-src/store/App.Store.js: -------------------------------------------------------------------------------- 1 | import {createStore, applyMiddleware} from 'redux'; 2 | import thunkMiddleware from 'redux-thunk'; 3 | import {apiSetData} from './api.Actions'; 4 | 5 | function handleData(state = {data1: {}}, action) { 6 | switch (action.type) { 7 | case 'GOT_DATA': return Object.assign({}, state, {data1: action.payload}); 8 | default: return state; 9 | } 10 | } 11 | 12 | const store = createStore(handleData, applyMiddleware(thunkMiddleware)); 13 | 14 | const newData = { 15 | 'React version': '15', 16 | 'Project': 'Redux with fetch polyfill', 17 | 'currentDateTime': new Date().toLocaleString() 18 | }; 19 | 20 | store.dispatch(apiSetData(newData)); 21 | 22 | export default store; 23 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/ui-src/store/api.Actions.js: -------------------------------------------------------------------------------- 1 | import 'whatwg-fetch'; 2 | 3 | let jsonHeader = {'Accept': 'application/json', 'Content-Type': 'application/json'}; 4 | 5 | export function apiSetData(data) { 6 | return (dispatch) => { 7 | fetch('/routes/setData', {method: 'POST', headers: jsonHeader, body: JSON.stringify(data)}) 8 | .then(() => { 9 | fetch('/routes/getData') 10 | .then((response) => response.json()) 11 | .then((json) => dispatch({type: 'GOT_DATA', payload: json})); 12 | }); 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 3 | const webpack = require('webpack'); 4 | const configJson = require('./webpack.config.json'); 5 | 6 | module.exports = (env) => { 7 | 8 | const noMinimize = env.noMinimize; 9 | var plugins = []; 10 | 11 | plugins.push(new ExtractTextPlugin({filename: 'app.css', allChunks: true})); 12 | plugins.push(new webpack.optimize.CommonsChunkPlugin({name: 'lib'})); 13 | if (noMinimize) { 14 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('development')}})); 15 | } else { 16 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('production')}})); 17 | plugins.push(new webpack.optimize.UglifyJsPlugin({include: /lib\.js/, minimize: true})); 18 | } 19 | 20 | const ROOT_PATH = path.resolve(__dirname); 21 | const SRC_PATH = path.resolve(ROOT_PATH, './ui-src'); 22 | const DIST_PATH = path.resolve(ROOT_PATH, './ui-dist'); 23 | 24 | 25 | return { 26 | context: SRC_PATH, 27 | entry: { 28 | app: './app.jsx', 29 | lib: configJson.lib 30 | }, 31 | 32 | output: { 33 | path: DIST_PATH, 34 | filename: '[name].js' 35 | }, 36 | 37 | module: { 38 | rules: [ 39 | { 40 | test: /\.jsx?$/, 41 | loader: 'babel-loader', 42 | query: {presets:['es2015', 'react', 'stage-0']}, 43 | exclude: /(node_modules)/, 44 | }, 45 | { 46 | test: /\.css$/, 47 | use: ExtractTextPlugin.extract({ 48 | fallback: 'style-loader', 49 | use: 'css-loader' 50 | }) 51 | }, 52 | { 53 | test: /\.(png|jpg|ico|gif)$/, 54 | loader: 'file-loader?name=img/[name].[ext]' 55 | }, 56 | { 57 | test: /\.(html)$/, 58 | loader: 'file-loader?name=[name].[ext]' 59 | } 60 | ] 61 | }, 62 | plugins, 63 | resolve: { 64 | extensions: ['.js', '.jsx'], 65 | modules: ['node_modules'] 66 | } 67 | }; 68 | }; 69 | -------------------------------------------------------------------------------- /React.15/ReduxFetch/webpack.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": [ 3 | "react", 4 | "react-dom", 5 | "react-redux", 6 | "redux", 7 | "redux-thunk", 8 | "whatwg-fetch" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /React.15/ReduxPages/README.md: -------------------------------------------------------------------------------- 1 | # ReactPatterns ReduxPages 2 | 3 | This demonstrates using Redux to handle app state. 4 | 5 | Pages with; 6 | 7 | * Radium 8 | * Window Events 9 | * Window Object 10 | 11 | The singleton test is from (http://amanvirk.me/singleton-classes-in-es6/) 12 | -------------------------------------------------------------------------------- /React.15/ReduxPages/js/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | const favicon = require('serve-favicon'); 5 | const path = require('path'); 6 | const port = Number(3500); 7 | 8 | const app = express(); 9 | app.listen(port); 10 | 11 | app.use('/', express.static('ui-dist')); 12 | app.use(favicon(path.join(__dirname, '..', 'ui-dist', 'img', 'favicon.ico'))); 13 | app.get('/', function(req, res){ res.sendfile(__dirname + '/index.html', [], null); }); 14 | -------------------------------------------------------------------------------- /React.15/ReduxPages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReactPatterns.15-ReduxPages", 3 | "version": "1.0.0", 4 | "description": "A collection of simple react projects providing reusable components, startup and test examples.", 5 | "license": "MIT", 6 | "author": { 7 | "name": "Janaka Stevens", 8 | "email": "jmstevens@calitek.com" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/calitek/ReactPatterns.git" 13 | }, 14 | "scripts": { 15 | "start": "node js/server.js", 16 | "ww": "webpack --progress --profile --colors --env.noMinimize --watch", 17 | "nw": "webpack --progress --profile --colors --env.noMinimize" 18 | }, 19 | "dependencies": { 20 | "express": "latest", 21 | "serve-favicon": "latest" 22 | }, 23 | "devDependencies": { 24 | "radium": "latest", 25 | "react": "^15.4.0", 26 | "react-dom": "^15.4.0", 27 | "react-redux": "latest", 28 | "redux": "latest", 29 | "redux-logger": "latest", 30 | 31 | "babel-core": "latest", 32 | "babel-loader": "^6.1.0", 33 | "babel-preset-es2015": "latest", 34 | "babel-preset-react": "latest", 35 | "babel-preset-stage-0": "latest", 36 | "css-loader": "latest", 37 | "extract-text-webpack-plugin": "^2.0.0-rc.3", 38 | "file-loader": "latest", 39 | "loader-utils": "latest", 40 | "style-loader": "^0.13.1", 41 | "webpack": "latest" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/app.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import './index.html'; 4 | import './css/index.css'; 5 | import './img/favicon.ico'; 6 | 7 | import React from 'react'; 8 | import ReactDom from 'react-dom'; 9 | import {Provider} from 'react-redux'; 10 | 11 | import AppCtrl from './components/app.ctrl'; 12 | import AppStore from './store/App.Store'; 13 | 14 | window.ReactDom = ReactDom; 15 | 16 | ReactDom.render(, document.getElementById('react')); 17 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/components/app.ctrl.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | 4 | import NavBar from './common/nav.bar'; 5 | 6 | import CachePage from './cache/cache.page'; 7 | import EventPage from './event/event.page'; 8 | import HomePage from './home/home.page'; 9 | import ObjectPage from './object/object.page'; 10 | import RadiumPage from './radium/radium.page'; 11 | 12 | let AppCtrlSty = { 13 | height: '100%', 14 | overflow: 'hidden', 15 | padding: '0px', 16 | width: '100%' 17 | }; 18 | 19 | function AppCtrl({appState}) { 20 | let page = appState.currentPage; 21 | let hideCache = (page != 'cache'); 22 | let hideEvent = (page != 'event'); 23 | let hideHome = (page != 'home'); 24 | let hideObject = (page != 'object'); 25 | let hideRadium = (page != 'radium'); 26 | return ( 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | ); 36 | } 37 | 38 | function mapStateToProps(store) { return {appState: store.appState}; } 39 | 40 | export default connect(mapStateToProps)(AppCtrl); 41 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/components/cache/cache.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Cache from '../../lib/cache'; 4 | 5 | let AboutPageSty = { 6 | border: 'solid 1px darkslategrey', 7 | height: 'calc(100% - 2px)', 8 | overflow: 'hidden', 9 | padding: '0px', 10 | width: '100%' 11 | }; 12 | 13 | export default class CachePage extends React.Component { 14 | state = {constructorTime: new Date().toLocaleString(), componentDidMountTime: ''}; 15 | componentDidMount = () => { this.setState({componentDidMountTime: new Date().toLocaleString()}); }; 16 | render() { 17 | if (this.props.hide) return null; 18 | let aTime = (new Cache()).time.toString(); 19 | let renderTime = new Date().toLocaleString(); 20 | return ( 21 |
22 | singleton object time: {aTime} 23 |

24 | constructorTime: {this.state.constructorTime} 25 |

26 | componentDidMountTime: {this.state.componentDidMountTime} 27 |

28 | renderTime: {renderTime} 29 |
30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/components/common/app.colors.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | morning_sky: '#cae4db', 3 | honey: '#dcae1d', 4 | cerulean: '#00303f', 5 | mist: '#7a9d96', 6 | 7 | bluebell: '#155765', 8 | olive: '#57652a', 9 | ornate: '#ab9353', 10 | plum: '#4d2c3d', 11 | 12 | gold: '#cda34f', 13 | daisy: '#e9e7da', 14 | stem: '#636b46', 15 | greenery: '#373f27', 16 | 17 | aqua: '#6bbaa7', 18 | sunshine: '#fba100', 19 | lavender: '#6c648b', 20 | dusty_rose: '#b6a19e', 21 | 22 | rust: '#b56357', 23 | mint: '#b4dbc0', 24 | slate: '#eae3ea', 25 | sea_foam: '#a7b3a5', 26 | 27 | white: '#fff', 28 | black: '#000' 29 | }; 30 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/components/common/nav.bar.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | import {bindActionCreators} from 'redux'; 4 | 5 | import {appNavMenuAction} from '../../store/app/app.Actions'; 6 | import AppColors from './app.colors'; 7 | 8 | let NavBarSty = { 9 | background: AppColors.greenery, 10 | lineHeight: '3em', 11 | overflow: 'hidden', 12 | padding: '0px', 13 | }; 14 | 15 | let spanSty = { 16 | color: AppColors.white, 17 | cursor: 'pointer', 18 | fontFamily: '\'Trebuchet MS\', \'Lucida Grande\', \'Lucida Sans Unicode\', \'Lucida Sans\', \'sans-serif\'', 19 | fontSize: '1.5em', 20 | fontWeight: '500', 21 | }; 22 | 23 | let spanSpacerSty = {padding: '0 2em'}; 24 | 25 | const NavBar = (props) => { 26 | const onMouseEnter = (event) => { if (props.navEnter) props.navEnter(event.target.id); }; 27 | const onMouseLeave = (event) => { if (props.navLeave) props.navLeave(event.target.id); }; 28 | const navClick = (event) => { 29 | props.appNavMenuAction(event.target.id); 30 | if (props.navEnter) props.navEnter(''); 31 | }; 32 | let SpanSty = Object.assign({}, spanSty); 33 | let SelectedSty = Object.assign({}, SpanSty); 34 | SelectedSty.color = AppColors.mint; 35 | 36 | let cacheSty = props.fromPage === 'cache' ? SelectedSty : SpanSty; 37 | let eventSty = props.fromPage === 'event' ? SelectedSty : SpanSty; 38 | let homeSty = props.fromPage === 'home' ? SelectedSty : SpanSty; 39 | let objectSty = props.fromPage === 'object' ? SelectedSty : SpanSty; 40 | let radiumSty = props.fromPage === 'radium' ? SelectedSty : SpanSty; 41 | 42 | return ( 43 | 56 | ); 57 | }; 58 | 59 | function mapDispatchToProps(dispatch) { 60 | return bindActionCreators({appNavMenuAction}, dispatch); 61 | } 62 | 63 | export default connect(null, mapDispatchToProps)(NavBar); 64 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/components/event/event.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | let EventPageSty = { 4 | height: '100%', 5 | padding: '0 10px 0 0' 6 | }; 7 | 8 | export default class EventPage extends React.Component { 9 | state = {keyCode: 0}; 10 | componentDidMount = () => { 11 | window.addEventListener('keydown', this.keyDownListener); 12 | }; 13 | componentWillUnmount = () => { 14 | window.removeEventListener('keydown', this.keyDownListener); 15 | }; 16 | keyDownListener = (event) => { 17 | let intKey = (window.Event) ? event.which : event.keyCode; 18 | this.setState({keyCode: intKey}); 19 | }; 20 | render() { 21 | if (this.props.hide) return null; 22 | let keycode = this.state.keyCode; 23 | return ( 24 |
25 | React 15 Window events 26 |

27 | Press any key to see the key code. 28 |

29 | Key code: {keycode} 30 |
31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/components/home/home.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Cache from '../../lib/cache'; 4 | 5 | let HomePageSty = { 6 | border: 'solid 1px darkslategrey', 7 | height: 'calc(100% - 2px)', 8 | overflow: 'hidden', 9 | padding: '0px', 10 | width: '100%' 11 | }; 12 | 13 | export default class HomePage extends React.Component { 14 | state = {constructorTime: new Date().toLocaleString(), componentDidMountTime: ''}; 15 | componentDidMount = () => { this.setState({componentDidMountTime: new Date().toLocaleString()}); }; 16 | render() { 17 | if (this.props.hide) return null; 18 | let aTime = (new Cache()).time.toString(); 19 | let renderTime = new Date().toLocaleString(); 20 | let platform = window.navigator.platform; 21 | let innerWidth = Math.floor(window.innerWidth); 22 | let innerHeight = Math.floor(window.innerHeight); 23 | let screenwidth = Math.floor(window.screen.width); 24 | let screenheight = Math.floor(window.screen.height); 25 | let devicePixelRatio = Math.floor(window.devicePixelRatio); 26 | let navigatorproduct = window.navigator.product; 27 | let navigatoruserAgent = window.navigator.userAgent; 28 | return ( 29 |
30 | Platform: {platform}
31 | Inner Width: {innerWidth}
32 | Inner Height: {innerHeight}
33 | Screen Width: {screenwidth}
34 | Screen Height: {screenheight}
35 | Device Pixel Ratio: {devicePixelRatio}
36 | Navigator Product: {navigatorproduct}
37 | Navigator User Agent: {navigatoruserAgent}

38 | singleton object time: {aTime} 39 |

40 | constructorTime: {this.state.constructorTime} 41 |

42 | componentDidMountTime: {this.state.componentDidMountTime} 43 |

44 | renderTime: {renderTime} 45 |
46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/components/radium/button.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Radium from 'radium'; 3 | 4 | let styles = { 5 | base: { 6 | fontSize: 16, 7 | backgroundColor: '#0074d9', 8 | color: '#fff', 9 | border: 0, 10 | borderRadius: '0.3em', 11 | padding: '0.4em 1em', 12 | cursor: 'pointer', 13 | outline: 'none', 14 | 15 | '@media (min-width: 992px)': { 16 | padding: '0.6em 1.2em' 17 | }, 18 | 19 | '@media (min-width: 1200px)': { 20 | padding: '0.8em 1.5em' 21 | }, 22 | 23 | ':hover': { 24 | backgroundColor: '#0088FF' 25 | }, 26 | 27 | ':focus': { 28 | backgroundColor: '#0088FF' 29 | }, 30 | 31 | ':active': { 32 | backgroundColor: '#005299', 33 | transform: 'translateY(2px)', 34 | } 35 | }, 36 | 37 | red: { 38 | backgroundColor: '#d90000', 39 | 40 | ':hover': { 41 | backgroundColor: '#FF0000' 42 | }, 43 | ':focus': { 44 | backgroundColor: '#FF0000' 45 | }, 46 | ':active': { 47 | backgroundColor: '#990000' 48 | } 49 | } 50 | }; 51 | 52 | export default class Button extends React.Component { 53 | render() { 54 | return ( 55 | 61 | ); 62 | } 63 | } 64 | 65 | Button = Radium(Button); 66 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/components/radium/computed-well.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Radium from 'radium'; 3 | 4 | export default class ComputedWell extends React.Component { 5 | constructor() { 6 | super(); 7 | this.state = {dynamicBg: '#000'}; 8 | } 9 | getStyles = () => { 10 | return { 11 | padding: '1em', 12 | borderRadius: 5, 13 | background: this.state.dynamicBg 14 | }; 15 | }; 16 | handleSubmit = (ev) => { 17 | ev.preventDefault(); 18 | this.setState({dynamicBg: this.inputRef.value}); 19 | }; 20 | render() { 21 | return ( 22 |
23 | { this.inputRef = ref; }} type="text" placeholder="black" /> 24 | 25 | 26 |
27 | ); 28 | } 29 | } 30 | 31 | ComputedWell = Radium(ComputedWell); 32 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/components/radium/hover.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Radium from 'radium'; 3 | 4 | class HoverMessage extends React.Component { 5 | render() { 6 | let buttonHover = Radium.getState(this.state, 'button', ':hover') ? ({' '}Hovering yes!) : null; 7 | return ( 8 |
9 | 10 | {buttonHover} 11 |
12 | ); 13 | } 14 | } 15 | 16 | module.exports = Radium(HoverMessage); 17 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/css/index.css: -------------------------------------------------------------------------------- 1 | .bodyStyle { 2 | background-color: #00303f; 3 | color: #eae3ea; 4 | display: block; 5 | height: 100%; 6 | overflow: hidden; 7 | width: 100%; 8 | } 9 | 10 | .header { 11 | height: 30px; 12 | margin: 0; 13 | padding: 10px 0; 14 | text-align: center; 15 | } 16 | 17 | .Title {font-size: 1.3em;} 18 | 19 | .content { 20 | height: 100%; 21 | padding: 0 5px; 22 | } 23 | 24 | .contentPage { 25 | margin: 5px auto; 26 | max-width: 1366px; 27 | } 28 | 29 | * { outline: none; } 30 | 31 | .a{display:block} 32 | 33 | .FlexBox { 34 | display: -webkit-box; 35 | display: -moz-box; 36 | display: -ms-flexbox; 37 | display: flex; 38 | } 39 | 40 | .FlexBoxCenter { 41 | display: -webkit-box; 42 | display: -moz-box; 43 | display: -ms-flexbox; 44 | display: flex; 45 | justify-content: center; 46 | } 47 | 48 | .FlexBoxJustAround { 49 | display: -webkit-box; 50 | display: -moz-box; 51 | display: -ms-flexbox; 52 | display: flex; 53 | justify-content: space-around; 54 | } 55 | 56 | .FlexBoxJustBetween { 57 | display: -webkit-box; 58 | display: -moz-box; 59 | display: -ms-flexbox; 60 | display: flex; 61 | justify-content: space-between; 62 | } 63 | 64 | .FlexBoxWrap { 65 | display: -webkit-box; 66 | display: -moz-box; 67 | display: -ms-flexbox; 68 | display: flex; 69 | flex-wrap: wrap; 70 | } 71 | 72 | .FlexJustify { 73 | -webkit-box-pack: justify; 74 | justify-content: space-between; 75 | } 76 | 77 | .FlexBoxStretch { 78 | display: -webkit-box; 79 | display: -moz-box; 80 | display: -ms-flexbox; 81 | display: flex; 82 | align-content: stretch; 83 | } 84 | 85 | .FlexItem { 86 | flex-grow: 1; 87 | } 88 | 89 | .HighZ {z-index: 200;} 90 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.15/ReduxPages/ui-src/img/favicon.ico -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ReactPatterns-ReduxPages 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/lib/cache.js: -------------------------------------------------------------------------------- 1 | //Singleton test 2 | 3 | let instance = null; 4 | export default class Cache{ 5 | constructor() { 6 | if (!instance) instance = this; 7 | this.time = new Date(); 8 | return instance; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/store/App.Store.js: -------------------------------------------------------------------------------- 1 | import {createStore, combineReducers, applyMiddleware} from 'redux'; 2 | import createLogger from 'redux-logger'; 3 | 4 | import appState from './app/app.Reducer'; 5 | 6 | const reducer = combineReducers({appState}); 7 | let middleware = []; 8 | 9 | const useLogger = 1; 10 | const loggerMiddleware = createLogger(); 11 | if (useLogger) middleware.push(loggerMiddleware); 12 | 13 | const store = createStore(reducer, applyMiddleware(...middleware)); 14 | 15 | export default store; 16 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/store/app/app.actions.js: -------------------------------------------------------------------------------- 1 | export function appNavMenuAction(newPage) { return {type: 'AppNavMenuAction', newPage}; } 2 | -------------------------------------------------------------------------------- /React.15/ReduxPages/ui-src/store/app/app.reducer.js: -------------------------------------------------------------------------------- 1 | 2 | const initialAppState = { 3 | currentPage: 'home', 4 | currentExample: '', 5 | srcUrl: '' 6 | }; 7 | 8 | export default function handleActions(state = initialAppState, action) { 9 | let _appState = Object.assign({}, state); 10 | switch (action.type) { 11 | case 'AppNavMenuAction': _appState.currentPage = action.newPage; return _appState; 12 | default: return state; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /React.15/ReduxPages/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 3 | const webpack = require('webpack'); 4 | const configJson = require('./webpack.config.json'); 5 | 6 | module.exports = (env) => { 7 | 8 | const noMinimize = env.noMinimize; 9 | var plugins = []; 10 | 11 | plugins.push(new ExtractTextPlugin({filename: 'app.css', allChunks: true})); 12 | plugins.push(new webpack.optimize.CommonsChunkPlugin({name: 'lib'})); 13 | if (noMinimize) { 14 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('development')}})); 15 | } else { 16 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('production')}})); 17 | plugins.push(new webpack.optimize.UglifyJsPlugin({include: /lib\.js/, minimize: true})); 18 | } 19 | 20 | const ROOT_PATH = path.resolve(__dirname); 21 | const SRC_PATH = path.resolve(ROOT_PATH, './ui-src'); 22 | const DIST_PATH = path.resolve(ROOT_PATH, './ui-dist'); 23 | 24 | 25 | return { 26 | context: SRC_PATH, 27 | entry: { 28 | app: './app.jsx', 29 | lib: configJson.lib 30 | }, 31 | 32 | output: { 33 | path: DIST_PATH, 34 | filename: '[name].js' 35 | }, 36 | 37 | module: { 38 | rules: [ 39 | { 40 | test: /\.jsx?$/, 41 | loader: 'babel-loader', 42 | query: {presets:['es2015', 'react', 'stage-0']}, 43 | exclude: /(node_modules)/, 44 | }, 45 | { 46 | test: /\.css$/, 47 | use: ExtractTextPlugin.extract({ 48 | fallback: 'style-loader', 49 | use: 'css-loader' 50 | }) 51 | }, 52 | { 53 | test: /\.(png|jpg|ico|gif)$/, 54 | loader: 'file-loader?name=img/[name].[ext]' 55 | }, 56 | { 57 | test: /\.(html)$/, 58 | loader: 'file-loader?name=[name].[ext]' 59 | } 60 | ] 61 | }, 62 | plugins, 63 | resolve: { 64 | extensions: ['.js', '.jsx'], 65 | modules: ['node_modules'] 66 | } 67 | }; 68 | }; 69 | -------------------------------------------------------------------------------- /React.15/ReduxPages/webpack.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": [ 3 | "radium", 4 | "react", 5 | "react-dom", 6 | "react-redux", 7 | "redux", 8 | "redux-logger" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/README.md: -------------------------------------------------------------------------------- 1 | # ReactPatterns ReduxSocketIO 2 | 3 | A basic demonstration of redux with websocket. This would be the starting point for a simple data handling app. 4 | The 15 version uses more es6 and refines the reflux usage a bit. 5 | 6 | # Getting started 7 | 8 | cd into the root directory of the project. If the first time "npm install". "npm run ww" for webpack with watch. 9 | "npm run nw" for webpack no watch. "npm start" to start the node server. "localhost:3500" in the browser. 10 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/data/basic.json: -------------------------------------------------------------------------------- 1 | { 2 | "React version": "15", 3 | "Project": "Redux with socket.io", 4 | "currentDateTime": "2/20/2017, 1:40:50 PM" 5 | } -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/js/mainsocket.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const getSetData = require('./socket/GetSetData'); 4 | 5 | module.exports = function(socket) { 6 | console.log('Socket.io connection made.'); 7 | 8 | const getDataDone = function(data){ 9 | console.log('getDataDone'); 10 | socket.emit('server:GetDataDone', data); 11 | }; 12 | const onGetData = function() { 13 | console.log('onGetData'); 14 | getSetData.getData(getDataDone); 15 | }; 16 | socket.on('client:GetData', onGetData); 17 | 18 | const setDataDone = function(){ socket.emit('server:SetDataDone'); }; 19 | const onSetData = function(data) { 20 | getSetData.setData(data, setDataDone); 21 | }; 22 | socket.on('client:SetData', onSetData); 23 | }; 24 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/js/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | const app = express(); 5 | const server = require('http').Server(app); 6 | const ioServer = require('socket.io')(server); 7 | const favicon = require('serve-favicon'); 8 | 9 | const path = require('path'); 10 | const port = Number(3500); 11 | 12 | server.listen(port); 13 | 14 | const socketCallBack = function(socket){ require('./mainsocket')(socket); }; 15 | 16 | ioServer.on('connection', socketCallBack); 17 | 18 | app.use('/', express.static('ui-dist')); 19 | app.use(favicon(path.join(__dirname, '..', 'ui-dist', 'img', 'favicon.ico'))); 20 | app.get('/', function(req, res){ res.sendfile(__dirname + '/index.html', [], null); }); 21 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/js/socket/GetSetData.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | 5 | const rootDataPath = './data'; 6 | 7 | module.exports.getData = function(doneCallBack) { 8 | const filePath = rootDataPath + '/basic.json'; 9 | const jsonReadCallBack = function(err, data){ 10 | if (err) doneCallBack('Data readFile error ' + filePath); 11 | else { 12 | const jsonData = JSON.parse(data.toString()); 13 | doneCallBack(jsonData); 14 | } 15 | }; 16 | fs.readFile(filePath, jsonReadCallBack); 17 | }; 18 | 19 | module.exports.setData = function(data, doneCallBack) { 20 | const filePath = rootDataPath + '/basic.json'; 21 | const writeFileCallBack = function (err) { 22 | if (err) console.log('error saving Data.json file '); 23 | else doneCallBack(); 24 | }; 25 | fs.writeFile(filePath, JSON.stringify(data, null, 2), writeFileCallBack); 26 | }; 27 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReactPatterns.15-ReduxSocketIO", 3 | "version": "1.0.0", 4 | "description": "A collection of simple react projects providing reusable components, startup and test examples.", 5 | "license": "MIT", 6 | "author": { 7 | "name": "Janaka Stevens", 8 | "email": "jmstevens@calitek.com" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/calitek/ReactPatterns.git" 13 | }, 14 | "scripts": { 15 | "start": "nodemon --watch js js/server.js", 16 | "ww": "webpack --progress --profile --colors --env.noMinimize --watch", 17 | "nw": "webpack --progress --profile --colors --env.noMinimize" 18 | }, 19 | "dependencies": { 20 | "express": "latest", 21 | "nodemon": "latest", 22 | "serve-favicon": "latest", 23 | "socket.io": "latest" 24 | }, 25 | "devDependencies": { 26 | "react": "^15.4.0", 27 | "react-dom": "^15.4.0", 28 | "react-redux": "latest", 29 | "redux": "latest", 30 | 31 | "babel-core": "latest", 32 | "babel-loader": "^6.1.0", 33 | "babel-preset-es2015": "latest", 34 | "babel-preset-react": "latest", 35 | "babel-preset-stage-0": "latest", 36 | "css-loader": "latest", 37 | "extract-text-webpack-plugin": "^2.0.0-rc.3", 38 | "file-loader": "latest", 39 | "style-loader": "^0.13.1", 40 | "webpack": "latest" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/ui-src/app.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import './index.html'; 4 | import './css/index.css'; 5 | import './img/favicon.ico'; 6 | 7 | import React from 'react'; 8 | import ReactDom from 'react-dom'; 9 | import {Provider} from 'react-redux'; 10 | 11 | import AppCtrl from './components/app.ctrl'; 12 | import AppStore from './store/App.Store'; 13 | 14 | window.ReactDom = ReactDom; 15 | 16 | ReactDom.render( 17 | , 18 | document.getElementById('react') 19 | ); 20 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/ui-src/components/app.ctrl.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | 4 | import AppNotes from './app.notes'; 5 | 6 | let AppCtrlSty = { 7 | height: '100%', 8 | padding: '0 10px 0 0' 9 | }; 10 | 11 | function AppCtrl({Data1}) { 12 | let data1 = Data1; 13 | return ( 14 |
15 | React Version: {data1['React version']}

16 | Project: {data1.Project}

17 | Current date/time: {data1.currentDateTime}

18 | 19 |
20 | ); 21 | } 22 | 23 | function mapStateToProps(store) { 24 | return {Data1: store.data1}; 25 | } 26 | 27 | export default connect(mapStateToProps)(AppCtrl); 28 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/ui-src/components/app.notes.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | let AppNotesSty = { 4 | marginLeft: 'auto', 5 | marginRight: 'auto', 6 | marginTop: '30px', 7 | maxWidth: '500px', 8 | textIndent: '20px' 9 | }; 10 | 11 | let textSty = { 12 | color: '#000', 13 | fontSize: '1.0em', 14 | textAlign: 'left' 15 | }; 16 | 17 | let btnDivSty = {textAlign: 'center'}; 18 | 19 | let standardBtnSty = { 20 | backgroundColor: '#9a6', 21 | borderBottomColor: '#cea', 22 | borderLeftColor: '#93a363', 23 | borderRightColor: '#cea', 24 | borderTopColor: '#93a363', 25 | borderRadius: '6px', 26 | color: '#eeffee', 27 | cursor: 'pointer', 28 | lineHeight: '100%', 29 | outline: 'none', 30 | verticalAlign: 'middle', 31 | whiteSpace: 'nowrap' 32 | }; 33 | 34 | let p1Text = ` 35 | `; 36 | 37 | export default class AppNotes extends React.Component { 38 | state = {show: true}; 39 | onClick = () => { this.setState({show: !this.state.show}); }; 40 | render() { 41 | let showNotes = this.state.show; 42 | let btnText = showNotes ? 'Hide notes' : 'Show notes'; 43 | let notesDivSty = showNotes ? {display: 'block'} : {display: 'none'}; 44 | return ( 45 |
46 |
47 | 48 |
49 |
50 |

{p1Text}

51 |
52 |
53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/ui-src/css/index.css: -------------------------------------------------------------------------------- 1 | .bodyStyle { 2 | background-color: #00303f; 3 | color: #eae3ea; 4 | display: block; 5 | overflow: hidden; 6 | width: 100%; 7 | } 8 | 9 | .header { 10 | height: 30px; 11 | margin: 0; 12 | padding: 10px 0; 13 | text-align: center; 14 | } 15 | 16 | .Title {font-size: 1.3em;} 17 | 18 | .content { 19 | height: calc(100% - 52px); 20 | max-width: 1366px; 21 | margin-left: auto; 22 | margin-right: auto; 23 | padding: 0 5px; 24 | } 25 | 26 | * { outline: none; } 27 | 28 | .a{display:block} 29 | 30 | .FlexBox { 31 | display: -webkit-box; 32 | display: -moz-box; 33 | display: -ms-flexbox; 34 | display: flex; 35 | } 36 | 37 | .FlexBoxJustAround { 38 | display: -webkit-box; 39 | display: -moz-box; 40 | display: -ms-flexbox; 41 | display: flex; 42 | justify-content: space-around; 43 | } 44 | 45 | .FlexBoxJustBetween { 46 | display: -webkit-box; 47 | display: -moz-box; 48 | display: -ms-flexbox; 49 | display: flex; 50 | justify-content: space-between; 51 | } 52 | 53 | .FlexBoxWrap { 54 | display: -webkit-box; 55 | display: -moz-box; 56 | display: -ms-flexbox; 57 | display: flex; 58 | flex-wrap: wrap; 59 | } 60 | 61 | .FlexJustify { 62 | -webkit-box-pack: justify; 63 | justify-content: space-between; 64 | } 65 | 66 | .FlexBoxStretch { 67 | display: -webkit-box; 68 | display: -moz-box; 69 | display: -ms-flexbox; 70 | display: flex; 71 | align-content: stretch; 72 | } 73 | 74 | .FlexItem { 75 | flex-grow: 1; 76 | } 77 | 78 | .HighZ {z-index: 200;} 79 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/ui-src/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.15/ReduxSocketIO/ui-src/img/favicon.ico -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/ui-src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ReactPatterns-ReduxWebSocket 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | ReactPatterns-ReduxSocket.io 16 |
17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/ui-src/store/Actions.js: -------------------------------------------------------------------------------- 1 | export function apiGetData() { return {type: 'ApiGetData'}; } 2 | 3 | export function apiGotData(data) { return {type: 'ApiGotData', data}; } 4 | 5 | export function apiSetData(data) { return {type: 'ApiSetData', data}; } 6 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/ui-src/store/App.Store.js: -------------------------------------------------------------------------------- 1 | import {createStore, applyMiddleware} from 'redux'; 2 | import startWs, {wsMiddleware} from './ws.api'; 3 | import {apiSetData} from './Actions'; 4 | 5 | function handleData(state = {data1: {}}, action) { 6 | switch (action.type) { 7 | case 'ApiGotData': return Object.assign({}, state, {data1: action.data}); 8 | default: return state; 9 | } 10 | } 11 | 12 | const store = createStore(handleData, applyMiddleware(wsMiddleware)); 13 | 14 | startWs(store); 15 | 16 | const newData = { 17 | 'React version': '15', 18 | 'Project': 'Redux with socket.io', 19 | 'currentDateTime': new Date().toLocaleString() 20 | }; 21 | 22 | store.dispatch(apiSetData(newData)); 23 | 24 | export default store; 25 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/ui-src/store/ws.api.js: -------------------------------------------------------------------------------- 1 | import * as Actions from './Actions'; 2 | 3 | var socket = null; 4 | 5 | export function wsMiddleware() { 6 | return (next) => (action) => { 7 | if (socket && action.type === 'ApiGetData') { 8 | console.log('ApiGetData'); 9 | socket.emit('client:GetData', {}); 10 | } else if (socket && action.type === 'ApiSetData') { 11 | console.log('ApiSetData'); 12 | socket.emit('client:SetData', action.data); 13 | } 14 | 15 | return next(action); 16 | }; 17 | } 18 | 19 | export default function (store) { 20 | /* eslint-disable */ 21 | socket = new io(); 22 | /* eslint-enable */ 23 | 24 | socket.on('server:GetDataDone', (data) => { 25 | console.log('GetDataDone'); 26 | store.dispatch(Actions.apiGotData(data)); 27 | }); 28 | 29 | socket.on('server:SetDataDone', () => { 30 | console.log('SetDataDone'); 31 | store.dispatch(Actions.apiGetData()); 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 3 | const webpack = require('webpack'); 4 | const configJson = require('./webpack.config.json'); 5 | 6 | module.exports = (env) => { 7 | 8 | const noMinimize = env.noMinimize; 9 | var plugins = []; 10 | 11 | plugins.push(new ExtractTextPlugin({filename: 'app.css', allChunks: true})); 12 | plugins.push(new webpack.optimize.CommonsChunkPlugin({name: 'lib'})); 13 | if (noMinimize) { 14 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('development')}})); 15 | } else { 16 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('production')}})); 17 | plugins.push(new webpack.optimize.UglifyJsPlugin({include: /lib\.js/, minimize: true})); 18 | } 19 | 20 | const ROOT_PATH = path.resolve(__dirname); 21 | const SRC_PATH = path.resolve(ROOT_PATH, './ui-src'); 22 | const DIST_PATH = path.resolve(ROOT_PATH, './ui-dist'); 23 | 24 | 25 | return { 26 | context: SRC_PATH, 27 | entry: { 28 | app: './app.jsx', 29 | lib: configJson.lib 30 | }, 31 | 32 | output: { 33 | path: DIST_PATH, 34 | filename: '[name].js' 35 | }, 36 | 37 | module: { 38 | rules: [ 39 | { 40 | test: /\.jsx?$/, 41 | loader: 'babel-loader', 42 | query: {presets:['es2015', 'react', 'stage-0']}, 43 | exclude: /(node_modules)/, 44 | }, 45 | { 46 | test: /\.css$/, 47 | use: ExtractTextPlugin.extract({ 48 | fallback: 'style-loader', 49 | use: 'css-loader' 50 | }) 51 | }, 52 | { 53 | test: /\.(png|jpg|ico|gif)$/, 54 | loader: 'file-loader?name=img/[name].[ext]' 55 | }, 56 | { 57 | test: /\.(html)$/, 58 | loader: 'file-loader?name=[name].[ext]' 59 | } 60 | ] 61 | }, 62 | plugins, 63 | resolve: { 64 | extensions: ['.js', '.jsx'], 65 | modules: ['node_modules'] 66 | } 67 | }; 68 | }; 69 | -------------------------------------------------------------------------------- /React.15/ReduxSocketIO/webpack.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": [ 3 | "react", 4 | "react-dom", 5 | "react-redux", 6 | "redux" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /React.Common/README.md: -------------------------------------------------------------------------------- 1 | # ReactPatterns Common Pages 2 | 3 | * Button 4 | * DropDowns 5 | * Form Input 6 | * Gallery 7 | * List 8 | * PageIndicator 9 | * ProgressBar 10 | * Sliders 11 | * Tooltip 12 | * TreeViews 13 | -------------------------------------------------------------------------------- /React.Common/data/AppData.json: -------------------------------------------------------------------------------- 1 | { 2 | "nextid": "[object Object]1" 3 | } -------------------------------------------------------------------------------- /React.Common/data/inputs.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "this is a text input", 3 | "checkbox": true, 4 | "radioGroup": "setkey", 5 | "color": "#546d53", 6 | "number": "20", 7 | "range": "70", 8 | "folder": "C:\\fakepath\\_1020715.JPG" 9 | } -------------------------------------------------------------------------------- /React.Common/js/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | const router = express.Router(); 5 | 6 | const getSetData = require('./routes/GetSetData'); 7 | const getPicList = require('./routes/GetPicList'); 8 | 9 | router.get('/getPicList', function(req, res) { 10 | const gotPicList = function(data){ res.send(data); }; 11 | getPicList.getPicList(gotPicList); 12 | }); 13 | 14 | router.get('/getAppData', function(req, res) { 15 | const getDataDone = function(data){ res.send(data); }; 16 | getSetData.getAppData(getDataDone); 17 | }); 18 | 19 | router.get('/getImageList', function(req, res) { 20 | const getDataDone = function(data){ res.send(data); }; 21 | getSetData.getImageList(getDataDone); 22 | }); 23 | 24 | router.get('/getTreeView', function(req, res) { 25 | const getDataDone = function(data){ res.send(data); }; 26 | getSetData.getTreeView(getDataDone); 27 | }); 28 | 29 | router.post('/setAppData', function(req) { getSetData.setAppData(req.body); }); 30 | router.post('/setTreeView', function(req) { getSetData.setTreeView(req.body); }); 31 | 32 | router.get('/getInputData', function(req, res) { 33 | const getDataDone = function(data){ res.send(data); }; 34 | getSetData.getInputData(getDataDone); 35 | }); 36 | 37 | router.post('/setInputData', function(req) { 38 | getSetData.setInputData(req.body); 39 | }); 40 | 41 | module.exports = router; 42 | -------------------------------------------------------------------------------- /React.Common/js/routes/GetPicList.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const exiftool = require('node-exiftool'); 4 | 5 | const fieldList = [ 6 | 'FileName', 7 | 'Description', 8 | 'Copyright', 9 | ]; 10 | 11 | module.exports.getPicList = function(doneCallBack) { 12 | const ep = new exiftool.ExiftoolProcess(); 13 | const picFolder = './ui-dist/data/_sm'; 14 | 15 | const getFileListCallBack = function(fileList) { 16 | const lgPicFolder = '../data/_lg/'; 17 | const smPicFolder = '../data/_sm/'; 18 | let picList = []; 19 | const addObject = {lgFolder: lgPicFolder, smFolder: smPicFolder}; 20 | fileList.forEach(function(value){ picList.push(Object.assign(value, addObject)); }); 21 | doneCallBack({picList}); 22 | }; 23 | ep.open().then(() => ep.readMetadata(picFolder, fieldList)) 24 | .then((outout) => { getFileListCallBack(outout.data); ep.close(); }); 25 | }; 26 | -------------------------------------------------------------------------------- /React.Common/js/routes/GetSetData.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | 5 | const rootDataPath = './data'; 6 | 7 | module.exports.getAppData = function(doneCallBack) { 8 | const filePath = rootDataPath + '/AppData.json'; 9 | const jsonReadCallBack = function(err, data){ 10 | if (err) console.log('AppData readFile error ' + filePath); 11 | else { 12 | const jsonData = JSON.parse(data.toString()); 13 | doneCallBack(jsonData); 14 | } 15 | }; 16 | fs.readFile(filePath, jsonReadCallBack); 17 | }; 18 | 19 | module.exports.setAppData = function(data) { 20 | const filePath = rootDataPath + '/AppData.json'; 21 | const writeFileCallBack = function (err) { 22 | if (err) console.log('error saving AppData.json file '); 23 | }; 24 | fs.writeFile(filePath, JSON.stringify(data, null, 2), writeFileCallBack); 25 | }; 26 | 27 | module.exports.getImageList = function(doneCallBack) { 28 | const filePath = rootDataPath + '/ImageList.json'; 29 | const jsonReadCallBack = function(err, data){ 30 | if (err) console.log('ImageList readFile error ' + filePath); 31 | else { 32 | const jsonData = JSON.parse(data.toString()); 33 | doneCallBack(jsonData); 34 | } 35 | }; 36 | fs.readFile(filePath, jsonReadCallBack); 37 | }; 38 | 39 | module.exports.getTreeView = function(doneCallBack) { 40 | const filePath = rootDataPath + '/TreeView.json'; 41 | const jsonReadCallBack = function(err, data){ 42 | if (err) console.log('TreeView readFile error ' + filePath); 43 | else { 44 | const jsonData = JSON.parse(data.toString()); 45 | doneCallBack(jsonData); 46 | } 47 | }; 48 | fs.readFile(filePath, jsonReadCallBack); 49 | }; 50 | 51 | module.exports.setTreeView = function(data) { 52 | const filePath = rootDataPath + '/TreeView.json'; 53 | const writeFileCallBack = function (err) { 54 | if (err) console.log('error saving TreeView.json file '); 55 | }; 56 | fs.writeFile(filePath, JSON.stringify(data.data, null, 2), writeFileCallBack); 57 | }; 58 | 59 | module.exports.getInputData = function(doneCallBack) { 60 | const filePath = rootDataPath + '/inputs.json'; 61 | const jsonReadCallBack = function(err, data){ 62 | if (err) doneCallBack('Data readFile error ' + filePath); 63 | else { 64 | const jsonData = JSON.parse(data.toString()); 65 | doneCallBack(jsonData); 66 | } 67 | }; 68 | fs.readFile(filePath, jsonReadCallBack); 69 | }; 70 | 71 | module.exports.setInputData = function(data) { 72 | const filePath = rootDataPath + '/inputs.json'; 73 | const writeFileCallBack = function (err) { 74 | if (err) console.log('error saving Data.json file '); 75 | }; 76 | fs.writeFile(filePath, JSON.stringify(data, null, 2), writeFileCallBack); 77 | }; 78 | -------------------------------------------------------------------------------- /React.Common/js/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bodyParser = require('body-parser'); 4 | const express = require('express'); 5 | const favicon = require('serve-favicon'); 6 | 7 | const path = require('path'); 8 | const port = Number(process.env.COMMONPORT || 3500); 9 | 10 | const routes = require('./routes'); 11 | 12 | const app = express(); 13 | app.listen(port); 14 | 15 | app.use(bodyParser.json()); 16 | app.use(bodyParser.urlencoded({extended: false})); 17 | 18 | app.use('/', express.static('ui-dist')); 19 | app.use('/routes', routes); 20 | 21 | app.use(favicon(path.join(__dirname, '..', 'ui-dist', 'img', 'favicon.ico'))); 22 | app.get('/', function(req, res){ res.sendfile(__dirname + '/index.html', [], null); }); 23 | -------------------------------------------------------------------------------- /React.Common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReactPatterns.Common", 3 | "version": "1.0.0", 4 | "description": "A simple react project providing reusable components.", 5 | "license": "MIT", 6 | "author": { 7 | "name": "J Mark Stevens", 8 | "email": "jms@jmarkstevens.com" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/calitek/ReactPatterns.git" 13 | }, 14 | "scripts": { 15 | "start": "nodemon --watch js js/server.js", 16 | "ww": "webpack --progress --profile --colors --env.noMinimize --watch", 17 | "nw": "webpack --progress --profile --colors --env.noMinimize" 18 | }, 19 | "dependencies": { 20 | "body-parser": "latest", 21 | "express": "latest", 22 | "node-exiftool": "latest", 23 | "nodemon": "latest", 24 | "serve-favicon": "latest" 25 | }, 26 | "devDependencies": { 27 | "babel-core": "latest", 28 | "babel-loader": "^6.1.0", 29 | "babel-preset-es2015": "latest", 30 | "babel-preset-react": "latest", 31 | "babel-preset-stage-0": "latest", 32 | "css-loader": "latest", 33 | "extract-text-webpack-plugin": "^2.0.0-rc.3", 34 | "file-loader": "latest", 35 | "loader-utils": "latest", 36 | "lodash": "latest", 37 | "radium": "latest", 38 | "react": "^15.4.0", 39 | "react-dom": "^15.4.0", 40 | "react-mixin": "^1.2.2", 41 | "react-redux": "latest", 42 | "redux": "latest", 43 | "redux-logger": "latest", 44 | "redux-thunk": "latest", 45 | "screenfull": "latest", 46 | "style-loader": "^0.13.1", 47 | "traverse": "latest", 48 | "webpack": "latest", 49 | "whatwg-fetch": "latest" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /React.Common/ui-src/app.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import './index.html'; 4 | import './css/index.css'; 5 | import './css/rangeInput.css'; 6 | 7 | import './img/favicon.ico'; 8 | import './img/sun.ico'; 9 | import './img/leaf.ico'; 10 | import './img/snow.ico'; 11 | import './img/flow.png'; 12 | import './img/1x1TransShim.gif'; 13 | import './img/SLogoS5-48_C.png'; 14 | 15 | import React from 'react'; 16 | import ReactDom from 'react-dom'; 17 | import {Provider} from 'react-redux'; 18 | 19 | import AppCtrl from './components/app.ctrl'; 20 | import AppStore from './store/App.Store'; 21 | 22 | window.ReactDom = ReactDom; 23 | 24 | ReactDom.render(, document.getElementById('react')); 25 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/Button/app.text.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | p1Text: ` 3 | 4 | ` 5 | }; 6 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/DropDowns/app.text.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | p1Text: ` 3 | 4 | ` 5 | }; 6 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/DropDowns/dropdown.menu.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import JDropMenu from '../common/DropDowns/jDropMenu'; 4 | 5 | let DropDownMenuSty = { 6 | fontSize: '1.2em', 7 | padding: '2px 2px 0 0', 8 | position: 'relative', 9 | right: '0px', 10 | top: '0px' 11 | }; 12 | 13 | let options = [ 14 | {value: 'new', label: 'New'}, 15 | {value: 'edit', label: 'Edit'}, 16 | {type: 'seperator', key: '100'}, 17 | {value: 'moveUp', label: 'Move up'}, 18 | {value: 'moveDown', label: 'Move down'}, 19 | {type: 'seperator', key: '101'}, 20 | {value: 'rename', label: 'Rename'}, 21 | {type: 'seperator', key: '102'}, 22 | {value: 'remove', label: 'Remove'} 23 | ]; 24 | 25 | export default class DropDownMenu extends React.Component { 26 | state = {option: {}}; 27 | onSelect = (option) => { this.setState({option}); }; 28 | render() { 29 | let optionLabel = this.state.option.label; 30 | let optionValue = this.state.option.value; 31 | return ( 32 |
33 | 36 | Label: {optionLabel}
37 | Value: {optionValue} 38 |


39 |
40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/DropDowns/dropdown.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import AppNotes from '../common/app.notes'; 4 | import AppText from './app.text'; 5 | 6 | import DropDownMenu from './dropdown.menu'; 7 | import DropDownSelect from './dropdown.select'; 8 | import JMultiSelect from './multi.select'; 9 | 10 | let DropDownsSty = { 11 | borderBottom: '3px solid #636b46', 12 | padding: '0 10px 0 0' 13 | }; 14 | 15 | let DropDownSty = { 16 | border: 'solid 1px darkslategrey', 17 | height: 'calc(100% - 10px)', 18 | overflow: 'auto', 19 | padding: '10px', 20 | width: '33%' 21 | }; 22 | 23 | const ColumnsSty = { 24 | height: '100%', 25 | }; 26 | 27 | export default function DropDowns(props) { 28 | if (props.hide) return null; 29 | return ( 30 | 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/DropDowns/dropdown.select.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import JDropSelect from '../common/DropDowns/jDropSelect'; 4 | 5 | let DropDownSelectSty = { 6 | fontSize: '1.2em', 7 | padding: '2px 2px 0 0', 8 | textAlign: 'right' 9 | }; 10 | 11 | let options = [ 12 | {label: 'Any', value: 'Any'}, 13 | {label: 'Extremely slow', value: 'slow3'}, 14 | {label: 'Very slow', value: 'slow2'}, 15 | {label: 'Slow', value: 'slow1'}, 16 | {label: 'Moderate', value: 'mod'}, 17 | {label: 'Fast', value: 'fast1'}, 18 | {label: 'Very fast', value: 'fast2'}, 19 | {label: 'Extremely fast', value: 'fast3'} 20 | ]; 21 | 22 | export default class DropDownSelect extends React.Component { 23 | state = {name: 'growthspeed', option: {}}; 24 | onDropSelect = (name, option) => { this.setState({name, option}); }; 25 | render() { 26 | let name = 'growthspeed'; 27 | // let defaultOption = this.state.option.value ? this.state.option : lodash.findWhere(options, {value: 'Any'}); 28 | let defaultOption = this.state.option.value ? this.state.option : options[0]; 29 | let selectedName = this.state.name; 30 | let selectedLabel = this.state.option.label; 31 | let selectedValue = this.state.option.value; 32 | return ( 33 |
34 | 37 | Item name: {selectedName}
38 | Selected label: {selectedLabel}
39 | Selected value: {selectedValue} 40 |

41 |
42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/DropDowns/multi.select.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import JMultiSelect from '../common/DropDowns/jMultiSelect'; 4 | 5 | const MultiSelectSty = { 6 | height: '100%', 7 | maxWidth: '300px', 8 | minHeight: '300px', 9 | }; 10 | 11 | const leafcolor = { 12 | 'value': [], 13 | 'key': 'leaf color', 14 | 'options': [ 15 | { 16 | 'count': 59, 17 | 'label': 'Green on both sides', 18 | 'value': 'allgrn' 19 | }, 20 | { 21 | 'count': 13, 22 | 'label': 'Whitish bottom side', 23 | 'value': 'whtbot' 24 | }, 25 | { 26 | 'count': 25, 27 | 'label': 'Moderately pale bottom side', 28 | 'value': 'mpbot' 29 | }, 30 | { 31 | 'count': 19, 32 | 'label': 'Both sides blue-gray to silver', 33 | 'value': 'allbs' 34 | }, 35 | { 36 | 'count': 3, 37 | 'label': 'Red, reddish to bronze when new', 38 | 'value': 'newred' 39 | } 40 | ] 41 | }; 42 | 43 | const isDesktop = 1; 44 | 45 | export default class MultiSelect extends React.Component { 46 | state = {currentValue: leafcolor.value} 47 | onJSelect = (itemName, selectedItems) => { 48 | let newValue = []; 49 | selectedItems.forEach(item => newValue.push(item.value)); 50 | console.log('itemName: ', itemName); 51 | console.log('newValue: ', newValue); 52 | this.setState({currentValue: newValue}); 53 | } 54 | clickHandler = () => { 55 | this.setState({currentValue: []}); 56 | } 57 | render() { 58 | return ( 59 |
60 | 61 |


62 | 70 |
71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/FormInput/app.text.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | p1Text: ` 3 | 4 | ` 5 | }; 6 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/Gallery/app.text.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | p1Text: ` 3 | 4 | ` 5 | }; 6 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/Gallery/gallery.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | 4 | import AppNotes from '../common/app.notes'; 5 | import AppText from './app.text'; 6 | 7 | import JButton from '../common/Button/jButton'; 8 | import JGallery from '../common/Gallery/jGallery'; 9 | 10 | let GallerySty = { 11 | borderBottom: '3px solid #636b46', 12 | padding: '0 10px 0 0' 13 | }; 14 | 15 | let basicBtn = {buttonid: 'galleryHide', text: 'Open Gallery'}; 16 | 17 | class Gallery extends React.Component { 18 | state = {hideGallery: false}; 19 | galleryHideHandler = () => { this.setState({hideGallery: !this.state.hideGallery}); }; 20 | render() { 21 | if (this.props.hide) return null; 22 | let data = this.props.picList; 23 | let hideGallery = this.state.hideGallery; 24 | return ( 25 | 31 | ); 32 | } 33 | } 34 | 35 | function mapStateToProps(store) { return {picList: store.galleryState.picList}; } 36 | 37 | export default connect(mapStateToProps, null)(Gallery); 38 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/List/app.text.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | p1Text: ` 3 | 4 | ` 5 | }; 6 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/List/list.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import AppNotes from '../common/app.notes'; 4 | import AppText from './app.text'; 5 | 6 | import JList from '../common/List/jList'; 7 | 8 | let ListSty = { 9 | borderBottom: '3px solid #cae4db', 10 | padding: '0 10px 0 0' 11 | }; 12 | 13 | let list = [ 14 | 'line one of list', 15 | 'another line of list', 16 | 'third line of list', 17 | 'fourth line of list', 18 | 'fifth line of list', 19 | 'sixth line of list' 20 | ]; 21 | 22 | let listSty = { 23 | border: '1px solid #e9e7da', 24 | margin: '10px 10px' 25 | }; 26 | 27 | let lineSty = { 28 | color: '#b4dbc0', 29 | marginLeft: '5px' 30 | }; 31 | 32 | export default function List(props) { 33 | if (props.hide) return null; 34 | return ( 35 |
36 |

37 | 38 | 39 | 40 |
41 | 42 | 43 | 44 |
45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/PageIndicator/indicator.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import JPageIndicator from '../common/PageIndicator/jPageIndicator'; 4 | 5 | import AppStyle from '../common/app.style'; 6 | import IndicatorPop from './indicator.pop'; 7 | 8 | import IndicatorStyle from './indicator.style'; 9 | import IndicatorText from './indicator.text'; 10 | 11 | const pageNumber = 4; 12 | 13 | export default class IndicatorPage extends React.Component { 14 | state = {page: 1, hideNote: false}; 15 | _handlePageIndicatorClick = (index) => { 16 | if (this.state.page !== (index + 1)) this.setState({page: index + 1}); 17 | } 18 | showNoteHandler = () => { this.setState({hideNote: !this.state.hideNote}); } 19 | render() { 20 | 21 | if (this.props.hide) return null; 22 | let currentPage = this.state.page; 23 | let noteText; 24 | switch (currentPage) { 25 | case 1: noteText = IndicatorText.note1; break; 26 | case 2: noteText = IndicatorText.note2; break; 27 | case 3: noteText = IndicatorText.note3; break; 28 | case 4: noteText = IndicatorText.note4; break; 29 | } 30 | 31 | 32 | let bottomBtnDivSty = Object.assign({}, AppStyle.bottomBtnDivSty); 33 | bottomBtnDivSty.display = currentPage < pageNumber ? 'block' : 'none'; 34 | let topBtnDivSty = Object.assign({}, AppStyle.topBtnDivSty); 35 | topBtnDivSty.top = '50px'; 36 | 37 | let pageDesc = `Page ${currentPage} of ${pageNumber}`; 38 | return ( 39 |
40 | 41 |
42 | {pageDesc} 43 | 44 |
45 |
46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/PageIndicator/indicator.pop.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const popupSty = { 4 | background: 'rgba(28, 34, 24, .6)', 5 | color: '#e4eae0', 6 | fontFamily: 'Georgia, serif', 7 | fontSize: '1.3vmax', 8 | left: '50%', 9 | padding: '30px', 10 | position: 'absolute', 11 | textAlign: 'center', 12 | top: '33%', 13 | transform: 'translate(-50%, -50%)', 14 | zIndex: '5' 15 | }; 16 | 17 | export default function IndicatorPopup({hide, subText}) { 18 | if (hide) return null; 19 | return ( 20 |
21 | {subText} 22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/PageIndicator/indicator.style.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | IndicatorPageSty: { 4 | height: 'calc(100% - 50px)', 5 | marginTop: '50px', 6 | overflow: 'hidden', 7 | padding: '0px', 8 | width: '100%' 9 | }, 10 | 11 | iFrameSty: { 12 | overflow: 'hidden', 13 | width: '100%' 14 | }, 15 | 16 | iframeDivSty: { 17 | overflowX: 'hidden', 18 | overflowY: 'hidden' 19 | }, 20 | 21 | standardBtnImg: { 22 | backgroundColor: 'transparent', 23 | backgroundImg: 'none', 24 | backgroundSize: 'contain', 25 | border: '0px', 26 | color: '#9fd8de', 27 | cursor: 'pointer', 28 | height: 'inherit', 29 | margin: '0 3px', 30 | outline: 'none', 31 | padding: '0px', 32 | verticalAlign: 'middle', 33 | width: 'inherit' 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/PageIndicator/indicator.text.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | note1: ` 3 | BergstromGardens.com is a current project written in javascript with react and redux libraries. 4 | The Palms page includes a filter that limits the data shown. 5 | `, 6 | note2: ` 7 | CodeViewer is an app to view highlighted code for projects in a given root folder. 8 | This is actual project code for active projects. 9 | `, 10 | note3: ` 11 | Gallery notes 12 | `, 13 | note4: ` 14 | Clippets is what I use to store snippets of text. It is mostly used for things I don't do every day. 15 | For instance setting up a DigitalOcean server. 16 | ` 17 | }; 18 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/ProgressBar/app.text.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | p1Text: ` 3 | 4 | ` 5 | }; 6 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/ProgressBar/progress.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import AppNotes from '../common/app.notes'; 4 | import AppText from './app.text'; 5 | 6 | import JButton from '../common/Button/jButton'; 7 | import JProgressBar from '../common/ProgressBar/jProgressBar'; 8 | 9 | let ProgressBarSty = { 10 | borderBottom: '3px solid #636b46', 11 | padding: '0 10px 0 0' 12 | }; 13 | 14 | let customCountSty = { 15 | backgroundColor: '#33045B', 16 | height: '5px', 17 | marginRight: '5px', 18 | marginTop: '6px', 19 | width: '100%' 20 | }; 21 | 22 | let customIndexSty = {backgroundColor: '#874C08', height: '5px', width: '1%'}; 23 | let assignSty = {color: '#4d2c3d'}; 24 | 25 | let firstItemBtn = {buttonid: 'first', icon: 'fa fa-fast-backward fa-lg', style: 'BtnImg', assignStyle: assignSty}; 26 | let previousItemBtn = {buttonid: 'previous', icon: 'fa fa-backward fa-lg', style: 'BtnImg', assignStyle: assignSty}; 27 | 28 | let nextItemBtn = {buttonid: 'next', icon: 'fa fa-forward fa-lg', style: 'BtnImg', assignStyle: assignSty}; 29 | let lastItemBtn = {buttonid: 'last', icon: 'fa fa-fast-forward fa-lg', style: 'BtnImg', assignStyle: assignSty}; 30 | 31 | let ButtonAreaSty = { 32 | fontSize: '.9em', 33 | height: '24px', 34 | marginBottom: '10px', 35 | marginTop: '10px', 36 | verticalAlign: 'middle' 37 | }; 38 | 39 | let progressData = {count: 120}; 40 | 41 | export default class ProgressBar extends React.Component { 42 | state = {progressIndex: 10}; 43 | clickHandler = (buttonid) => { 44 | let oldIndex = this.state.progressIndex; 45 | let newIndex = oldIndex; 46 | switch (buttonid) { 47 | case 'first': newIndex = 1; break; 48 | case 'previous': newIndex -= oldIndex > 1 ? 1 : 0; break; 49 | case 'next': newIndex += oldIndex < progressData.count ? 1 : 0; break; 50 | case 'last': newIndex = progressData.count; break; 51 | } 52 | this.setState({progressIndex: newIndex}); 53 | }; 54 | render() { 55 | if (this.props.hide) return null; 56 | progressData.index = this.state.progressIndex; 57 | return ( 58 |
59 |

60 |
default

61 | 62 |
center

63 | 64 |
after

65 | 66 |
before

67 | 68 |
beforenafter

69 | 70 |
none

71 | 72 |
indexColor

73 | 74 |
countColor

75 | 76 |
customStyle

77 | 78 |

79 |
80 | 81 |   82 | 83 | 84 |   85 | 86 |
87 | 88 |
89 | ); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/Sliders/app.text.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | p1Text: ` 3 | 4 | ` 5 | }; 6 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/Sliders/sliders.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import AppNotes from '../common/app.notes'; 4 | import AppText from './app.text'; 5 | 6 | import RangeSelector from '../common/Sliders/jRangeSelector'; 7 | import SimpleSlider from '../common/Sliders/jSlider'; 8 | 9 | let slidersSty = { 10 | backgroundColor: '#e1ded5', 11 | borderBottom: '3px solid #636b46', 12 | margin: '5px auto', 13 | maxWidth: '900px', 14 | padding: '10px' 15 | }; 16 | 17 | let innerSty = { 18 | width: '100%' 19 | }; 20 | 21 | const formatter = value => Math.ceil((value * 39) - 5); 22 | const unformatter = value => Math.ceil(((value + 4) / 39) * 100) / 100; 23 | 24 | let getInitialAppState = function() { 25 | return { 26 | formattedValue: 34, 27 | lowerValue: 1, 28 | upperValue: 85 29 | }; 30 | }; 31 | 32 | export default class Sliders extends React.Component { 33 | state = getInitialAppState(); 34 | _handleSliderChange = (formattedValue) => { this.setState({formattedValue}); } 35 | _handleLowerChange = (lowerValue) => { this.setState({lowerValue}); } 36 | _handleUpperChange = (upperValue) => { this.setState({upperValue}); } 37 | _resetState = () => { this.setState(getInitialAppState()); } 38 | render() { 39 | if (this.props.hide) return null; 40 | let formattedValue = this.state.formattedValue; 41 | let percentValue = unformatter(formattedValue); 42 | let lowerValue = this.state.lowerValue; 43 | let upperValue = this.state.upperValue; 44 | return ( 45 |
46 |
47 |
48 |
Lower Value: {lowerValue}
49 |
Upper Value: {upperValue}
50 | 62 |
63 |
64 |
Value -5 - 34: {formattedValue}
65 |
66 | 72 |
73 |
74 |

75 | 76 |

77 |

78 | 79 |
80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/Tooltip/app.text.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | p1Text: ` 3 | 4 | ` 5 | }; 6 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/Tooltip/tooltip.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import AppNotes from '../common/app.notes'; 4 | import AppText from './app.text'; 5 | 6 | import JTooltip from '../common/Tooltip/jTooltip'; 7 | 8 | let TooltipSty = { 9 | borderBottom: '3px solid #636b46', 10 | padding: '0 10px' 11 | }; 12 | 13 | let columnSty = { 14 | height: 'calc(100% - 10px)', 15 | overflow: 'auto', 16 | paddingLeft: '0px', 17 | width: '330px' 18 | }; 19 | 20 | let titleSty = { 21 | background: 'transparent', 22 | boxSizing: 'border-box', 23 | cursor: 'default', 24 | height: '18px', 25 | lineHeight: '18px', 26 | overflow: 'hidden', 27 | outline: 'none', 28 | position: 'relative', 29 | textAlign: 'left', 30 | transition: 'all 200ms ease', 31 | width: '100%' 32 | }; 33 | 34 | let toolTipSty = {display: 'inline-block', zIndex: '100'}; 35 | let titleDivSty = {display: 'inline-block', lineHeight: '18px', position: 'relative'}; 36 | 37 | let fillText = ` 38 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 39 | `; 40 | 41 | let hoverValues = [ 42 | {title: 'LowTemp', text: fillText.repeat(Math.ceil(Math.random() * 2)), place: 'bottom'}, 43 | {title: 'LeafType', text: fillText.repeat(Math.ceil(Math.random() * 2)), place: 'bottom'}, 44 | {title: 'Height', text: fillText.repeat(Math.ceil(Math.random() * 2)), place: 'bottom'}, 45 | {title: 'Width', text: fillText.repeat(Math.ceil(Math.random() * 2)), place: 'bottom'}, 46 | {title: 'TrunkType', text: fillText.repeat(Math.ceil(Math.random() * 2)), place: 'right'}, 47 | {title: 'SunExposure', text: fillText.repeat(Math.ceil(Math.random() * 2)), place: 'right'}, 48 | {title: 'WaterTolerance', text: fillText.repeat(Math.ceil(Math.random() * 2)), place: 'right'}, 49 | {title: 'BogTolerant', text: fillText.repeat(Math.ceil(Math.random() * 2)), place: 'top'}, 50 | {title: 'DraughtTolerant', text: fillText.repeat(Math.ceil(Math.random() * 2)), place: 'top'}, 51 | {title: 'GrowthSpeed', text: fillText.repeat(Math.ceil(Math.random() * 2)), place: 'top'}, 52 | {title: 'DryAirTolerance', text: fillText.repeat(Math.ceil(Math.random() * 2)), place: 'top'} 53 | ]; 54 | 55 | function hoverMap(item) { 56 | let adjust = {left: 0, top: 0}; 57 | 58 | let tooltip =
; 59 | return ( 60 |
61 | {tooltip} 62 |
63 |
64 | {item.title}: 65 |
66 |
67 |
68 | ); 69 | } 70 | 71 | export default function Tooltip(props) { 72 | let hoverList = hoverValues.map(hoverMap); 73 | if (props.hide) return null; 74 | return ( 75 |
76 |


77 |
78 | {hoverList} 79 |
80 | 81 |
82 | ); 83 | } 84 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/TreeViews/app.text.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | p1Text: ` 3 | 4 | ` 5 | }; 6 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/TreeViews/jumplist/jump.ctrl.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import JTreeViewB from '../../common/TreeViews/jTreeViewB'; 4 | 5 | const options = { 6 | icon: {sun: 1, leaf: 2, snow: 3}, 7 | typeName: ['node', 'nodeLevel'] 8 | }; 9 | 10 | export default function JumpCtrl({imageList, clickHandler}) { 11 | return ( 12 |
13 | 14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/TreeViews/treeview.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | 4 | import AppNotes from '../common/app.notes'; 5 | import AppText from './app.text'; 6 | 7 | import JumpCtrl from './jumplist/jump.ctrl'; 8 | import TreeCtrl from './treeview/tree.ctrl'; 9 | 10 | 11 | let TreeViewsSty = { 12 | height: '100%', 13 | padding: '0 10px 0 0' 14 | }; 15 | 16 | let TreeCtrlSty = { 17 | border: 'solid 1px darkslategrey', 18 | height: 'calc(100% - 10px)', 19 | overflow: 'auto', 20 | paddingLeft: '0px', 21 | width: '50%' 22 | }; 23 | 24 | class TreeViews extends React.Component { 25 | state = {currentImageItem: {title: 'not selected'}}; 26 | jumpclick = (node) => { this.setState({currentImageItem: node});}; 27 | render() { 28 | if (this.props.hide) return null; 29 | let currentTreeNode = this.props.currentTreeNode.title; 30 | let currentImageItem = this.state.currentImageItem.title; 31 | return ( 32 |
33 |
34 |
35 | current node: {currentTreeNode} 36 |
37 | 38 |
39 |
40 | current node: {currentImageItem} 41 |
42 | 43 |
44 |
45 | 46 |
47 | ); 48 | } 49 | } 50 | 51 | function mapStateToProps(store) { 52 | return { 53 | imageList: store.treeState.jumpList, 54 | treeData: store.treeState.treeData, 55 | currentTreeNode: store.treeState.currentTreeNode, 56 | showTreeEdit: store.treeState.showTreeEdit, 57 | showTreeNew: store.treeState.showTreeNew 58 | }; 59 | } 60 | 61 | export default connect(mapStateToProps)(TreeViews); 62 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/TreeViews/treeview/tree.ctrl.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | 4 | import {apiSetTreeView} from '../../../store/api/api.Actions'; 5 | import TreeList from './tree.list'; 6 | import TreeMenu from './tree.menu'; 7 | import TreeEdit from './tree.edit'; 8 | import TreeNew from './tree.new'; 9 | 10 | let TreeCtrlRenderSty = {height: 'calc(100% - 19px)'}; 11 | 12 | class TreeCtrl extends React.Component { 13 | componentWillReceiveProps = (nextProps) => { 14 | if (nextProps.treeData && (nextProps.treeData !== this.props.treeData)) { 15 | apiSetTreeView({data: nextProps.treeData}); 16 | } 17 | } 18 | render() { 19 | let hideTreeEdit = !this.props.showTreeEdit; 20 | let hideTreeNew = !this.props.showTreeNew; 21 | return ( 22 |
23 | 24 | 25 | 26 | 27 |
28 | ); 29 | } 30 | } 31 | 32 | function mapStateToProps(store) { 33 | return { 34 | treeData: store.treeState.treeData, 35 | currentTreeNode: store.treeState.currentTreeNode, 36 | showTreeEdit: store.treeState.showTreeEdit, 37 | showTreeNew: store.treeState.showTreeNew 38 | }; 39 | } 40 | 41 | export default connect(mapStateToProps)(TreeCtrl); 42 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/TreeViews/treeview/tree.detail.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import JInput from '../../common/FormInput/jInput'; 4 | 5 | let treeDetailSty = {margin: '10px 10px'}; 6 | let inputTextSty = {color: 'black', margin: '0 5px', width: '100%'}; 7 | 8 | let titleInput = {name: 'title', type: 'text', style: inputTextSty, focus: true}; 9 | 10 | let radioInput1 = {name: 'radioGroup', type: 'radio', radioValue: 'dev'}; 11 | let radioInput2 = {name: 'radioGroup', type: 'radio', radioValue: 'home'}; 12 | let radioInput3 = {name: 'radioGroup', type: 'radio', radioValue: 'sys'}; 13 | 14 | export default class TreeDetail extends React.Component { 15 | state = {title: 'Hello!'}; 16 | componentWillReceiveProps = (nextProps) => { 17 | if (this.state.title != nextProps.treeNode.title) this.setState({title: nextProps.treeNode.title}); 18 | }; 19 | handleTitleChange = (name, value) => { this.props.handleChange(name, value); }; 20 | handleValueChange = (name, value) => { this.props.handleChange('type', value); }; 21 | render() { 22 | titleInput.textValue = this.props.treeNode.title; 23 | 24 | let currentRadioGroupValue = this.props.treeNode.type; 25 | radioInput1.radioChecked = (currentRadioGroupValue == radioInput1.radioValue); 26 | radioInput2.radioChecked = (currentRadioGroupValue == radioInput2.radioValue); 27 | radioInput3.radioChecked = (currentRadioGroupValue == radioInput3.radioValue); 28 | return ( 29 |
30 |  Dev   31 |  Home   32 |  System   33 |

34 |
35 |
36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/TreeViews/treeview/tree.edit.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | import {bindActionCreators} from 'redux'; 4 | 5 | import TreeDetail from './tree.detail'; 6 | import {treeActions, saveTreeEdit} from '../../../store/treeview/tree.Actions'; 7 | import JButton from '../../common/Button/jButton'; 8 | 9 | let saveEditBtn = {buttonid: 'save', text: 'Save'}; 10 | let cancelEditBtn = {buttonid: 'cancel', text: 'Cancel'}; 11 | 12 | class TreeEdit extends React.Component { 13 | state = {treeNode: {nodeid: '', children: [], title: '', type: ''}}; 14 | 15 | componentWillReceiveProps = (nextProps) => { this.setState({treeNode: nextProps.treeNode}); }; 16 | clickHandler = (buttonid) => { 17 | let node = this.state.treeNode; 18 | switch (buttonid) { 19 | case 'save': this.props.saveTreeEdit(node); break; 20 | case 'cancel': this.props.treeActions('cancelEdit'); break; 21 | } 22 | }; 23 | handleChange = (field, value) => { 24 | let node = this.state.treeNode; 25 | if (field == 'title') node.title = value; 26 | if (field == 'type') node.type = value; 27 | this.setState({treeNode: node}); 28 | }; 29 | render() { 30 | if (this.props.hide) return null; 31 | return ( 32 |
33 |
34 | 35 | 36 |
37 | 38 |
39 | ); 40 | } 41 | } 42 | 43 | function mapDispatchToProps(dispatch) { 44 | return bindActionCreators({treeActions, saveTreeEdit}, dispatch); 45 | } 46 | 47 | export default connect(null, mapDispatchToProps)(TreeEdit); 48 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/TreeViews/treeview/tree.list.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | import {bindActionCreators} from 'redux'; 4 | 5 | import {selectTreeNode, setTreeNodeClosed} from '../../../store/treeview/tree.Actions'; 6 | import TreeView from '../../common/TreeViews/jTreeView'; 7 | 8 | const options = { 9 | icon: {sun: 'dev', leaf: 'home', snow: 'sys'}, 10 | typeName: ['node', 'type'] 11 | }; 12 | 13 | const TreeList = (props) => { 14 | const iconHandler = (node) => { props.setTreeNodeClosed(node); }; 15 | const clickHandler = (node) => { props.selectTreeNode(node); }; 16 | return ( 17 |
18 | 24 |
25 | ); 26 | }; 27 | 28 | function mapDispatchToProps(dispatch) { 29 | return bindActionCreators({selectTreeNode, setTreeNodeClosed}, dispatch); 30 | } 31 | 32 | export default connect(null, mapDispatchToProps)(TreeList); 33 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/TreeViews/treeview/tree.menu.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | import {bindActionCreators} from 'redux'; 4 | 5 | import {treeActions} from '../../../store/treeview/tree.Actions'; 6 | import JButton from '../../common/Button/jButton'; 7 | 8 | const TreeMenuSty = { 9 | fontSize: '.9em', 10 | height: '40px', 11 | marginBottom: '10px', 12 | textAlign: 'center', 13 | verticalAlign: 'middle' 14 | }; 15 | 16 | const newBtn = {buttonid: 'new', icon: 'fa fa-file-text-o fa-2x', style: 'BtnImg', assignStyle: {color: '#419079'}}; 17 | const editBtn = {buttonid: 'edit', icon: 'fa fa-pencil fa-2x', style: 'BtnImg'}; 18 | const moveUpBtn = {buttonid: 'moveUp', icon: 'fa fa-arrow-up fa-2x', style: 'BtnImg'}; 19 | const moveDownBtn = {buttonid: 'moveDown', icon: 'fa fa-arrow-down fa-2x', style: 'BtnImg'}; 20 | const removeBtn = {buttonid: 'remove', icon: 'fa fa-trash-o fa-2x', style: 'BtnImg'}; 21 | 22 | class TreeMenu extends React.Component { 23 | onSelect = (btn) => { this.props.treeActions(btn); }; 24 | render() { 25 | return ( 26 |
27 | 28 |   29 | 30 |      31 | 32 |   33 | 34 |      35 | 36 |
37 | ); 38 | } 39 | } 40 | 41 | function mapDispatchToProps(dispatch) { 42 | return bindActionCreators({treeActions}, dispatch); 43 | } 44 | 45 | export default connect(null, mapDispatchToProps)(TreeMenu); 46 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/TreeViews/treeview/tree.new.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | import {bindActionCreators} from 'redux'; 4 | 5 | import TreeDetail from './tree.detail'; 6 | import {saveTreeNew, treeActions} from '../../../store/treeview/tree.Actions'; 7 | import JButton from '../../common/Button/jButton'; 8 | 9 | let newBeforeBtn = {buttonid: 'before', text: 'New Before', assignStyle: {width: '92px'}}; 10 | let newAfterBtn = {buttonid: 'after', text: 'New After', assignStyle: {width: '92px'}}; 11 | let newChildBtn = {buttonid: 'child', text: 'New Child', assignStyle: {width: '92px'}}; 12 | let cancelNewBtn = {buttonid: 'cancel', text: 'Cancel', assignStyle: {width: '92px'}}; 13 | 14 | class TreeNew extends React.Component { 15 | state = {treeNode: {nodeid: '', title: '', type: 'dev', selected: false, children: []}}; 16 | clickHandler = (buttonid) => { 17 | switch (buttonid) { 18 | case 'before': 19 | case 'after': 20 | case 'child': this.props.saveTreeNew(this.state.treeNode, buttonid); break; 21 | case 'cancel': this.props.treeActions('cancelNew'); break; 22 | } 23 | }; 24 | handleChange = (field, value) => { 25 | let node = this.state.treeNode; 26 | if (field == 'title') node.title = value; 27 | if (field == 'type') node.type = value; 28 | this.setState({treeNode: node}); 29 | }; 30 | render() { 31 | if (this.props.hide) return null; 32 | return ( 33 |
34 |
35 |
36 |
37 | 38 | 39 |
40 |
41 | 42 | 43 |
44 |
45 |
46 | 47 |
48 | ); 49 | } 50 | } 51 | 52 | function mapDispatchToProps(dispatch) { 53 | return bindActionCreators({saveTreeNew, treeActions}, dispatch); 54 | } 55 | 56 | export default connect(null, mapDispatchToProps)(TreeNew); 57 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/app.ctrl.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | 4 | import NavBar from './common/nav.bar'; 5 | 6 | import Button from './Button/button.page'; 7 | import DropDowns from './DropDowns/dropdown.page'; 8 | import FormInput from './FormInput/input.page'; 9 | import Gallery from './Gallery/gallery.page'; 10 | import List from './List/list.page'; 11 | import PageIndicator from './PageIndicator/indicator.page'; 12 | import ProgressBar from './ProgressBar/progress.page'; 13 | import Sliders from './Sliders/sliders.page'; 14 | import Tooltip from './Tooltip/tooltip.page'; 15 | import TreeViews from './TreeViews/treeview.page'; 16 | 17 | let AppCtrlSty = { 18 | height: '100%', 19 | margin: '0px', 20 | overflow: 'hidden', 21 | padding: '0px', 22 | width: '100%' 23 | }; 24 | 25 | function AppCtrl({appState}) { 26 | let page = appState.currentPage; 27 | 28 | let hideButton = (page != 'Button'); 29 | let hideDropDowns = (page != 'DropDowns'); 30 | let hideFormInput = (page != 'FormInput'); 31 | let hideGallery = (page != 'Gallery'); 32 | let hideList = (page != 'List'); 33 | let hidePageIndicator = (page != 'PageIndicator'); 34 | let hideProgressBar = (page != 'ProgressBar'); 35 | let hideSliders = (page != 'Sliders'); 36 | let hideTooltip = (page != 'Tooltip'); 37 | let hideTreeViews = (page != 'TreeViews'); 38 | 39 | return ( 40 |
41 | 42 |
53 | ); 54 | } 55 | 56 | function mapStateToProps(store) { return {appState: store.appState}; } 57 | 58 | export default connect(mapStateToProps)(AppCtrl); 59 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/common/DropDowns/Icon.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | class Icon extends React.Component { 4 | 5 | styles = () => { 6 | return { 7 | component: Object.assign({ 8 | width: this.props.size, 9 | height: this.props.size, 10 | display: 'inline-block', 11 | verticalAlign: 'middle' 12 | }, this.props.style) 13 | }; 14 | } 15 | 16 | render() { 17 | const {elementProps} = this.props; 18 | const styles = this.styles(); 19 | 20 | return ( 21 | 28 | 29 | 34 | 40 | 41 | 42 | ); 43 | } 44 | } 45 | 46 | Icon.propTypes = { 47 | elementProps: React.PropTypes.object, 48 | size: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]), 49 | style: React.PropTypes.object, 50 | type: React.PropTypes.string 51 | }; 52 | 53 | Icon.defaultProps = { 54 | elementProps: {}, 55 | size: 24, 56 | type: 'accounts' 57 | }; 58 | 59 | module.exports = Icon; 60 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/common/DropDowns/jDropMenu.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | let DropdownSty = {position: 'relative'}; 4 | 5 | let DropdownControlSty = { 6 | position: 'relative', 7 | overflow: 'hidden', 8 | background: 'transparent', 9 | boxSizing: 'border-box', 10 | cursor: 'default', 11 | outline: 'none', 12 | padding: '5px 5px', 13 | textAlign: 'right', 14 | transition: 'all 200ms ease', 15 | width: '100%' 16 | }; 17 | 18 | let DropdownMenuSty = { 19 | backgroundColor: '#261a3b', 20 | boxShadow: '0 1px 0 rgba(0, 0, 0, 0.06)', 21 | boxSizing: 'border-box', 22 | fontSize: '.9em', 23 | lineHeight: '150%', 24 | marginTop: '-1px', 25 | maxHeight: '300px', 26 | overflowY: 'auto', 27 | padding: '8px 12px', 28 | position: 'absolute', 29 | right: '0px', 30 | top: '100%', 31 | zIndex: '200' 32 | }; 33 | 34 | let DropdownSeperatorSty = { 35 | backgroundColor: '#000000', 36 | height: '3px', 37 | margin: '3px 0', 38 | width: '100%' 39 | }; 40 | 41 | let DropdownOptionSty = { 42 | boxSizing: 'border-box', 43 | color: '#EEFFEE', 44 | cursor: 'pointer', 45 | display: 'block' 46 | }; 47 | 48 | class JDropMenu extends React.Component { 49 | state = {isOpen: false, selected: {}}; 50 | setValue = (e) => { 51 | let selectedOption = this.props.options[parseInt(e.target.id)]; 52 | this.props.onChange(selectedOption); 53 | this.setState({isOpen: false}); 54 | }; 55 | handleMouseDown = (event) => { 56 | if (event.type == 'mousedown' && event.button !== 0) return; 57 | event.stopPropagation(); 58 | event.preventDefault(); 59 | this.setState({isOpen: !this.state.isOpen}); 60 | }; 61 | render() { 62 | let items = this.props.options.map((option, index) => { 63 | if (option.type == 'seperator') { 64 | return (
); 65 | } else { 66 | return ( 67 |
{option.label}
73 | ); 74 | } 75 | }); 76 | 77 | let value = (); 78 | let menu = this.state.isOpen ?
{items}
: null; 79 | 80 | return ( 81 |
82 |
83 | {value} 84 |
85 | {menu} 86 |
87 | ); 88 | } 89 | } 90 | 91 | JDropMenu.propTypes = { 92 | options: React.PropTypes.array.isRequired, 93 | onChange: React.PropTypes.func.isRequired 94 | }; 95 | 96 | module.exports = JDropMenu; 97 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/common/Gallery/gallery.style.js: -------------------------------------------------------------------------------- 1 | let backgroundSize = 'contain'; 2 | let dropShadow = '0 1px 0px #333, 1px 0 0px #333, 1px 2px 1px #333, 2px 1px 1px #333, 2px 3px 2px #333'; 3 | 4 | module.exports = { 5 | GallerySty: { 6 | backgroundColor: 'grey', 7 | color: 'white', 8 | height: '100vh', 9 | left: '0px', 10 | padding: '0 10px 0 0', 11 | position: 'absolute', 12 | top: '0px', 13 | width: '100vw' 14 | }, 15 | imageDivSty: { 16 | backgroundPosition: 'center center', 17 | backgroundRepeat: 'no-repeat', 18 | backgroundSize, 19 | height: '100%', 20 | MozBackgroundSize: backgroundSize, 21 | OBackgroundSize: backgroundSize, 22 | overflow: 'hidden', 23 | padding: '0px', 24 | position: 'relative', 25 | WebkitBackgroundSize: backgroundSize, 26 | width: '100%' 27 | }, 28 | imageThumbSty: {position: 'relative', height: '100%', width: '100%'}, 29 | actionSty: {position: 'relative', height: '100%', width: '100%'}, 30 | fullCloseSty: {position: 'absolute', left: '15px', top: '5px'}, 31 | nextSty: {position: 'absolute', right: '25px', top: '50%'}, 32 | prevSty: {position: 'absolute', left: '25px', top: '50%'}, 33 | thumbsOpenSty: {position: 'absolute', right: '25px', top: '5px'}, 34 | thumbsClosedSty: {color: '#afac87', position: 'absolute', right: '25px', top: '0px'}, 35 | nextPanelSty: {height: '80vh', position: 'absolute', right: '0px', top: '10vh', width: '75%'}, 36 | prevPanelSty: {height: '80vh', position: 'absolute', left: '0px', top: '10vh', width: '25%'}, 37 | copyRightSty: { 38 | position: 'absolute', color: '#777', right: '5px', top: '75%', fontSize: '.8em', 39 | writingMode: 'vertical-rl', textShadow: dropShadow 40 | }, 41 | statusSty: {color: 'black', fontSize: '1.5em', position: 'absolute', textAlign: 'center', top: '5px', width: '100%'} 42 | }; 43 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/common/Gallery/jThumbs.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import ListItem from './listitem'; 4 | 5 | let thumbColumnSty = { 6 | boxSizing: 'border-box', 7 | flexGrow: '1', 8 | height: '100%', 9 | margin: '0px', 10 | maxWidth: '10%', 11 | overflowY: 'auto', 12 | overflowX: 'hidden', 13 | padding: '0px 10px', 14 | textAlign: 'center' 15 | }; 16 | 17 | let thumbRowSty = { 18 | maxHeight: '13vh', 19 | margin: '10px 0px 5px', 20 | overflowY: 'hidden', 21 | overflowX: 'auto', 22 | padding: '0px', 23 | width: '100%', 24 | whiteSpace: 'nowrap' 25 | }; 26 | 27 | function listMap(item, index) { 28 | return ( 29 | 36 | ); 37 | } 38 | 39 | class ThumbColumn extends React.Component { 40 | componentWillReceiveProps = () => { 41 | if (!this.props.hide) this.thumbDiv.scrollTop = 0; 42 | }; 43 | setThumbDivRef = (node) => this.thumbDiv = node; 44 | afterScroll = () => { 45 | let thisElement = this.thumbDiv; 46 | let thisElementScrollTop = thisElement.scrollTop; 47 | if (thisElement.scrollHeight - thisElementScrollTop != thisElement.clientHeight) { 48 | thisElement.scrollTop = thisElementScrollTop - 300; 49 | } 50 | }; 51 | render() { 52 | if (this.props.hide) return null; 53 | let children = this.props.data.list.map(listMap, this); 54 | let ThumbColumnSty; 55 | if (this.props.thumbColumn) ThumbColumnSty = Object.assign({}, thumbColumnSty); 56 | else ThumbColumnSty = Object.assign({}, thumbRowSty); 57 | return ( 58 |
59 | {children} 60 |
61 | ); 62 | } 63 | } 64 | 65 | ThumbColumn.propTypes = { 66 | data: React.PropTypes.object.isRequired, 67 | hide: React.PropTypes.bool, 68 | close: React.PropTypes.func 69 | }; 70 | 71 | module.exports = ThumbColumn; 72 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/common/Gallery/listitem.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | let ThumbColumnItemSty = { 4 | background: 'transparent', 5 | backgroundPosition: 'center center', 6 | backgroundRepeat: 'no-repeat', 7 | backgroundSize: 'contain', 8 | marginBottom: '10px', 9 | marginRight: 'auto', 10 | marginLeft: 'auto', 11 | textAlign: 'center', 12 | width: 'calc(100% - 4px)' 13 | }; 14 | 15 | let ThumbRowItemSty = { 16 | background: 'transparent', 17 | display: 'inline-block', 18 | verticalAlign: 'middle' 19 | }; 20 | 21 | let thumbImageSty = { 22 | display: 'block', 23 | marginRight: 'auto', 24 | marginLeft: 'auto', 25 | maxWidth: 'calc(100% - 6px)', 26 | maxHeight: 'calc(13vh - 41px)', 27 | width: 'auto', 28 | height: 'auto' 29 | }; 30 | 31 | class ListItem extends React.Component { 32 | componentDidUpdate = () => { 33 | if ((this.props.index == this.props.selected)) { 34 | this.refName.scrollIntoView({behavior: 'smooth'}); 35 | this.props.afterScroll(); 36 | } 37 | }; 38 | clickHandler = () => { this.props.clickHandler(this.props.index); }; 39 | render() { 40 | let thumbColumnImgBorder; 41 | if (this.props.index == this.props.selected) thumbColumnImgBorder = '3px solid rgb(220, 112, 24)'; 42 | else thumbColumnImgBorder = '3px solid transparent'; 43 | 44 | let ThumbDivSty; 45 | if (this.props.thumbColumn) ThumbDivSty = Object.assign({}, ThumbColumnItemSty); 46 | else ThumbDivSty = Object.assign({}, ThumbRowItemSty); 47 | // ThumbDivSty.backgroundImage = 'url(' + src + ')'; 48 | let ThumbImgSty = Object.assign({}, thumbImageSty); 49 | ThumbImgSty.border = thumbColumnImgBorder; 50 | let src = this.props.item.smFolder + this.props.item.FileName; 51 | return ( 52 |
this.refName = ref} style={ThumbDivSty} > 53 | 54 |
55 | ); 56 | } 57 | } 58 | 59 | ListItem.propTypes = { 60 | item: React.PropTypes.object.isRequired, 61 | thumbColumn: React.PropTypes.bool, 62 | index: React.PropTypes.number, 63 | selected: React.PropTypes.number, 64 | afterScroll: React.PropTypes.func 65 | }; 66 | 67 | module.exports = ListItem; 68 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/common/Gallery/shortcuts.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | let ShortcutsSty = { 4 | backgroundColor: '#333', 5 | border: '1px solid green', 6 | color: '#AAA', 7 | left: '10px', 8 | padding: '10px', 9 | position: 'absolute', 10 | top: '50px' 11 | }; 12 | 13 | let headSty = { 14 | color: '#e2d290', 15 | fontSize: '1.2em', 16 | textAlign: 'center' 17 | }; 18 | 19 | let keySty = { 20 | color: '#aaa', 21 | fontSize: '1em', 22 | textAlign: 'center', 23 | width: '30px' 24 | }; 25 | 26 | let descSty = { 27 | color: '#aaa', 28 | fontSize: '1em', 29 | textAlign: 'left' 30 | }; 31 | 32 | let okSty = { 33 | backgroundColor: '#222', 34 | cursor: 'pointer', 35 | padding: '5px 0px', 36 | textAlign: 'center', 37 | width: '100%' 38 | }; 39 | 40 | export default class Shortcuts extends React.Component { 41 | closeHandler = () => { this.props.closeHandler(); }; 42 | render() { 43 | if (this.props.hide) return null; 44 | return ( 45 |
46 |
Keyboard Shortcuts
47 |
48 |
49 |
50 | →
51 | ←
52 | T
53 | B
54 | S
55 | X
56 |
57 |
58 | Next pic
59 | Previous pic
60 | Side Thumbs
61 | Bottom Thumbs
62 | Full screen
63 | Exit
64 |
65 |
66 |
67 |
Ok
68 |
69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/common/List/jList.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | let listSty = {}; 4 | let listStyleDefault = {}; 5 | 6 | let lineSty = {}; 7 | let lineStyleDefault = { 8 | color: '#a7b3a5', 9 | marginLeft: '7px' 10 | }; 11 | 12 | function divMap(item, index) { 13 | return (
{item}
); 14 | } 15 | 16 | function spanMap(item, index) { 17 | return ({item}); 18 | } 19 | 20 | function JList({data, lineStyle, listStyle, spanLine}) { 21 | listSty = listStyle ? listStyle : listStyleDefault; 22 | lineSty = lineStyle ? lineStyle : lineStyleDefault; 23 | var list; 24 | if (spanLine) list = data.map(spanMap); 25 | else list = data.map(divMap); 26 | return ( 27 |
28 | {list} 29 |
30 | ); 31 | } 32 | 33 | module.exports = JList; 34 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/common/PageIndicator/jPageIndicator.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | const styles = { 4 | component: { 5 | textAlign: 'center', 6 | padding: '0', 7 | }, 8 | dot: { 9 | width: 9, 10 | height: 9, 11 | margin: 7, 12 | padding: 0, 13 | borderRadius: '100%', 14 | display: 'inline-block', 15 | verticalAlign: 'middle', 16 | backgroundColor: '#fff', 17 | cursor: 'pointer' 18 | }, 19 | dotActive: { 20 | backgroundColor: '#b4dbc0' 21 | } 22 | }; 23 | 24 | const PageIndicator = (props) => { 25 | 26 | const _handleDotClick = (e) => { if (props.onClick) props.onClick(parseInt(e.target.id)); }; 27 | 28 | const _renderDots = () => { 29 | const dots = []; 30 | 31 | for (let i = 0; i < props.count; i++) { 32 | const dotStyles = props.activeIndex === i ? Object.assign({}, styles.dot, styles.dotActive) : styles.dot; 33 | dots.push(); 34 | } 35 | return dots; 36 | }; 37 | 38 | let renderedDots = _renderDots(); 39 | 40 | return ( 41 |
42 | {renderedDots} 43 |
44 | ); 45 | }; 46 | 47 | PageIndicator.propTypes = { 48 | activeIndex: React.PropTypes.number, 49 | count: React.PropTypes.number.isRequired, 50 | onClick: React.PropTypes.func 51 | }; 52 | 53 | module.exports = PageIndicator; 54 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/common/ProgressBar/jProgressBar.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | let defaultCountSty = { 4 | backgroundColor: '#4d2c3d', 5 | height: '12px', 6 | marginRight: '5px', 7 | marginTop: '4px', 8 | width: '100%' 9 | }; 10 | 11 | let defaultIndexSty = {backgroundColor: '#ab9353', height: '6px', borderTop: '3px solid #4d2c3d', width: '1%'}; 12 | let centerSty = {color: '#e9e7da', marginLeft: 'auto', marginRight: 'auto', marginTop: '-33px'}; 13 | let numberSty = {color: '#e9e7da'}; 14 | 15 | const JProgressBar = (props) => { 16 | if (!props.data) return null; 17 | let progressSty = {fontSize: '1em', width: '100%'}; 18 | let count = props.data.count; 19 | let index = props.data.index; 20 | let perc = index/count * 100; 21 | let percentage = perc > 50 ? Math.floor(perc) : Math.ceil(perc); 22 | 23 | let countSty = props.countSty ? Object.assign({}, props.countSty) : Object.assign({}, defaultCountSty); 24 | let indexSty = props.indexSty ? Object.assign({}, props.indexSty) : Object.assign({}, defaultIndexSty); 25 | indexSty.width = percentage + '%'; 26 | countSty.backgroundColor = props.countColor ? props.countColor : defaultCountSty.backgroundColor; 27 | indexSty.backgroundColor = props.indexColor ? props.indexColor : defaultIndexSty.backgroundColor; 28 | indexSty.borderTopColor = countSty.backgroundColor; 29 | 30 | let barRender = ( 31 |
32 |
33 |
34 | ); 35 | 36 | let progressRender = ''; 37 | let position = props.position ? props.position : 'center'; 38 | switch (position) { 39 | case 'center': progressRender = ( 40 |
41 | {barRender}
42 |
43 |
{index} / {count}
44 |
45 |
46 | ); break; 47 | case 'after': progressRender = ( 48 |
49 | {barRender} 50 | {index} / {count} 51 |
52 | ); break; 53 | case 'before': progressRender = ( 54 |
55 | {index} / {count}  56 | {barRender} 57 |
58 | ); break; 59 | case 'beforenafter': progressRender = ( 60 |
61 | {index}  62 | {barRender} 63 |  {count} 64 |
65 | ); break; 66 | case 'none': progressRender = ( 67 |
68 | {barRender} 69 |
70 | ); break; 71 | } 72 | return progressRender; 73 | }; 74 | 75 | module.exports = JProgressBar; 76 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/common/Tooltip/jTooltip.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | let TooltipSty = { 4 | display: 'inline-block', 5 | lineHeight: '14px', 6 | marginRight: '5px', 7 | verticalAlign: 'top' 8 | }; 9 | 10 | let helpTip = { 11 | background: '#5a5e5e', 12 | border: '1px solid #a3aaaa', 13 | borderRadius: '50%', 14 | boxShadow: '0 1px 2px rgba(0, 0, 0, 0.18)', 15 | boxSizing: 'border-box', 16 | color: '#fafafa', 17 | cursor: 'default', 18 | fontSize: '11px', 19 | height: '14px', 20 | lineHeight: '14px', 21 | marginTop: '1px', 22 | textAlign: 'center', 23 | width: '14px' 24 | }; 25 | 26 | let contentSty = { 27 | background: 'rgb(28, 34, 24)', 28 | border: '1px solid rgba(0, 0, 0, 0.08)', 29 | borderRadius: '3px', 30 | boxShadow: '0 2px 6px rgba(0, 0, 0, 0.2)', 31 | color: '#e9e7da', 32 | fontSize: '0.9375em', 33 | lineHeight: '1.2em', 34 | maxWidth: '280px', 35 | minWidth: '200px', 36 | padding: '5px', 37 | textAlign: 'left', 38 | wordWrap: 'break-word', 39 | zIndex: '200' 40 | }; 41 | 42 | let contentOuterSty = {height: '100%', width: '100%'}; 43 | 44 | function Contents({tooltipActive, place, position, data}) { 45 | if (!data) return null; 46 | let contentHtml = data; 47 | let contentLength = contentHtml.length; 48 | let topNeg = (Math.ceil(contentLength/40) + 1) * 18; 49 | let rightNeg = contentLength * .25; 50 | 51 | let active = tooltipActive; 52 | let inPosition = position || null; 53 | let contentInnerSty = {position: 'absolute'}; 54 | if (active) { 55 | switch (place) { 56 | case 'bottom': contentInnerSty.left = inPosition.right + 5; contentInnerSty.top = inPosition.top + 20; break; 57 | case 'right': contentInnerSty.left = inPosition.right + 5; contentInnerSty.top = inPosition.top - rightNeg; break; 58 | case 'top': contentInnerSty.left = inPosition.right + 5; contentInnerSty.top = inPosition.top - topNeg; break; 59 | } 60 | } 61 | else contentInnerSty.display = 'none'; 62 | let displayContent = {__html: contentHtml}; 63 | return ( 64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | ); 72 | } 73 | 74 | class JTooltip extends React.Component { 75 | state = {tooltipActive: false, position: {}}; 76 | onMouseEnter = () => { 77 | let rect = this.TooltipRef.getBoundingClientRect(); 78 | let position = {}; 79 | position.left = rect.left - this.props.adjust.left; 80 | position.top = rect.top - this.props.adjust.top; 81 | position.right = rect.right - this.props.adjust.left; 82 | position.bottom = rect.bottom - this.props.adjust.top; 83 | this.setState({tooltipActive: true, position}); 84 | }; 85 | onMouseLeave = () => { this.setState({tooltipActive: false}); }; 86 | render() { 87 | let help = '?'; 88 | return( 89 |
{ this.TooltipRef = ref; }} style={TooltipSty} > 90 |
91 |
{help}
92 |
93 | 99 |
100 | ); 101 | } 102 | } 103 | 104 | module.exports = JTooltip; 105 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/common/TreeViews/jTreeView.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import lodashGet from 'lodash/get'; 3 | 4 | let TreeRootSty = {lineHeight: '120%'}; 5 | let liSty = {listStyleType: 'none'}; 6 | let ulSty = {height: 'inherit', WebkitPaddingStart: '16px'}; 7 | let ulStyle = {height: 'inherit', WebkitPaddingStart: '16px'}; 8 | let iconSty = {marginRight: '10px', width: '16px'}; 9 | 10 | let nottogglable = { 11 | color: '#FFF', 12 | cursor: 'pointer', 13 | margin: '0 0 0 .8em' 14 | }; 15 | 16 | let inOptions = {}; 17 | let inCustomColors = {}; 18 | 19 | const defaultColors = { 20 | parent: '#AF90A5', 21 | parentSelected: '#7BB53B', 22 | endnode: '#afac87', 23 | endnodeSelected: '#b58900' 24 | }; 25 | 26 | const JTreeViewNode = (props) => { 27 | const iconHandler = () => { 28 | if (props.node.children && props.node.children.length > 0) { 29 | props.iconClick(props.node); 30 | } else { 31 | clickHandler(); 32 | } 33 | }; 34 | const clickHandler = () => { props.titleClick(props.node); }; 35 | let titleColors = inCustomColors ? inCustomColors : defaultColors; 36 | let titleSty = {marginTop: '2px'}; 37 | let childNodes; 38 | let pSty = nottogglable; 39 | 40 | if (props.node.children && props.node.children.length > 0) { 41 | childNodes = props.node.children.map((child, index) => { 42 | return ( 43 |
  • 44 | 45 |
  • 46 | ); 47 | }); 48 | titleSty.color = props.node.selected ? titleColors.parentSelected : titleColors.parent; 49 | } else { 50 | titleSty.color = props.node.selected ? titleColors.endnodeSelected : titleColors.endnode; 51 | } 52 | 53 | let isClosed = true; 54 | if (props.node.closed != null) isClosed = props.node.closed; 55 | 56 | let branch = ( 57 |
      58 | {childNodes} 59 |
    60 | ); 61 | if (isClosed) branch = null; 62 | 63 | let iconType = lodashGet(props, inOptions.typeName); 64 | if (iconType == inOptions.icon.sun) iconSty.background = 'url(\'./img/sun.ico\') 0/16px no-repeat'; 65 | else if (iconType == inOptions.icon.leaf) iconSty.background = 'url(\'./img/leaf.ico\') 0/16px no-repeat'; 66 | else if (iconType == inOptions.icon.snow) iconSty.background = 'url(\'./img/snow.ico\') 0/16px no-repeat'; 67 | else iconSty.background = 'url(\'./img/sun.ico\') 0/16px no-repeat'; 68 | 69 | return ( 70 |
    71 |
    72 |
     
    73 |
    74 | {props.node.title} 75 |
    76 |
    77 | {branch} 78 |
    79 | ); 80 | }; 81 | 82 | function JTreeView({data, options, iconClick, titleClick, customColors}) { 83 | inOptions = options; 84 | inCustomColors = customColors; 85 | let childNodes = data.map((child, index) => { 86 | return ( 87 |
  • 88 | 89 |
  • 90 | ); 91 | }); 92 | return ( 93 |
    94 |
      95 | {childNodes} 96 |
    97 |
    98 | ); 99 | } 100 | 101 | module.exports = JTreeView; 102 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/common/app.colors.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | morning_sky: '#cae4db', 3 | honey: '#dcae1d', 4 | cerulean: '#00303f', 5 | mist: '#7a9d96', 6 | 7 | bluebell: '#155765', 8 | olive: '#57652a', 9 | ornate: '#ab9353', 10 | plum: '#4d2c3d', 11 | 12 | gold: '#cda34f', 13 | daisy: '#e9e7da', 14 | stem: '#636b46', 15 | greenery: '#373f27', 16 | 17 | aqua: '#6bbaa7', 18 | sunshine: '#fba100', 19 | lavender: '#6c648b', 20 | dusty_rose: '#b6a19e', 21 | 22 | rust: '#b56357', 23 | mint: '#b4dbc0', 24 | slate: '#eae3ea', 25 | sea_foam: '#a7b3a5', 26 | 27 | white: '#fff', 28 | black: '#000' 29 | }; 30 | -------------------------------------------------------------------------------- /React.Common/ui-src/components/common/app.notes.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const AppNotesSty = { 4 | marginLeft: 'auto', 5 | marginRight: 'auto', 6 | marginTop: '30px', 7 | maxWidth: '500px', 8 | textIndent: '20px' 9 | }; 10 | 11 | const textSty = { 12 | color: '#FFF', 13 | fontSize: '1.0em', 14 | textAlign: 'left' 15 | }; 16 | 17 | const btnDivSty = {textAlign: 'center'}; 18 | 19 | const standardBtnSty = { 20 | backgroundColor: '#9a6', 21 | borderBottomColor: '#cea', 22 | borderLeftColor: '#93a363', 23 | borderRightColor: '#cea', 24 | borderTopColor: '#93a363', 25 | borderRadius: '6px', 26 | color: '#eeffee', 27 | cursor: 'pointer', 28 | lineHeight: '100%', 29 | outline: 'none', 30 | verticalAlign: 'middle', 31 | whiteSpace: 'nowrap' 32 | }; 33 | 34 | export default class AppNotes extends React.Component { 35 | state = {show: true}; 36 | onClick = () => { this.setState({show: !this.state.show}); }; 37 | render() { 38 | if (this.props.AppText.trim().length === 0) return null; 39 | let showNotes = this.state.show; 40 | let btnText = showNotes ? 'Hide notes' : 'Show notes'; 41 | let notesDivSty = showNotes ? {display: 'block'} : {display: 'none'}; 42 | return ( 43 |
    44 |
    45 | 46 |
    47 |
    48 |

    {this.props.AppText}

    49 |
    50 |
    51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /React.Common/ui-src/css/index.css: -------------------------------------------------------------------------------- 1 | .bodyStyle { 2 | background-color: #00303f; 3 | color: #eae3ea; 4 | display: block; 5 | height: 100%; 6 | overflow: hidden; 7 | width: 100%; 8 | } 9 | 10 | .header { 11 | height: 30px; 12 | margin: 0; 13 | padding: 10px 0; 14 | text-align: center; 15 | } 16 | 17 | .Title {font-size: 1.3em;} 18 | 19 | .content { 20 | height: 100%; 21 | padding: 0 5px; 22 | } 23 | 24 | .contentPage { 25 | margin: 5px auto; 26 | max-width: 1366px; 27 | } 28 | 29 | * { outline: none; } 30 | 31 | .a{display:block} 32 | 33 | .FlexBox { 34 | display: -webkit-box; 35 | display: -moz-box; 36 | display: -ms-flexbox; 37 | display: flex; 38 | } 39 | 40 | .FlexBoxC { 41 | display: -webkit-box; 42 | display: -moz-box; 43 | display: -ms-flexbox; 44 | display: flex; 45 | flex-direction: column; 46 | } 47 | 48 | .FlexBoxCenter { 49 | display: -webkit-box; 50 | display: -moz-box; 51 | display: -ms-flexbox; 52 | display: flex; 53 | justify-content: center; 54 | } 55 | 56 | .FlexBoxJustAround { 57 | display: -webkit-box; 58 | display: -moz-box; 59 | display: -ms-flexbox; 60 | display: flex; 61 | justify-content: space-around; 62 | } 63 | 64 | .FlexBoxJustBetween { 65 | display: -webkit-box; 66 | display: -moz-box; 67 | display: -ms-flexbox; 68 | display: flex; 69 | flex-wrap: wrap; 70 | justify-content: space-between; 71 | } 72 | 73 | .FlexBoxWrap { 74 | display: -webkit-box; 75 | display: -moz-box; 76 | display: -ms-flexbox; 77 | display: flex; 78 | flex-wrap: wrap; 79 | } 80 | 81 | .FlexJustify { 82 | -webkit-box-pack: justify; 83 | justify-content: space-between; 84 | } 85 | 86 | .FlexBoxStretch { 87 | display: -webkit-box; 88 | display: -moz-box; 89 | display: -ms-flexbox; 90 | display: flex; 91 | align-content: stretch; 92 | } 93 | 94 | .FlexItem { 95 | flex-grow: 1; 96 | } 97 | 98 | .HighZ {z-index: 200;} 99 | -------------------------------------------------------------------------------- /React.Common/ui-src/css/rangeInput.css: -------------------------------------------------------------------------------- 1 | input[type=range] { 2 | -webkit-appearance: none; 3 | margin: 18px 0; 4 | width: 100%; 5 | } 6 | input[type=range]:focus { 7 | outline: none; 8 | } 9 | input[type=range]::-webkit-slider-runnable-track { 10 | width: 100%; 11 | height: 8.4px; 12 | cursor: pointer; 13 | animate: 0.2s; 14 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; 15 | background: #4d2c3d; 16 | border-radius: 1.3px; 17 | border: 0.2px solid #010101; 18 | } 19 | input[type=range]::-webkit-slider-thumb { 20 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; 21 | border: 1px solid #000000; 22 | height: 36px; 23 | width: 16px; 24 | border-radius: 3px; 25 | background: #ffffff; 26 | cursor: pointer; 27 | -webkit-appearance: none; 28 | margin-top: -14px; 29 | } 30 | input[type=range]:focus::-webkit-slider-runnable-track { 31 | background: #367ebd; 32 | } 33 | input[type=range]::-moz-range-track { 34 | width: 100%; 35 | height: 8.4px; 36 | cursor: pointer; 37 | animate: 0.2s; 38 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; 39 | background: #3071a9; 40 | border-radius: 1.3px; 41 | border: 0.2px solid #010101; 42 | } 43 | input[type=range]::-moz-range-thumb { 44 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; 45 | border: 1px solid #000000; 46 | height: 36px; 47 | width: 16px; 48 | border-radius: 3px; 49 | background: #ffffff; 50 | cursor: pointer; 51 | } 52 | input[type=range]::-ms-track { 53 | width: 100%; 54 | height: 8.4px; 55 | cursor: pointer; 56 | animate: 0.2s; 57 | background: transparent; 58 | border-color: transparent; 59 | border-width: 16px 0; 60 | color: transparent; 61 | } 62 | input[type=range]::-ms-fill-lower { 63 | background: #2a6495; 64 | border: 0.2px solid #010101; 65 | border-radius: 2.6px; 66 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; 67 | } 68 | input[type=range]::-ms-fill-upper { 69 | background: #3071a9; 70 | border: 0.2px solid #010101; 71 | border-radius: 2.6px; 72 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; 73 | } 74 | input[type=range]::-ms-thumb { 75 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; 76 | border: 1px solid #000000; 77 | height: 36px; 78 | width: 16px; 79 | border-radius: 3px; 80 | background: #ffffff; 81 | cursor: pointer; 82 | } 83 | input[type=range]:focus::-ms-fill-lower { 84 | background: #3071a9; 85 | } 86 | input[type=range]:focus::-ms-fill-upper { 87 | background: #367ebd; 88 | } 89 | -------------------------------------------------------------------------------- /React.Common/ui-src/img/1x1TransShim.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.Common/ui-src/img/1x1TransShim.gif -------------------------------------------------------------------------------- /React.Common/ui-src/img/SLogoS5-48_C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.Common/ui-src/img/SLogoS5-48_C.png -------------------------------------------------------------------------------- /React.Common/ui-src/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.Common/ui-src/img/favicon.ico -------------------------------------------------------------------------------- /React.Common/ui-src/img/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.Common/ui-src/img/flow.png -------------------------------------------------------------------------------- /React.Common/ui-src/img/leaf.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.Common/ui-src/img/leaf.ico -------------------------------------------------------------------------------- /React.Common/ui-src/img/snow.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.Common/ui-src/img/snow.ico -------------------------------------------------------------------------------- /React.Common/ui-src/img/sun.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmarkstevens/ReactPatterns/3a0e40f4d562155163bcac98d9555c1f2bba8f1b/React.Common/ui-src/img/sun.ico -------------------------------------------------------------------------------- /React.Common/ui-src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ReactPatterns-ReduxPages 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /React.Common/ui-src/store/App.Store.js: -------------------------------------------------------------------------------- 1 | import {createStore, combineReducers, applyMiddleware} from 'redux'; 2 | import logger from 'redux-logger'; 3 | import thunkMiddleware from 'redux-thunk'; 4 | 5 | import {apiGetAppData, apiGetImageList, apiGetTreeView, apiGetInputData, apiGetPicList} from './api/api.Actions'; 6 | 7 | import appState from './app/app.Reducer'; 8 | import galleryState from './gallery/gallery.Reducer'; 9 | import inputState from './input/input.Reducer'; 10 | import treeState from './treeview/tree.Reducer'; 11 | 12 | const reducer = combineReducers({appState, galleryState, inputState, treeState}); 13 | let middleware = [thunkMiddleware]; 14 | 15 | const useLogger = 1; 16 | if (useLogger) middleware.push(logger); 17 | 18 | const store = createStore(reducer, applyMiddleware(...middleware)); 19 | 20 | store.dispatch(apiGetAppData()); 21 | store.dispatch(apiGetImageList()); 22 | store.dispatch(apiGetTreeView()); 23 | store.dispatch(apiGetInputData()); 24 | store.dispatch(apiGetPicList()); 25 | 26 | export default store; 27 | -------------------------------------------------------------------------------- /React.Common/ui-src/store/api/api.Actions.js: -------------------------------------------------------------------------------- 1 | import 'whatwg-fetch'; 2 | 3 | let jsonHeader = {'Accept': 'application/json', 'Content-Type': 'application/json'}; 4 | 5 | export function apiGetAppData() { 6 | return (dispatch) => { 7 | fetch('/routes/getAppData') 8 | .then((response) => response.json()) 9 | .then((json) => dispatch({type: 'GetAppDataDone', payload: json})); 10 | }; 11 | } 12 | 13 | export function apiGetImageList() { 14 | return (dispatch) => { 15 | fetch('/routes/getImageList') 16 | .then((response) => response.json()) 17 | .then((json) => dispatch({type: 'GetImageListDone', payload: json})); 18 | }; 19 | } 20 | 21 | export function apiGetInputData() { 22 | return (dispatch) => { 23 | fetch('/routes/getInputData') 24 | .then((response) => response.json()) 25 | .then((json) => dispatch({type: 'GetInputDataDone', payload: json})); 26 | }; 27 | } 28 | 29 | export function apiGetPicList() { 30 | return (dispatch) => { 31 | fetch('/routes/getPicList') 32 | .then((response) => response.json()) 33 | .then((json) => dispatch({type: 'GetPicListDone', payload: json})); 34 | }; 35 | } 36 | 37 | export function apiGetTreeView() { 38 | return (dispatch) => { 39 | fetch('/routes/getTreeView') 40 | .then((response) => response.json()) 41 | .then((json) => dispatch({type: 'GetTreeViewDone', payload: json})); 42 | }; 43 | } 44 | 45 | export function apiSetAppData(data) { 46 | fetch('/routes/setAppData', {method: 'POST', headers: jsonHeader, body: JSON.stringify(data)}); 47 | } 48 | 49 | export function apiSetInputData(data) { 50 | fetch('/routes/setInputData', {method: 'POST', headers: jsonHeader, body: JSON.stringify(data)}); 51 | } 52 | 53 | export function apiSetTreeView(data) { 54 | fetch('/routes/setTreeView', {method: 'POST', headers: jsonHeader, body: JSON.stringify(data)}); 55 | } 56 | -------------------------------------------------------------------------------- /React.Common/ui-src/store/app/app.actions.js: -------------------------------------------------------------------------------- 1 | export function appNavMenuAction(newPage) { return {type: 'AppNavMenuAction', newPage}; } 2 | -------------------------------------------------------------------------------- /React.Common/ui-src/store/app/app.reducer.js: -------------------------------------------------------------------------------- 1 | 2 | const initialAppState = { 3 | currentPage: 'Button' 4 | }; 5 | 6 | export default function handleActions(state = initialAppState, action) { 7 | let _appState = Object.assign({}, state); 8 | switch (action.type) { 9 | case 'AppNavMenuAction': _appState.currentPage = action.newPage; return _appState; 10 | default: return state; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /React.Common/ui-src/store/gallery/gallery.Reducer.js: -------------------------------------------------------------------------------- 1 | 2 | const initialState = { 3 | picList: [], 4 | }; 5 | 6 | export default function handleActions(state = initialState, action) { 7 | switch (action.type) { 8 | case 'GetPicListDone': return {...state, ...action.payload}; 9 | default: return state; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /React.Common/ui-src/store/input/input.Actions.js: -------------------------------------------------------------------------------- 1 | 2 | export function editRecord(field, value) { return {type: 'EditRecord', field, value}; } 3 | -------------------------------------------------------------------------------- /React.Common/ui-src/store/input/input.Reducer.js: -------------------------------------------------------------------------------- 1 | 2 | import {apiSetInputData} from '../api/api.Actions'; 3 | 4 | const setData = (inputCopy) => { apiSetInputData(inputCopy); }; 5 | 6 | const onEditRecord = (inputCopy, field, value) => { 7 | switch (field) { 8 | case 'text': inputCopy.text = value; break; 9 | case 'checkbox': inputCopy.checkbox = value; break; 10 | case 'radioGroup': inputCopy.radioGroup = value; break; 11 | case 'color': inputCopy.color = value; break; 12 | case 'number': inputCopy.number = value; break; 13 | case 'range': inputCopy.range = value; break; 14 | case 'folder': inputCopy.folder = value; break; 15 | } 16 | setData(inputCopy); 17 | return inputCopy; 18 | }; 19 | 20 | const initialState = { 21 | 'text': '', 22 | 'checkbox': false, 23 | 'radioGroup': '', 24 | 'color': '#ffffff', 25 | 'number': '', 26 | 'range': '', 27 | 'folder': '' 28 | }; 29 | 30 | export default function handleActions(state = initialState, action) { 31 | let inputCopy = Object.assign({}, state); 32 | switch (action.type) { 33 | case 'GetInputDataDone': return {...state, ...action.payload}; 34 | case 'EditRecord': { 35 | let editRecordData = onEditRecord(inputCopy, action.field, action.value); 36 | return {...state, ...editRecordData}; 37 | } 38 | default: return state; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /React.Common/ui-src/store/treeview/tree.Actions.js: -------------------------------------------------------------------------------- 1 | 2 | export function setClippetsTree() { return {type: 'SetClippetsTree'}; } 3 | 4 | export function selectTreeNode(node) { return {type: 'SelectTreeNode', node}; } 5 | 6 | export function setTreeNodeClosed(node) { return {type: 'SetTreeNodeClosed', node}; } 7 | 8 | export function saveTreeEdit(node) { return {type: 'SaveTreeEdit', node}; } 9 | 10 | export function saveTreeNew(node, location) { return {type: 'SaveTreeNew', node, location}; } 11 | 12 | export function treeActions(action) { 13 | switch (action) { 14 | case 'new': return {type: 'ShowNew'}; 15 | case 'edit': return {type: 'ShowEdit'}; 16 | case 'moveUp': return {type: 'MoveUp'}; 17 | case 'moveDown': return {type: 'MoveDown'}; 18 | case 'remove': return {type: 'Remove'}; 19 | case 'cancelEdit': return {type: 'CancelEdit'}; 20 | case 'cancelNew': return {type: 'CancelNew'}; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /React.Common/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 3 | const webpack = require('webpack'); 4 | const configJson = require('./webpack.config.json'); 5 | 6 | module.exports = (env) => { 7 | 8 | const noMinimize = env.noMinimize; 9 | var plugins = []; 10 | 11 | plugins.push(new ExtractTextPlugin({filename: 'app.css', allChunks: true})); 12 | plugins.push(new webpack.optimize.CommonsChunkPlugin({name: 'lib'})); 13 | if (noMinimize) { 14 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('development')}})); 15 | } else { 16 | plugins.push(new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('production')}})); 17 | plugins.push(new webpack.optimize.UglifyJsPlugin({include: /lib\.js/, minimize: true})); 18 | } 19 | 20 | const ROOT_PATH = path.resolve(__dirname); 21 | const SRC_PATH = path.resolve(ROOT_PATH, './ui-src'); 22 | const DIST_PATH = path.resolve(ROOT_PATH, './ui-dist'); 23 | 24 | 25 | return { 26 | context: SRC_PATH, 27 | entry: { 28 | app: './app.jsx', 29 | lib: configJson.lib 30 | }, 31 | 32 | output: { 33 | path: DIST_PATH, 34 | filename: '[name].js' 35 | }, 36 | 37 | module: { 38 | rules: [ 39 | { 40 | test: /\.jsx?$/, 41 | loader: 'babel-loader', 42 | query: {presets:['es2015', 'react', 'stage-0']}, 43 | exclude: /(node_modules)/, 44 | }, 45 | { 46 | test: /\.css$/, 47 | use: ExtractTextPlugin.extract({ 48 | fallback: 'style-loader', 49 | use: 'css-loader' 50 | }) 51 | }, 52 | { 53 | test: /\.(png|jpg|ico|gif)$/, 54 | loader: 'file-loader?name=img/[name].[ext]' 55 | }, 56 | { 57 | test: /\.(html)$/, 58 | loader: 'file-loader?name=[name].[ext]' 59 | } 60 | ] 61 | }, 62 | plugins, 63 | resolve: { 64 | extensions: ['.js', '.jsx'], 65 | modules: ['node_modules'] 66 | } 67 | }; 68 | }; 69 | -------------------------------------------------------------------------------- /React.Common/webpack.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": [ 3 | "lodash", 4 | "lodash/throttle", 5 | "radium", 6 | "react", 7 | "react-dom", 8 | "react-mixin", 9 | "react-redux", 10 | "redux", 11 | "redux-logger", 12 | "screenfull", 13 | "redux-thunk", 14 | "traverse", 15 | "whatwg-fetch" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReactPatterns", 3 | "version": "4.0.1", 4 | "description": "A collection of simple react projects providing reusable components, startup and test examples.", 5 | "license": "MIT", 6 | "author": { 7 | "name": "J Mark Stevens", 8 | "email": "jmstevens@jmarkstevens.com" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/jmarkstevens/ReactPatterns.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/jmarkstevens/ReactPatterns/issues" 16 | }, 17 | "keywords": [ 18 | "react", 19 | "patterns", 20 | "treeview", 21 | "dropdown", 22 | "buttons", 23 | "form", 24 | "list", 25 | "progressbar", 26 | "range slider", 27 | "slider", 28 | "tooltip", 29 | "reflux", 30 | "websocket", 31 | "electron", 32 | "keycapture", 33 | "drag and drop" 34 | ] 35 | } 36 | --------------------------------------------------------------------------------