├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── README.md ├── cfg ├── base.js ├── defaults.js ├── dev.js ├── dist.js └── test.js ├── karma.conf.js ├── package.json ├── server.js ├── src ├── AppRoutes.jsx ├── actions │ └── README.md ├── components │ ├── Footer.jsx │ ├── Master.jsx │ └── pages │ │ ├── about │ │ └── AboutPage.jsx │ │ ├── account │ │ └── AccountPage.jsx │ │ ├── add │ │ └── AddPage.jsx │ │ ├── browse │ │ └── BrowsePage.jsx │ │ ├── home │ │ ├── HomePage.jsx │ │ └── HomePage.scss │ │ ├── results │ │ └── ResultsPage.jsx │ │ └── search │ │ └── SearchPage.jsx ├── config │ ├── README.md │ ├── base.js │ ├── dev.js │ ├── dist.js │ └── test.js ├── favicon.ico ├── images │ └── logo.jpg ├── index.html ├── index.jsx ├── sources │ └── README.md ├── stores │ └── README.md ├── styles │ └── App.css └── tags.json ├── test ├── actions │ └── .keep ├── config │ └── ConfigTest.js ├── helpers │ └── shallowRenderHelper.js ├── loadtests.js ├── sources │ └── .keep └── stores │ └── .keep └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-1", "react"], 3 | "env": { 4 | "test": { 5 | "sourceMaps": "both" 6 | }, 7 | "production": { 8 | "plugins": [ 9 | "transform-react-remove-prop-types", 10 | "transform-react-constant-elements", 11 | "transform-react-inline-elements", 12 | "transform-react-display-name" 13 | ], 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | src/config/**/* 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "root": true, 3 | "parser": "babel-eslint", 4 | "plugins": [ 5 | "babel", 6 | "react", 7 | ], 8 | "parserOptions": { 9 | "ecmaVersion": 7, 10 | "sourceType": "module", 11 | "ecmaFeatures": { 12 | "jsx": true, 13 | experimentalObjectRestSpread: true, 14 | } 15 | }, 16 | "env": { 17 | "browser": true, 18 | "amd": true, 19 | "es6": true, 20 | "node": true, 21 | "mocha": true 22 | }, 23 | rules: { 24 | // Errors 25 | 'array-bracket-spacing': ['error', 'never'], 26 | 'arrow-spacing': 'error', 27 | 'arrow-parens': 'error', 28 | 'block-spacing': ['error', 'always'], 29 | 'brace-style': ['error', "1tbs", { "allowSingleLine": true }], 30 | 'comma-dangle': ['error', 'always-multiline'], 31 | 'comma-spacing': ['error', {before: false, after: true}], 32 | 'comma-style': ['error', 'last'], 33 | 'computed-property-spacing': ['error', 'never'], 34 | 'consistent-this': ['error', 'self'], 35 | 'consistent-return': 'off', 36 | 'dot-notation': 'error', 37 | 'dot-location': ['error', 'property'], 38 | 'eqeqeq': ['error', 'smart'], 39 | 'eol-last': 'error', 40 | 'indent': ['error', 2, {SwitchCase: 1}], 41 | 'id-blacklist': ['error', 'e'], 42 | 'jsx-quotes': ['error', 'prefer-double'], 43 | 'keyword-spacing': 'error', 44 | 'key-spacing': 'error', 45 | 'max-len': ['error', 120, 4], 46 | 'new-cap': ['off', {capIsNew: true, newIsCap: true}], 47 | 'no-unused-expressions': 'error', 48 | 'no-unused-vars': 'error', 49 | 'no-confusing-arrow': 'error', 50 | 'no-shadow': 'off', 51 | 'no-spaced-func': 'error', 52 | 'no-multiple-empty-lines': 'error', 53 | 'no-multi-spaces': 'error', 54 | 'no-undef': 'error', 55 | 'no-empty-pattern': 'error', 56 | 'no-dupe-keys': 'error', 57 | 'no-dupe-args': 'error', 58 | 'no-duplicate-case': 'error', 59 | 'no-cond-assign': 'error', 60 | 'no-extra-semi': 'error', 61 | 'no-extra-boolean-cast': 'error', 62 | 'no-trailing-spaces': 'error', 63 | 'no-underscore-dangle': 'error', 64 | 'no-unneeded-ternary': 'error', 65 | 'no-unreachable': 'error', 66 | 'no-var': 'error', 67 | 'one-var': ['error', 'never'], 68 | 'operator-linebreak': ['error', 'after'], 69 | 'padded-blocks': ['error', 'never'], 70 | 'prefer-arrow-callback': 'off', 71 | 'prefer-const': 'error', 72 | 'prefer-template': 'error', 73 | 'quotes': ['error', 'single', 'avoid-escape'], 74 | 'semi': ['error', 'always'], 75 | 'space-before-blocks': ['error', 'always'], 76 | 'space-before-function-paren': ['error', 'never'], 77 | 'space-infix-ops': 'error', 78 | 'space-unary-ops': ['error', { words: true, nonwords: false }], 79 | 'spaced-comment': 'error', 80 | 'yoda': 'error', 81 | 82 | // Disabled 83 | 'strict': 'off', 84 | 'no-case-declarations': 'off', 85 | 86 | // Babel 87 | 'babel/object-curly-spacing': ['error', 'always'], 88 | 89 | // React 90 | 'react/display-name': 'error', 91 | 'react/jsx-boolean-value': ['error', 'always'], 92 | 'react/jsx-closing-bracket-location': 'error', 93 | 'react/jsx-curly-spacing': 'error', 94 | 'react/jsx-equals-spacing': 'error', 95 | 'react/jsx-first-prop-new-line': ['error', 'multiline'], 96 | 'react/jsx-handler-names': 'error', 97 | 'react/jsx-indent-props': ['error', 2], 98 | 'react/jsx-max-props-per-line': ['error', {maximum: 3}], 99 | 'react/jsx-no-duplicate-props': 'error', 100 | 'react/jsx-no-undef': 'error', 101 | 'react/jsx-pascal-case': 'error', 102 | 'react/jsx-space-before-closing': 'error', 103 | 'react/jsx-uses-react': 'error', 104 | 'react/jsx-uses-vars': 'error', 105 | 'react/no-danger': 'error', 106 | 'react/no-did-mount-set-state': 'error', 107 | 'react/no-did-update-set-state': 'error', 108 | 'react/no-direct-mutation-state': 'error', 109 | 'react/no-multi-comp': 'off', 110 | 'react/no-unknown-property': 'error', 111 | 'react/no-is-mounted': 'error', 112 | 'react/prefer-arrow-callback': 'off', 113 | 'react/prefer-es6-class': 'error', 114 | 'react/prop-types': 'error', 115 | 'react/react-in-jsx-scope': 'error', 116 | 'react/require-extension': 'error', 117 | 'react/self-closing-comp': 'error', 118 | 'react/sort-comp': 'error', 119 | 'react/sort-prop-types': 'error', 120 | 'react/wrap-multilines': 'error', 121 | 'react/jsx-indent': ['error', 2], 122 | 123 | // React Disabled 124 | 'react/jsx-no-bind': 'off', 125 | 'react/jsx-no-literals': 'off', 126 | 'react/jsx-sort-props': 'off', 127 | 'react/no-set-state': 'off', 128 | }, 129 | } 130 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Bower 30 | bower_components/ 31 | 32 | # Optional npm cache directory 33 | .npm 34 | 35 | # Optional REPL history 36 | .node_repl_history 37 | 38 | # Dist folder 39 | dist -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # adventurelookup-frontend 2 | An implementation of Adventure Lookup's frontend using React and [Material-UI](http://www.material-ui.com/) 3 | 4 | --- 5 | 6 | ## Installation and Usage: 7 | 8 | | command (in project root directory) | Action | 9 | | --- | --- | 10 | | `npm i` | Install dependencies | 11 | | `npm start` or `npm run serve` | Start | 12 | | `npm run serve:dist` | Start dev-server with dist version | 13 | | `npm run dist` | Build dist version and copy static files | 14 | | `npm test` | Run unit tests | 15 | | `npm run lint` | Lint all files in src (also automatically done AFTER tests are run) | 16 | | `npm run clean` | Clean up the dist directory | 17 | | `npm run copy` | Just copy the static assets | 18 | -------------------------------------------------------------------------------- /cfg/base.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let path = require('path'); 3 | let defaultSettings = require('./defaults'); 4 | 5 | // Additional npm or bower modules to include in builds 6 | // Add all foreign plugins you may need into this array 7 | // @example: 8 | // let npmBase = path.join(__dirname, '../node_modules'); 9 | // let additionalPaths = [ path.join(npmBase, 'react-bootstrap') ]; 10 | let additionalPaths = []; 11 | 12 | module.exports = { 13 | additionalPaths: additionalPaths, 14 | port: defaultSettings.port, 15 | debug: true, 16 | devtool: 'eval', 17 | output: { 18 | path: path.join(__dirname, '/../dist/assets'), 19 | filename: 'app.js', 20 | publicPath: defaultSettings.publicPath 21 | }, 22 | devServer: { 23 | contentBase: './src/', 24 | historyApiFallback: true, 25 | hot: true, 26 | port: defaultSettings.port, 27 | publicPath: defaultSettings.publicPath, 28 | noInfo: false 29 | }, 30 | resolve: { 31 | extensions: ['', '.js', '.jsx'], 32 | alias: { 33 | actions: `${defaultSettings.srcPath}/actions/`, 34 | components: `${defaultSettings.srcPath}/components/`, 35 | sources: `${defaultSettings.srcPath}/sources/`, 36 | stores: `${defaultSettings.srcPath}/stores/`, 37 | styles: `${defaultSettings.srcPath}/styles/`, 38 | config: `${defaultSettings.srcPath}/config/` + process.env.REACT_WEBPACK_ENV 39 | } 40 | }, 41 | module: {} 42 | }; 43 | -------------------------------------------------------------------------------- /cfg/defaults.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function that returns default values. 3 | * Used because Object.assign does a shallow instead of a deep copy. 4 | * Using [].push will add to the base array, so a require will alter 5 | * the base array output. 6 | */ 7 | 'use strict'; 8 | 9 | const path = require('path'); 10 | const srcPath = path.join(__dirname, '/../src'); 11 | const dfltPort = 8000; 12 | 13 | /** 14 | * Get the default modules object for webpack 15 | * @return {Object} 16 | */ 17 | function getDefaultModules() { 18 | return { 19 | preLoaders: [ 20 | { 21 | test: /\.(js|jsx)$/, 22 | include: srcPath, 23 | loader: 'eslint-loader' 24 | } 25 | ], 26 | loaders: [ 27 | { 28 | test: /\.css$/, 29 | loader: 'style-loader!css-loader' 30 | }, 31 | { 32 | test: /\.sass/, 33 | loader: 'style-loader!css-loader!sass-loader?outputStyle=expanded&indentedSyntax' 34 | }, 35 | { 36 | test: /\.scss/, 37 | loader: 'style-loader!css-loader!sass-loader?outputStyle=expanded' 38 | }, 39 | { 40 | test: /\.less/, 41 | loader: 'style-loader!css-loader!less-loader' 42 | }, 43 | { 44 | test: /\.styl/, 45 | loader: 'style-loader!css-loader!stylus-loader' 46 | }, 47 | { 48 | test: /\.(png|jpg|gif|woff|woff2)$/, 49 | loader: 'url-loader?limit=8192' 50 | }, 51 | { 52 | test: /\.(mp4|ogg|svg)$/, 53 | loader: 'file-loader' 54 | }, 55 | ] 56 | }; 57 | } 58 | 59 | module.exports = { 60 | srcPath: srcPath, 61 | publicPath: '/assets/', 62 | port: dfltPort, 63 | getDefaultModules: getDefaultModules 64 | }; 65 | -------------------------------------------------------------------------------- /cfg/dev.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let path = require('path'); 4 | let webpack = require('webpack'); 5 | let baseConfig = require('./base'); 6 | let defaultSettings = require('./defaults'); 7 | 8 | // Add needed plugins here 9 | let BowerWebpackPlugin = require('bower-webpack-plugin'); 10 | 11 | let config = Object.assign({}, baseConfig, { 12 | entry: [ 13 | 'webpack-dev-server/client?http://127.0.0.1:' + defaultSettings.port, 14 | 'webpack/hot/only-dev-server', 15 | './src/index' 16 | ], 17 | cache: true, 18 | devtool: 'eval-source-map', 19 | plugins: [ 20 | new webpack.HotModuleReplacementPlugin(), 21 | new webpack.NoErrorsPlugin(), 22 | new BowerWebpackPlugin({ 23 | searchResolveModulesDirectories: false 24 | }) 25 | ], 26 | module: defaultSettings.getDefaultModules() 27 | }); 28 | 29 | // Add needed loaders to the defaults here 30 | config.module.loaders.push({ 31 | test: /\.(js|jsx)$/, 32 | loader: 'react-hot!babel-loader', 33 | include: [].concat( 34 | config.additionalPaths, 35 | [ path.join(__dirname, '/../src') ] 36 | ) 37 | }); 38 | 39 | module.exports = config; 40 | -------------------------------------------------------------------------------- /cfg/dist.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let path = require('path'); 4 | let webpack = require('webpack'); 5 | 6 | let baseConfig = require('./base'); 7 | let defaultSettings = require('./defaults'); 8 | 9 | // Add needed plugins here 10 | let BowerWebpackPlugin = require('bower-webpack-plugin'); 11 | 12 | let config = Object.assign({}, baseConfig, { 13 | entry: path.join(__dirname, '../src/index'), 14 | cache: false, 15 | devtool: 'sourcemap', 16 | plugins: [ 17 | new webpack.optimize.DedupePlugin(), 18 | new webpack.DefinePlugin({ 19 | 'process.env.NODE_ENV': '"production"' 20 | }), 21 | new BowerWebpackPlugin({ 22 | searchResolveModulesDirectories: false 23 | }), 24 | new webpack.optimize.UglifyJsPlugin(), 25 | new webpack.optimize.OccurenceOrderPlugin(), 26 | new webpack.optimize.AggressiveMergingPlugin(), 27 | new webpack.NoErrorsPlugin() 28 | ], 29 | module: defaultSettings.getDefaultModules() 30 | }); 31 | 32 | // Add needed loaders to the defaults here 33 | config.module.loaders.push({ 34 | test: /\.(js|jsx)$/, 35 | loader: 'babel', 36 | include: [].concat( 37 | config.additionalPaths, 38 | [ path.join(__dirname, '/../src') ] 39 | ) 40 | }); 41 | 42 | module.exports = config; 43 | -------------------------------------------------------------------------------- /cfg/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let path = require('path'); 4 | let srcPath = path.join(__dirname, '/../src/'); 5 | 6 | let baseConfig = require('./base'); 7 | 8 | // Add needed plugins here 9 | let BowerWebpackPlugin = require('bower-webpack-plugin'); 10 | 11 | module.exports = { 12 | devtool: 'eval', 13 | module: { 14 | preLoaders: [ 15 | { 16 | test: /\.(js|jsx)$/, 17 | loader: 'isparta-instrumenter-loader', 18 | include: [ 19 | path.join(__dirname, '/../src') 20 | ] 21 | } 22 | ], 23 | loaders: [ 24 | { 25 | test: /\.(png|jpg|gif|woff|woff2|css|sass|scss|less|styl)$/, 26 | loader: 'null-loader' 27 | }, 28 | { 29 | test: /\.(js|jsx)$/, 30 | loader: 'babel-loader', 31 | include: [].concat( 32 | baseConfig.additionalPaths, 33 | [ 34 | path.join(__dirname, '/../src'), 35 | path.join(__dirname, '/../test') 36 | ] 37 | ) 38 | } 39 | ] 40 | }, 41 | resolve: { 42 | extensions: [ '', '.js', '.jsx' ], 43 | alias: { 44 | actions: srcPath + 'actions/', 45 | helpers: path.join(__dirname, '/../test/helpers'), 46 | components: srcPath + 'components/', 47 | sources: srcPath + 'sources/', 48 | stores: srcPath + 'stores/', 49 | styles: srcPath + 'styles/', 50 | config: srcPath + 'config/' + process.env.REACT_WEBPACK_ENV 51 | } 52 | }, 53 | plugins: [ 54 | new BowerWebpackPlugin({ 55 | searchResolveModulesDirectories: false 56 | }) 57 | ] 58 | }; 59 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | var webpackCfg = require('./webpack.config'); 2 | 3 | // Set node environment to testing 4 | process.env.NODE_ENV = 'test'; 5 | 6 | module.exports = function(config) { 7 | config.set({ 8 | basePath: '', 9 | browsers: [ 'PhantomJS' ], 10 | files: [ 11 | 'test/loadtests.js' 12 | ], 13 | port: 8000, 14 | captureTimeout: 60000, 15 | frameworks: [ 'mocha', 'chai' ], 16 | client: { 17 | mocha: {} 18 | }, 19 | singleRun: true, 20 | reporters: [ 'mocha', 'coverage' ], 21 | preprocessors: { 22 | 'test/loadtests.js': [ 'webpack', 'sourcemap' ] 23 | }, 24 | webpack: webpackCfg, 25 | webpackServer: { 26 | noInfo: true 27 | }, 28 | coverageReporter: { 29 | dir: 'coverage/', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text' } 33 | ] 34 | } 35 | }); 36 | }; 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "adventureLookup", 3 | "private": true, 4 | "version": "0.0.2", 5 | "description": "An implementation of Adventure Lookup's frontend using React and Material-UI", 6 | "main": "", 7 | "bugs": "https://github.com/AdventureLookup/adventurelookup-frontend/issues", 8 | "scripts": { 9 | "clean": "rimraf dist/*", 10 | "copy": "copyfiles -u 1 ./src/index.html ./src/favicon.ico ./src/tags.json ./src/images/**/* ./dist", 11 | "dist": "npm run copy & webpack --env=dist", 12 | "lint": "eslint ./src", 13 | "posttest": "npm run lint", 14 | "release:major": "npm version major && npm publish && git push --follow-tags", 15 | "release:minor": "npm version minor && npm publish && git push --follow-tags", 16 | "release:patch": "npm version patch && npm publish && git push --follow-tags", 17 | "serve": "node server.js --env=dev", 18 | "serve:dist": "node server.js --env=dist", 19 | "start": "node server.js --env=dev", 20 | "test": "karma start", 21 | "test:watch": "karma start --autoWatch=true --singleRun=false" 22 | }, 23 | "repository": "https://github.com/AdventureLookup/adventurelookup-frontend", 24 | "keywords": [], 25 | "contributors": [ 26 | { 27 | "name": "Patrick Templeton", 28 | "url": "https://github.com/templetonpr" 29 | }, 30 | { 31 | "name": "Andrew Brehaut", 32 | "url" :"https://brehaut.net" 33 | } 34 | ], 35 | "devDependencies": { 36 | "babel-core": "^6.0.0", 37 | "babel-eslint": "^6.0.0", 38 | "babel-loader": "^6.0.0", 39 | "babel-polyfill": "^6.3.14", 40 | "babel-preset-es2015": "^6.0.15", 41 | "babel-preset-react": "^6.0.15", 42 | "babel-preset-stage-1": "^6.5.0", 43 | "bower-webpack-plugin": "^0.1.9", 44 | "chai": "^3.2.0", 45 | "copyfiles": "^0.2.1", 46 | "css-loader": "^0.23.0", 47 | "eslint": "^2.2.0", 48 | "eslint-loader": "^1.0.0", 49 | "eslint-plugin-babel": "^3.2.0", 50 | "eslint-plugin-react": "^5.0.0", 51 | "file-loader": "^0.8.4", 52 | "glob": "^7.0.0", 53 | "image-webpack-loader": "^1.8.0", 54 | "isparta-instrumenter-loader": "^1.0.0", 55 | "karma": "^0.13.9", 56 | "karma-chai": "^0.1.0", 57 | "karma-coverage": "^1.0.0", 58 | "karma-mocha": "^1.0.0", 59 | "karma-mocha-reporter": "^2.0.0", 60 | "karma-phantomjs-launcher": "^1.0.0", 61 | "karma-sourcemap-loader": "^0.3.5", 62 | "karma-webpack": "^1.7.0", 63 | "minimist": "^1.2.0", 64 | "mocha": "^2.2.5", 65 | "node-sass": "^3.4.2", 66 | "null-loader": "^0.1.1", 67 | "open": "0.0.5", 68 | "phantomjs-prebuilt": "^2.0.0", 69 | "raw-loader": "^0.5.1", 70 | "react-addons-test-utils": "^15.0.0", 71 | "react-hot-loader": "^1.2.9", 72 | "rimraf": "^2.4.3", 73 | "sass-loader": "^3.1.2", 74 | "style-loader": "^0.13.0", 75 | "url-loader": "^0.5.6", 76 | "webpack": "^1.12.0", 77 | "webpack-dev-server": "^1.12.0" 78 | }, 79 | "dependencies": { 80 | "core-js": "^2.0.0", 81 | "history": "^3.0.0", 82 | "material-ui": "^0.15.0", 83 | "normalize.css": "^4.0.0", 84 | "react": "^15.0.0", 85 | "react-dom": "^15.0.0", 86 | "react-router": "^2.4.1", 87 | "react-tap-event-plugin": "^1.0.0", 88 | "react-title-component": "^1.0.1", 89 | "whatwg-fetch": "^1.0.0" 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | /*eslint no-console:0 */ 2 | 'use strict'; 3 | require('core-js/fn/object/assign'); 4 | const webpack = require('webpack'); 5 | const WebpackDevServer = require('webpack-dev-server'); 6 | const config = require('./webpack.config'); 7 | const open = require('open'); 8 | 9 | new WebpackDevServer(webpack(config), config.devServer) 10 | .listen(config.port, 'localhost', (err) => { 11 | if (err) { 12 | console.log(err); 13 | } 14 | console.log('Listening at localhost:' + config.port); 15 | console.log('Opening your system browser...'); 16 | open('http://localhost:' + config.port + '/webpack-dev-server/'); 17 | }); 18 | -------------------------------------------------------------------------------- /src/AppRoutes.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Route from 'react-router/lib/Route'; 3 | // import Redirect from 'react-router/lib/'; 4 | import IndexRoute from 'react-router/lib/IndexRoute'; 5 | 6 | import Master from './components/Master'; 7 | import HomePage from './components/pages/home/HomePage'; 8 | import SearchPage from './components/pages/search/SearchPage'; 9 | import ResultsPage from './components/pages/results/ResultsPage'; 10 | import AboutPage from './components/pages/about/AboutPage'; 11 | import BrowsePage from './components/pages/browse/BrowsePage'; 12 | import AddPage from './components/pages/add/AddPage'; 13 | import AccountPage from './components/pages/account/AccountPage'; 14 | 15 | const AppRoutes = ( 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | 28 | export default AppRoutes; 29 | -------------------------------------------------------------------------------- /src/actions/README.md: -------------------------------------------------------------------------------- 1 | # About this folder 2 | This folder will hold all of your **flux** actions if you are using flux. 3 | You can include actions into your components or stores like this: 4 | 5 | ```javascript 6 | let react = require('react/addons'); 7 | let MyAction = require('actions/MyAction'); 8 | class MyComponent extends React.Component { 9 | constructor(props) { 10 | super(props); 11 | MyAction.exampleMethod(); 12 | } 13 | } 14 | ``` 15 | -------------------------------------------------------------------------------- /src/components/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import Paper from 'material-ui/Paper'; 3 | 4 | class Footer extends Component { 5 | 6 | static propTypes = { 7 | style: PropTypes.object, 8 | }; 9 | 10 | render() { 11 | return ( 12 | 13 |

This is the footer

14 |

© 2016 Lookup Industries Inc.

15 |
16 | ); 17 | } 18 | } 19 | 20 | export default Footer; 21 | -------------------------------------------------------------------------------- /src/components/Master.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import Link from 'react-router/lib/Link'; 3 | import Title from 'react-title-component'; 4 | import AppBar from 'material-ui/AppBar'; 5 | import IconButton from 'material-ui/IconButton'; 6 | import IconMenu from 'material-ui/IconMenu'; 7 | import Drawer from 'material-ui/Drawer'; 8 | import Toggle from 'material-ui/Toggle'; 9 | import MenuItem from 'material-ui/MenuItem'; 10 | import MoreVertIcon from 'material-ui/svg-icons/navigation/more-vert'; 11 | import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme'; 12 | import getMuiTheme from 'material-ui/styles/getMuiTheme'; 13 | import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; 14 | // import { redA100 } from 'material-ui/styles/colors'; 15 | import Footer from './Footer'; 16 | 17 | // const muiTheme = getMuiTheme({ 18 | // palette: { 19 | // accent1Color: redA100, 20 | // }, 21 | // }); 22 | 23 | const lightTheme = getMuiTheme(); 24 | const darkTheme = getMuiTheme(darkBaseTheme); 25 | 26 | class Master extends Component { 27 | 28 | static propTypes = { 29 | children: PropTypes.node, 30 | }; 31 | 32 | constructor(props) { 33 | super(props); 34 | this.state = { 35 | drawerOpen: false, 36 | theme: lightTheme, 37 | }; 38 | } 39 | 40 | handleDrawerToggle = () => this.setState({ drawerOpen: !this.state.drawerOpen }); 41 | 42 | handleDrawerClose = () => this.setState({ drawerOpen: false }); 43 | 44 | handleNightToggle = () => { 45 | if (this.state.theme === lightTheme) { 46 | this.setState({ theme: darkTheme }); 47 | } else { 48 | this.setState({ theme: lightTheme }); 49 | } 50 | }; 51 | 52 | 53 | render() { 54 | return ( 55 | 56 |
57 | 58 | <AppBar 59 | title={"Adventure Lookup"} 60 | zDepth={1} 61 | onLeftIconButtonTouchTap={this.handleDrawerToggle} 62 | iconElementRight={ 63 | <IconMenu 64 | iconButtonElement={ 65 | <IconButton><MoreVertIcon /></IconButton> 66 | } 67 | targetOrigin={{ horizontal: 'right', vertical: 'top' }} 68 | anchorOrigin={{ horizontal: 'right', vertical: 'top' }} 69 | > 70 | <MenuItem primaryText="Account" /> 71 | <MenuItem primaryText="Help" /> 72 | <MenuItem primaryText="Sign out" /> 73 | </IconMenu> 74 | } 75 | /> 76 | <Drawer 77 | open={this.state.drawerOpen} 78 | docked={false} 79 | onRequestChange={(open) => this.setState({ drawerOpen: open })} 80 | > 81 | 82 | <Link to="/home"><MenuItem onTouchTap={this.handleDrawerClose}>Home</MenuItem></Link> 83 | <Link to="/about"><MenuItem onTouchTap={this.handleDrawerClose}>About</MenuItem></Link> 84 | <Link to="/search"><MenuItem onTouchTap={this.handleDrawerClose}>Find</MenuItem></Link> 85 | <Link to="/browse"><MenuItem onTouchTap={this.handleDrawerClose}>Browse</MenuItem></Link> 86 | <Link to="/add"><MenuItem onTouchTap={this.handleDrawerClose}>Add</MenuItem></Link> 87 | <Link to="/account"><MenuItem onTouchTap={this.handleDrawerClose}>Account</MenuItem></Link> 88 | <MenuItem> 89 | <Toggle label="Toggle Night Mode" onToggle={this.handleNightToggle} /> 90 | </MenuItem> 91 | </Drawer> 92 | <div style={{ minHeight: '80vh' }}> 93 | {this.props.children} 94 | </div> 95 | <Footer style={{ textAlign: 'center' }} /> 96 | </div> 97 | </MuiThemeProvider> 98 | ); 99 | } 100 | } 101 | 102 | export default Master; 103 | -------------------------------------------------------------------------------- /src/components/pages/about/AboutPage.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | class AboutPage extends Component { 4 | render() { 5 | return ( 6 | <div> 7 | <h1>This is the about page!</h1> 8 | <p>On this page, you can read an "interesting" bio about the app.</p> 9 | </div> 10 | ); 11 | } 12 | } 13 | 14 | export default AboutPage; 15 | -------------------------------------------------------------------------------- /src/components/pages/account/AccountPage.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | class AccountPage extends Component { 4 | render() { 5 | return ( 6 | <div> 7 | <h1>This is the account page!</h1> 8 | <p>On this page, you'll be able to do account management stuff, like change your email, password, etc.</p> 9 | <p> 10 | Admin users will have access to an admin dashboard where 11 | they can see and act on items in the moderation queue. 12 | </p> 13 | </div> 14 | ); 15 | } 16 | } 17 | 18 | export default AccountPage; 19 | -------------------------------------------------------------------------------- /src/components/pages/add/AddPage.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | class AddPage extends Component { 4 | render() { 5 | return ( 6 | <div> 7 | <h1>This is the add page!</h1> 8 | <p>On this page, you'll be able to add a new adventure, assuming you're logged in, of course.</p> 9 | </div> 10 | ); 11 | } 12 | } 13 | 14 | export default AddPage; 15 | -------------------------------------------------------------------------------- /src/components/pages/browse/BrowsePage.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | class BrowsePage extends Component { 4 | render() { 5 | return ( 6 | <div> 7 | <h1>This is the browse page!</h1> 8 | <p>On this page, you'll be able to see popular, recommended, and new adventures.</p> 9 | </div> 10 | ); 11 | } 12 | } 13 | 14 | export default BrowsePage; 15 | -------------------------------------------------------------------------------- /src/components/pages/home/HomePage.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | require('./HomePage.scss'); 4 | 5 | class HomePage extends Component { 6 | 7 | render() { 8 | return ( 9 | <div className="hero"> 10 | <img src="images/logo.jpg" alt="logo" /> 11 | <h1>Adventure awaits you!</h1> 12 | <p>Welcome to Adventure Lookup, a search engine for Dungeons and Dragons Adventures</p> 13 | </div> 14 | ); 15 | } 16 | } 17 | 18 | export default HomePage; 19 | -------------------------------------------------------------------------------- /src/components/pages/home/HomePage.scss: -------------------------------------------------------------------------------- 1 | .hero { 2 | padding-top: 15vh; 3 | text-align: center; 4 | } 5 | -------------------------------------------------------------------------------- /src/components/pages/results/ResultsPage.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | class ResultsPage extends Component { 4 | render() { 5 | return ( 6 | <div> 7 | <h1>This is the results page!</h1> 8 | </div> 9 | ); 10 | } 11 | } 12 | 13 | export default ResultsPage; 14 | -------------------------------------------------------------------------------- /src/components/pages/search/SearchPage.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import AutoComplete from 'material-ui/AutoComplete'; 3 | import FlatButton from 'material-ui/FlatButton'; 4 | import Paper from 'material-ui/Paper'; 5 | import RaisedButton from 'material-ui/RaisedButton'; 6 | 7 | const styles = { 8 | paper: { 9 | margin: '10vh 5vw', 10 | padding: '40px', 11 | minHeight: '200px', 12 | }, 13 | buttonContainer: { 14 | margin: '10px', 15 | float: 'right', 16 | }, 17 | button: { 18 | margin: '10px', 19 | }, 20 | }; 21 | 22 | class SearchPage extends Component { 23 | constructor(props) { 24 | super(props); 25 | this.state = { 26 | tags: [], 27 | query: '', 28 | }; 29 | } 30 | 31 | componentDidMount() { 32 | this.getTags(); 33 | } 34 | 35 | getTags() { 36 | // do ajax call to use tags.json in this.state.tags 37 | fetch('/tags.json') 38 | .then((res) => { 39 | return res.json(); 40 | }) 41 | .then((res) => { 42 | this.setState({ tags: res.tags }).bind(SearchPage); 43 | }); 44 | } 45 | 46 | handleSearchInput = (searchText) => { 47 | this.setState({ 48 | query: searchText, 49 | }); 50 | } 51 | 52 | render() { 53 | return ( 54 | <Paper style={styles.paper}> 55 | <AutoComplete 56 | floatingLabelText="Search..." 57 | filter={AutoComplete.fuzzyFilter} 58 | dataSource={this.state.tags} 59 | maxSearchResults={5} 60 | fullWidth={true} 61 | onUpdateInput={this.handleSearchInput} 62 | onNewRequest={this.handleSearchInput} 63 | /> 64 | <div style={styles.buttonContainer}> 65 | <RaisedButton label="Search" secondary={true} style={styles.button} /> 66 | <FlatButton label="[Advanced]" primary={true} style={styles.button} /> 67 | </div> 68 | </Paper> 69 | ); 70 | } 71 | } 72 | 73 | export default SearchPage; 74 | -------------------------------------------------------------------------------- /src/config/README.md: -------------------------------------------------------------------------------- 1 | # About this folder 2 | This folder holds configuration files for different environments. 3 | You can use it to provide your app with different settings based on the 4 | current environment, e.g. to configure different API base urls depending on 5 | whether your setup runs in dev mode or is built for distribution. 6 | You can include the configuration into your code like this: 7 | 8 | ```javascript 9 | let react = require('react/addons'); 10 | let config = require('config'); 11 | class MyComponent extends React.Component { 12 | constructor(props) { 13 | super(props); 14 | let currentAppEnv = config.appEnv; 15 | } 16 | } 17 | ``` 18 | -------------------------------------------------------------------------------- /src/config/base.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Settings configured here will be merged into the final config object. 4 | export default { 5 | } 6 | -------------------------------------------------------------------------------- /src/config/dev.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import baseConfig from './base'; 4 | 5 | let config = { 6 | appEnv: 'dev' // feel free to remove the appEnv property here 7 | }; 8 | 9 | export default Object.freeze(Object.assign({}, baseConfig, config)); 10 | -------------------------------------------------------------------------------- /src/config/dist.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import baseConfig from './base'; 4 | 5 | let config = { 6 | appEnv: 'dist' // feel free to remove the appEnv property here 7 | }; 8 | 9 | export default Object.freeze(Object.assign({}, baseConfig, config)); 10 | -------------------------------------------------------------------------------- /src/config/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import baseConfig from './base'; 4 | 5 | let config = { 6 | appEnv: 'test' // don't remove the appEnv property here 7 | }; 8 | 9 | export default Object.freeze(Object.assign(baseConfig, config)); 10 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdventureLookup/adventurelookup-frontend/1ad23e1b1af809adda91b374daae46513cb3206a/src/favicon.ico -------------------------------------------------------------------------------- /src/images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdventureLookup/adventurelookup-frontend/1ad23e1b1af809adda91b374daae46513cb3206a/src/images/logo.jpg -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | <!doctype html> 2 | <html> 3 | <head> 4 | <meta charset="utf-8"> 5 | <title>Adventure Lookup 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
APPLICATION CONTENT
15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/index.jsx: -------------------------------------------------------------------------------- 1 | import 'core-js/fn/object/assign'; 2 | import 'babel-polyfill'; 3 | import 'whatwg-fetch'; 4 | import React from 'react'; 5 | import ReactDOM from 'react-dom'; 6 | import { Router, useRouterHistory } from 'react-router'; 7 | import AppRoutes from './AppRoutes'; 8 | import { createHashHistory } from 'history'; 9 | 10 | const mountNode = document.getElementById('app'); 11 | 12 | // Needed for onTouchTap 13 | // this dependency should no longer be needed as ofReact 1.0 14 | // Check this repo for details: 15 | // https://github.com/zilverline/react-tap-event-plugin 16 | import injectTapEventPlugin from 'react-tap-event-plugin'; 17 | injectTapEventPlugin(); 18 | 19 | // Render the main component into the dom 20 | ReactDOM.render(( 21 | window.scrollTo(0, 0)} 24 | > 25 | {AppRoutes} 26 | 27 | ), mountNode); 28 | -------------------------------------------------------------------------------- /src/sources/README.md: -------------------------------------------------------------------------------- 1 | # About this folder 2 | This folder will hold all of your **flux** datasources. 3 | You can include them into your components or stores like this: 4 | 5 | ```javascript 6 | let react = require('react/addons'); 7 | let MySource = require('sources/MyAction'); 8 | class MyComponent extends React.Component { 9 | constructor(props) { 10 | super(props); 11 | MySource.getRemoteData(); 12 | } 13 | } 14 | ``` 15 | -------------------------------------------------------------------------------- /src/stores/README.md: -------------------------------------------------------------------------------- 1 | # About this folder 2 | This folder will hold all of your **flux** stores. 3 | You can include them into your components like this: 4 | 5 | ```javascript 6 | let react = require('react/addons'); 7 | let MyStore = require('stores/MyStore'); 8 | class MyComponent extends React.Component { 9 | constructor(props) { 10 | super(props); 11 | MyStore.doSomething(); 12 | } 13 | } 14 | ``` 15 | -------------------------------------------------------------------------------- /src/styles/App.css: -------------------------------------------------------------------------------- 1 | /* Base Application Styles */ 2 | -------------------------------------------------------------------------------- /src/tags.json: -------------------------------------------------------------------------------- 1 | {"tags": ["13th age","giant ant","beast","decrepit skeleton","skeleton","undead","dire rat","dire","giant scorpion","goblin grunt","goblin","humanoid","goblin scum","human thug","human","kobold archer","kobold","kobold warrior","orc warrior","orc","skeletal hound","skeletal archer","wolf","zombie shuffler","zombie","ankheg","bear","giant web spider","goblin shaman","hobgoblin warrior","human zombie","hunting spider","kobold hero","lizardman savage","lizardman","medium white dragon","white","dragon","newly-risen ghoul","ghoul","orc berserker","orc shaman","skeletal warrior","trog","troglodyte","bugbear","dire wolf","dretch","demon","gnoll ranger","gnoll","gnoll savage","hell hound","hungry star","aberration","imp","medium black dragon","black","ochre jelly","ooze","ogre","giant","otyugh","trog chanter","blackamber skeletal legionnaire","derro maniac","dwarf","derro","derro sage","despoiler","dire bear","flesh golem","golem","construct","gnoll war leader","half-orc legionnaire","half-orc","harpy...scale naga","spider mount","winter beast","bergship raider","bronze golem","crustycap","drow darkbolt","ethereal dybbuk","fallen lammasu","gelatinous dodecahedron","ice sorceress","lammasu warrior","manafang naga","moon dragon","umluppuk","void dragon","volcano dragon","adult remorhaz","black skull","cambion hellblade","couatl","elder swaysong naga","frost giant adventurer","iconic chimera","lammasu wizard","lich count","marble golem","ogre lightning mage","parasitic lightning beetle","purple larvae","purple worm","shadow dragon","shadow","shadow thief","deep bulette","djinn","drow cavalry","elder sparkscale naga","elder wendigo","empyrean dragon","hoard spirit","hoardsong dragon","lammasu priest","ogre minion","prismatic ogre mage","skull of the beast","wraith bat","dusk zorigami","efreet","elder manafang naga","massive mutant chuul","elder couatl","greathoard elder","remorhaz queen","ancient purple worm","flamewreathed dragon","lich prince","smoke minions","hagunemnon","tarrasque"]} 2 | -------------------------------------------------------------------------------- /test/actions/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdventureLookup/adventurelookup-frontend/1ad23e1b1af809adda91b374daae46513cb3206a/test/actions/.keep -------------------------------------------------------------------------------- /test/config/ConfigTest.js: -------------------------------------------------------------------------------- 1 | /*eslint-env node, mocha */ 2 | /*global expect */ 3 | /*eslint no-console: 0*/ 4 | 'use strict'; 5 | 6 | import config from 'config'; 7 | 8 | describe('appEnvConfigTests', () => { 9 | it('should load app config file depending on current --env', () => { 10 | expect(config.appEnv).to.equal('test'); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /test/helpers/shallowRenderHelper.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function to get the shallow output for a given component 3 | * As we are using phantom.js, we also need to include the fn.proto.bind shim! 4 | * 5 | * @see http://simonsmith.io/unit-testing-react-components-without-a-dom/ 6 | * @author somonsmith 7 | */ 8 | import React from 'react'; 9 | import TestUtils from 'react-addons-test-utils'; 10 | 11 | /** 12 | * Get the shallow rendered component 13 | * 14 | * @param {Object} component The component to return the output for 15 | * @param {Object} props [optional] The components properties 16 | * @param {Mixed} ...children [optional] List of children 17 | * @return {Object} Shallow rendered output 18 | */ 19 | export default function createComponent(component, props = {}, ...children) { 20 | const shallowRenderer = TestUtils.createRenderer(); 21 | shallowRenderer.render(React.createElement(component, props, children.length > 1 ? children : children[0])); 22 | return shallowRenderer.getRenderOutput(); 23 | } 24 | -------------------------------------------------------------------------------- /test/loadtests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('babel-polyfill'); 4 | require('core-js/fn/object/assign'); 5 | 6 | // Add support for all files in the test directory 7 | const testsContext = require.context('.', true, /(Test\.js$)|(Helper\.js$)/); 8 | testsContext.keys().forEach(testsContext); 9 | -------------------------------------------------------------------------------- /test/sources/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdventureLookup/adventurelookup-frontend/1ad23e1b1af809adda91b374daae46513cb3206a/test/sources/.keep -------------------------------------------------------------------------------- /test/stores/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdventureLookup/adventurelookup-frontend/1ad23e1b1af809adda91b374daae46513cb3206a/test/stores/.keep -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const args = require('minimist')(process.argv.slice(2)); 5 | 6 | // List of allowed environments 7 | const allowedEnvs = ['dev', 'dist', 'test']; 8 | 9 | // Set the correct environment 10 | let env; 11 | if (args._.length > 0 && args._.indexOf('start') !== -1) { 12 | env = 'test'; 13 | } else if (args.env) { 14 | env = args.env; 15 | } else { 16 | env = 'dev'; 17 | } 18 | process.env.REACT_WEBPACK_ENV = env; 19 | 20 | /** 21 | * Build the webpack configuration 22 | * @param {String} wantedEnv The wanted environment 23 | * @return {Object} Webpack config 24 | */ 25 | function buildConfig(wantedEnv) { 26 | let isValid = wantedEnv && wantedEnv.length > 0 && allowedEnvs.indexOf(wantedEnv) !== -1; 27 | let validEnv = isValid ? wantedEnv : 'dev'; 28 | let config = require(path.join(__dirname, 'cfg/' + validEnv)); 29 | return config; 30 | } 31 | 32 | module.exports = buildConfig(env); 33 | --------------------------------------------------------------------------------