├── .eslintignore ├── .eslintrc ├── .github └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .prettierrc ├── .ruby-version ├── .travis.yml ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── README.md ├── _config.yml ├── analytics.js ├── assets └── logos.png ├── generators ├── advanced-base │ ├── README.md │ ├── index.js │ └── templates │ │ ├── babelrc │ │ ├── index.js │ │ ├── src │ │ ├── App.js │ │ ├── Scenes.js │ │ ├── components │ │ │ ├── Button.js │ │ │ ├── ButtonCard.js │ │ │ ├── Page.js │ │ │ ├── ProfileHeader.js │ │ │ ├── SecondaryFlatButton.js │ │ │ ├── TextInput.js │ │ │ ├── Touchable.js │ │ │ ├── __tests__ │ │ │ │ ├── Button.test.js │ │ │ │ └── __snapshots__ │ │ │ │ │ └── Button.test.js.snap │ │ │ └── index.js │ │ ├── lib │ │ │ ├── i18n.js │ │ │ └── package.json │ │ ├── pages │ │ │ ├── Account.js │ │ │ ├── Home.js │ │ │ ├── Landing.js │ │ │ ├── Login.js │ │ │ ├── Signup.js │ │ │ └── index.js │ │ └── theme │ │ │ ├── images │ │ │ ├── default-user-image.png │ │ │ ├── landing.jpg │ │ │ └── logo.png │ │ │ └── index.js │ │ └── translations │ │ ├── en │ │ └── translations.json │ │ ├── fr │ │ └── translations.json │ │ └── index.js ├── app │ └── index.js ├── assets │ ├── README.md │ ├── doc │ │ ├── splashscreen-with-bottom-content.png │ │ └── splashscreen-with-right-side-content.png │ ├── getPixelColor.js │ ├── imageGenerator.js │ ├── index.js │ └── templates │ │ ├── android │ │ ├── colors.xml │ │ ├── launch_screen_bitmap.xml │ │ └── styles.xml │ │ └── ios │ │ ├── AppIconsetContents.json │ │ └── LaunchImageLaunchimageContents.json ├── base │ ├── README.md │ ├── index.js │ └── templates │ │ ├── index.js │ │ └── src │ │ ├── App.js │ │ ├── RootNavigation.js │ │ ├── components │ │ ├── Page.js │ │ └── index.js │ │ ├── modules │ │ ├── App │ │ │ ├── index.js │ │ │ └── module.js │ │ ├── Nav │ │ │ ├── index.js │ │ │ └── module.js │ │ ├── rootEnhancer.js │ │ ├── rootReducer.js │ │ └── store.js │ │ ├── pages │ │ ├── Home │ │ │ ├── Home.component.js │ │ │ ├── Home.container.js │ │ │ ├── Home.style.js │ │ │ └── index.js │ │ └── index.js │ │ └── theme │ │ └── index.js ├── bitrise │ ├── README.md │ ├── index.js │ └── templates │ │ └── bitrise.yml ├── checkversion │ ├── checkUpdate.js │ └── index.js ├── circleci │ ├── README.md │ ├── index.js │ └── templates │ │ └── config.yml ├── fastlane-env │ ├── README.md │ ├── index.js │ └── templates │ │ ├── environment │ │ └── index.js │ │ └── fastlane │ │ ├── env │ │ └── env.secret ├── fastlane-setup │ ├── README.md │ ├── index.js │ └── templates │ │ ├── Gemfile │ │ ├── deploy.sh │ │ ├── env │ │ ├── environment │ │ └── index.js │ │ ├── fastlane │ │ ├── Appfile │ │ ├── Fastfile │ │ └── ios_devices.txt │ │ ├── gitignore │ │ ├── gradleSigning │ │ ├── secrets-scripts │ │ ├── pack-secrets.sh │ │ └── unpack-secrets.sh │ │ └── strings.xml ├── jest │ ├── README.md │ ├── index.js │ └── templates │ │ ├── Button.test.js │ │ ├── FileStub.js │ │ └── firstTest.js ├── lint │ ├── README.md │ ├── index.js │ └── templates │ │ ├── eslintignore │ │ ├── eslintrc │ │ └── prettierrc ├── travisci │ ├── README.md │ ├── index.js │ └── templates │ │ └── travis.yml └── vscode │ ├── README.md │ ├── index.js │ └── templates │ ├── jsconfig.json │ └── settings.json ├── jsconfig.json ├── package.json ├── test.js └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | TestApp 2 | generators/**/templates 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "describe": true, 4 | "it": true 5 | }, 6 | "extends": "universe/node", 7 | "rules": { 8 | "class-methods-use-this": 0, 9 | "key-spacing": 0, 10 | "no-underscore-dangle": 0, 11 | "no-console": 0 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Hi, thanks for submitting a Pull Request! :balloon: 2 | 3 | Before submitting, please be sure to check a few things: 4 | 5 | ## Commit names formatting 6 | 7 | This repository is automatically published to npm with 8 | [semantic-release](https://github.com/semantic-release/semantic-release). 9 | 10 | In order to manage that, your commit should follow the AngularJS commit 11 | conventions 12 | [as explained here](https://github.com/semantic-release/semantic-release#default-commit-message-format) 13 | 14 | You can use `yarn commit` to write a commit respecting this convention. 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | TestApp 3 | AdvancedTestApp 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.3.1 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | branches: 5 | only: 6 | - master 7 | install: 8 | # Install React Native, Yarn and Yeoman: 9 | - npm install 10 | before_script: 11 | - npm prune 12 | after_success: 13 | - npm run semantic-release 14 | branches: 15 | except: 16 | - /^v\d+\.\d+\.\d+$/ 17 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Yeoman generator", 11 | "program": "/usr/local/bin/yo", 12 | "args": ["rn-toolbox:fastlane-env"], 13 | "console": "integratedTerminal", 14 | "internalConsoleOptions": "neverOpen", 15 | "cwd": "${workspaceFolder}/../yourProject" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "prettier.singleQuote": true, 4 | "prettier.trailingComma": "es5" 5 | } 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 BAM 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # React Native Toolbox [![Build Status](https://travis-ci.org/bamlab/generator-rn-toolbox.svg?branch=master)](https://travis-ci.org/bamlab/generator-rn-toolbox) [![NPM downloads](https://img.shields.io/npm/dm/generator-rn-toolbox.svg)](https://www.npmjs.com/package/generator-rn-toolbox) [![license](https://img.shields.io/github/license/mashape/apistatus.svg)]() 6 | 7 | Yeoman generators to kickstart your react-native v0.48+ projects. 8 | 9 | ## ⚠️ Deprecation notice ⚠️ 10 | 11 | > **Dear user**, we are working on a complete rewrite of generator-rn-toolbox 12 | > 13 | > We are be deprecating this repo and migrating its features to [react-native-make](https://github.com/bamlab/react-native-make) 14 | > 15 | > Already available: 16 | > 17 | > - Updated Icons generation with [Android adaptive icons](https://medium.com/google-design/designing-adaptive-icons-515af294c783) 18 | > - Updated SplashScreen generation with iOS _.xib_ files and ready for [react-native-splashscreen](https://github.com/crazycodeboy/react-native-splash-screen) 19 | 20 | ## Features 21 | 22 | In an existing React Native project, our generator contains sub-generators that will help you with: 23 | 24 | - Setup 25 | - [Linting](generators/lint/README.md) -- `yo rn-toolbox:lint` 26 | - [Base project](generators/base/README.md) -- `yo rn-toolbox:base` 27 | - [Advanced project](generators/advanced-base/README.md) -- `yo rn-toolbox:advanced-base` 28 | - [Jest](generators/jest/README.md) -- `yo rn-toolbox:jest` 29 | - [Fastlane setup for multiple environments](generators/fastlane-setup/README.md) -- `yo rn-toolbox:fastlane-setup` 30 | - [Fastlane environment instantiation](generators/fastlane-env/README.md) -- `yo rn-toolbox:fastlane-env` 31 | - [Icons and Splashscreen generation](generators/assets/README.md) -- `yo rn-toolbox:assets [--icon | --splash] ` 32 | - Environment 33 | - [Visual Studio Code](generators/vscode/README.md) -- `yo rn-toolbox:vscode` 34 | - Continuous integration / deployment 35 | - [TravisCI](generators/travisci/README.md) -- `yo rn-toolbox:travisci` 36 | - [Bitrise for continuous deployment](generators/bitrise/README.md) -- `yo rn-toolbox:bitrise` 37 | - [CircleCI for continuous deployment](generators/circleci/README.md) -- `yo rn-toolbox:circleci` 38 | 39 | ## Requirements 40 | 41 | - [ ] You need `node > 6` installed 42 | - [ ] Ruby > `2.2.3` 43 | - [ ] Bundler installed (`gem install bundler`) 44 | - [ ] Yeoman installed (`npm i -g yo`) 45 | - [ ] Yarn installed (`brew install yarn`) 46 | 47 | ## Usage 48 | 49 | Install the main `yeoman` generator: 50 | 51 | ``` 52 | npm install -g yo generator-rn-toolbox 53 | ``` 54 | 55 | Then follow the docs for any sub-generator listed above in the [features](https://github.com/bamlab/generator-rn-toolbox#features). 56 | 57 | If starting from scratch, use the `react-native init && cd ` command to instantiate your React Native Project (for more [go see the official React Native getting started](https://facebook.github.io/react-native/docs/getting-started.html)). 58 | 59 | It is recommended to initiate the git repository right after instantiating the app and to do you first commit. 60 | 61 | It is also recommended to do a separate commit after running each of these steps. 62 | 63 | ## Contributing 64 | 65 | See [our contributing guidelines](https://bamlab.github.io/open-source/#contributing) 66 | 67 | ### Local development 68 | 69 | To run the generator with your local version: 70 | 71 | ```shell 72 | git clone https://github.com/bamlab/generator-rn-toolbox.git 73 | cd generator-rn-toolbox 74 | npm link 75 | ``` 76 | 77 | When you're done, you can run `npm unlink` to stop using your local version. 78 | 79 | ### Disclaimer 80 | 81 | _To better understand your usage of this tool, basic analytics have been enabled. It only records generators usage as anonymous page views and does not track any user information_ 82 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /analytics.js: -------------------------------------------------------------------------------- 1 | const ua = require('universal-analytics'); 2 | 3 | const analytics = ua('UA-145385834-1'); 4 | 5 | module.exports = analytics; 6 | -------------------------------------------------------------------------------- /assets/logos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bamlab/generator-rn-toolbox/1e5604124c0808e9ce448865c2f90d4847f1e4d3/assets/logos.png -------------------------------------------------------------------------------- /generators/advanced-base/README.md: -------------------------------------------------------------------------------- 1 | # Advanced Base Project setup 2 | 3 | *Tired of the same empty initial app? Start with a real React Native Project* 4 | 5 | Use `yo rn-toolbox:advanced-base` to replace the base project 6 | 7 | This generator is an alternative to `yo rn-toolbox:base`. It add a basic navigation and some common component to start faster. 8 | 9 | **Features** 10 | - Centralized App.js 11 | - [react-navigation](https://github.com/react-community/react-navigation) 5 pages setup 12 | - Custom header 13 | - Custom button 14 | - Centralized app style in a theme 15 | - Page container 16 | - 2 dashbord page with tab navigation 17 | - A signup and a Login page with some input fields 18 | - A platform specific design 19 | - i18n support 20 | -------------------------------------------------------------------------------- /generators/advanced-base/index.js: -------------------------------------------------------------------------------- 1 | const Base = require('yeoman-generator'); 2 | const analytics = require('../../analytics'); 3 | 4 | class BaseGenerator extends Base { 5 | initializing() { 6 | analytics.pageview('/advanced-base').send(); 7 | this.composeWith(require.resolve('../checkversion')); 8 | } 9 | 10 | prompting() { 11 | const config = this.fs.readJSON(this.destinationPath('package.json')); 12 | return this.prompt([ 13 | { 14 | type: 'input', 15 | name: 'appName', 16 | message: 'Your react native app directory name', 17 | default: config.name, 18 | }, 19 | ]).then(answers => { 20 | this.answers = answers; 21 | }); 22 | } 23 | 24 | install() { 25 | this.yarnInstall( 26 | [ 27 | 'babel-preset-react-native-stage-0', 28 | 'react-navigation', 29 | 'react-native-vector-icons', 30 | 'react-native-i18n', 31 | ], 32 | { cwd: this.destinationRoot() } 33 | ).then(() => { 34 | this.spawnCommand('react-native', ['link']); 35 | }); 36 | } 37 | 38 | writing() { 39 | this.fs.delete(this.destinationPath('__tests__')); 40 | this.fs.delete(this.destinationPath('App.js')); 41 | this.fs.copyTpl( 42 | this.templatePath('**/*.js'), 43 | this.destinationPath(''), 44 | this.answers 45 | ); 46 | this.fs.copy(this.templatePath('**/*.json'), this.destinationPath('')); 47 | this.fs.copy(this.templatePath('**/*.png'), this.destinationPath('')); 48 | this.fs.copy(this.templatePath('**/*.jpg'), this.destinationPath('')); 49 | this.fs.copyTpl( 50 | this.templatePath('babelrc'), 51 | this.destinationPath('.babelrc') 52 | ); 53 | } 54 | 55 | end() { 56 | this.config.set('advanced-base', true); 57 | this.config.save(); 58 | } 59 | } 60 | 61 | module.exports = BaseGenerator; 62 | -------------------------------------------------------------------------------- /generators/advanced-base/templates/babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-native", "react-native-stage-0/decorator-support"] 3 | } 4 | -------------------------------------------------------------------------------- /generators/advanced-base/templates/index.js: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from 'react-native'; 2 | import App from '<%= appName %>/src/App'; 3 | 4 | AppRegistry.registerComponent('<%= appName %>', () => App); 5 | -------------------------------------------------------------------------------- /generators/advanced-base/templates/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Scenes from './Scenes'; 3 | 4 | const App = () => ; 5 | 6 | export default App; 7 | -------------------------------------------------------------------------------- /generators/advanced-base/templates/src/Scenes.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react'; 3 | import { 4 | createStackNavigator, 5 | createTabNavigator, 6 | HeaderBackButton, 7 | } from 'react-navigation'; 8 | 9 | import * as Pages from './pages'; 10 | import theme from 'theme'; 11 | import I18n from 'lib/i18n'; 12 | import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; 13 | 14 | const TabIcon = props => ; 15 | 16 | const LandingStack = createStackNavigator( 17 | { 18 | landing: { 19 | screen: Pages.Landing, 20 | }, 21 | login: { 22 | screen: Pages.Login, 23 | }, 24 | }, 25 | { 26 | initialRouteName: 'landing', 27 | mode: 'modal', 28 | headerMode: 'none', 29 | navigationOptions: { 30 | header: null, 31 | }, 32 | } 33 | ); 34 | 35 | const SignUpStack = createStackNavigator( 36 | { 37 | signup: { 38 | screen: Pages.Signup, 39 | navigationOptions: props => ({ 40 | title: I18n.t('signup.title'), 41 | headerLeft: ( 42 | { 44 | props.navigation.goBack(null); 45 | }} 46 | tintColor={theme.colors.overPrimary} 47 | /> 48 | ), 49 | }), 50 | }, 51 | }, 52 | { 53 | initialRouteName: 'signup', 54 | navigationOptions: { 55 | headerTintColor: theme.colors.overPrimary, 56 | headerStyle: { 57 | backgroundColor: theme.colors.primary, 58 | }, 59 | }, 60 | } 61 | ); 62 | 63 | const DashboardTab = createTabNavigator( 64 | { 65 | home: { 66 | screen: Pages.Home, 67 | navigationOptions: { 68 | title: I18n.t('home.title'), 69 | tabBarIcon: props => , 70 | }, 71 | }, 72 | account: { 73 | screen: Pages.Account, 74 | navigationOptions: { 75 | title: I18n.t('account.title'), 76 | tabBarIcon: props => , 77 | }, 78 | }, 79 | }, 80 | { 81 | initialRouteName: 'home', 82 | animationEnabled: true, 83 | backBehavior: 'initialRoute', 84 | tabBarOptions: { 85 | activeTintColor: theme.colors.primary, 86 | pressColor: theme.colors.grayLight, 87 | inactiveTintColor: theme.colors.gray, 88 | indicatorStyle: { 89 | backgroundColor: theme.colors.primary, 90 | height: 3, 91 | }, 92 | style: { 93 | backgroundColor: 'white', 94 | }, 95 | }, 96 | } 97 | ); 98 | 99 | const DashboardStack = createStackNavigator( 100 | { 101 | dashboardTabs: { 102 | screen: DashboardTab, 103 | navigationOptions: ({ navigationOptions }) => ({ 104 | ...navigationOptions, 105 | headerStyle: { 106 | ...navigationOptions.headerStyle, 107 | elevation: 0, 108 | }, 109 | }), 110 | }, 111 | }, 112 | { 113 | initialRouteName: 'dashboardTabs', 114 | navigationOptions: { 115 | headerTintColor: theme.colors.overPrimary, 116 | headerStyle: { 117 | backgroundColor: theme.colors.primary, 118 | }, 119 | }, 120 | } 121 | ); 122 | 123 | export const RootNavigator = createStackNavigator( 124 | { 125 | landing: { 126 | screen: LandingStack, 127 | }, 128 | signup: { 129 | screen: SignUpStack, 130 | }, 131 | dashboard: { 132 | screen: DashboardStack, 133 | }, 134 | }, 135 | { 136 | initialRouteName: 'landing', 137 | headerMode: 'none', 138 | } 139 | ); 140 | 141 | export default RootNavigator; 142 | -------------------------------------------------------------------------------- /generators/advanced-base/templates/src/components/Button.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { Text, StyleSheet } from 'react-native'; 4 | 5 | import Touchable from './Touchable'; 6 | 7 | import theme from 'theme'; 8 | 9 | export type Props = { 10 | text?: string, 11 | onPress: () => void, 12 | children?: React.Element<*>, 13 | style?: any, 14 | textStyle?: any, 15 | }; 16 | 17 | type DefaultProps = { 18 | onPress: () => void, 19 | }; 20 | 21 | class Button extends Component { 22 | static defaultProps: DefaultProps = { 23 | onPress: () => {}, 24 | }; 25 | 26 | render() { 27 | const { style, text, textStyle, children, ...rest } = this.props; 28 | const content = text 29 | ? 30 | {text.toUpperCase()} 31 | 32 | : children; 33 | 34 | return ( 35 | 36 | {content} 37 | 38 | ); 39 | } 40 | } 41 | 42 | const styles = StyleSheet.create({ 43 | button: { 44 | alignSelf: 'stretch', 45 | justifyContent: 'center', 46 | height: 40, 47 | backgroundColor: theme.colors.primary, 48 | paddingHorizontal: 8, 49 | borderRadius: 5, 50 | marginVertical: 8, 51 | }, 52 | text: { 53 | ...theme.fonts.button, 54 | color: theme.colors.overPrimary, 55 | textAlign: 'center', 56 | }, 57 | }); 58 | 59 | export default Button; 60 | -------------------------------------------------------------------------------- /generators/advanced-base/templates/src/components/ButtonCard.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { PureComponent } from 'react'; 3 | import { StyleSheet, View, Text } from 'react-native'; 4 | import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; 5 | 6 | import { Touchable } from 'components'; 7 | import theme from 'theme'; 8 | 9 | type Props = { 10 | text: string, 11 | onPress: ?Function, 12 | }; 13 | 14 | class ButtonCard extends PureComponent { 15 | render() { 16 | return ( 17 | 18 | 19 | 20 | {this.props.text} 21 | 22 | 23 | 24 | 25 | ); 26 | } 27 | } 28 | 29 | const styles = StyleSheet.create({ 30 | card: { 31 | backgroundColor: 'white', 32 | alignSelf: 'stretch', 33 | paddingHorizontal: theme.defaultPadding / 2, 34 | }, 35 | contentContainer: { 36 | borderBottomWidth: 1, 37 | borderColor: theme.colors.grayLighter, 38 | 39 | flexDirection: 'row', 40 | justifyContent: 'space-between', 41 | alignItems: 'center', 42 | minHeight: 55, 43 | }, 44 | text: { 45 | ...theme.fonts.button, 46 | }, 47 | }); 48 | 49 | export default ButtonCard; 50 | -------------------------------------------------------------------------------- /generators/advanced-base/templates/src/components/Page.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { View, StyleSheet, Image, Dimensions } from 'react-native'; 3 | import theme from 'theme'; 4 | 5 | type Props = { 6 | children: React.Element<*>, 7 | noPadding: boolean, 8 | noNavBar: boolean, 9 | backgroundColor: string, 10 | style?: any, 11 | backgroundImage?: any, 12 | }; 13 | 14 | type DefaultProps = { 15 | children: React.Element<*>, 16 | noPadding: boolean, 17 | noNavBar: boolean, 18 | backgroundColor: string, 19 | }; 20 | 21 | class Page extends Component { 22 | static defaultProps: DefaultProps = { 23 | children: null, 24 | noPadding: false, 25 | noNavBar: false, 26 | backgroundColor: theme.colors.background, 27 | }; 28 | 29 | render() { 30 | const containerStyle = StyleSheet.flatten([ 31 | styles.page, 32 | { 33 | paddingTop: this.props.noNavBar ? 0 : 16, 34 | paddingHorizontal: this.props.noPadding ? 0 : 32, 35 | backgroundColor: this.props.backgroundColor, 36 | }, 37 | this.props.style, 38 | ]); 39 | 40 | return ( 41 | 42 | {this.props.backgroundImage && 43 | } 44 | {this.props.children} 45 | 46 | ); 47 | } 48 | } 49 | 50 | const styles = StyleSheet.create({ 51 | page: { 52 | flex: 1, 53 | flexDirection: 'column', 54 | justifyContent: 'flex-start', 55 | }, 56 | image: { 57 | position: 'absolute', 58 | top: 0, 59 | left: 0, 60 | width: Dimensions.get('window').width, 61 | height: Dimensions.get('window').height, 62 | }, 63 | }); 64 | 65 | export default Page; 66 | -------------------------------------------------------------------------------- /generators/advanced-base/templates/src/components/ProfileHeader.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { StyleSheet, View, Image, Text, ActivityIndicator } from 'react-native'; 4 | import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; 5 | 6 | import { Page, Touchable } from 'components'; 7 | import theme from 'theme'; 8 | 9 | type Props = { 10 | user: ?Object, 11 | onPress: ?Function, 12 | }; 13 | 14 | class ProfileHeader extends Component { 15 | render() { 16 | const { user } = this.props; 17 | 18 | return ( 19 | 20 | 21 | 22 | 23 | 24 | {user 25 | ? 26 | : } 27 | 28 | 29 | 30 | {user && 31 | 32 | 33 | {user.firstName} {user.lastName} 34 | 35 | } 36 | 37 | ); 38 | } 39 | } 40 | 41 | const styles = StyleSheet.create({ 42 | container: { 43 | backgroundColor: theme.colors.primary, 44 | alignSelf: 'stretch', 45 | alignItems: 'center', 46 | paddingVertical: 16, 47 | }, 48 | imageContainer: { 49 | marginHorizontal: Page.DEFAULT_PADDING, 50 | }, 51 | userImage: { 52 | height: 70, 53 | width: 70, 54 | borderRadius: 35, 55 | borderWidth: 2, 56 | borderColor: 'white', 57 | }, 58 | name: { 59 | color: 'white', 60 | marginTop: 10, 61 | fontSize: 18, 62 | textAlign: 'center', 63 | }, 64 | imageOverlay: { 65 | position: 'absolute', 66 | top: 0, 67 | height: 70, 68 | width: 70, 69 | borderRadius: 35, 70 | 71 | backgroundColor: '#00000055', 72 | justifyContent: 'center', 73 | alignItems: 'center', 74 | }, 75 | }); 76 | 77 | export default ProfileHeader; 78 | -------------------------------------------------------------------------------- /generators/advanced-base/templates/src/components/SecondaryFlatButton.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { StyleSheet } from 'react-native'; 4 | 5 | import theme from 'theme'; 6 | 7 | import Button from './Button'; 8 | import type { Props } from './Button'; 9 | 10 | class SecondaryFlatButton extends Component { 11 | render() { 12 | return ( 13 | , 11 | ).toJSON(); 12 | expect(tree).toMatchSnapshot(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /generators/jest/templates/FileStub.js: -------------------------------------------------------------------------------- 1 | module.exports = 'test-file-stub'; 2 | -------------------------------------------------------------------------------- /generators/jest/templates/firstTest.js: -------------------------------------------------------------------------------- 1 | describe('FirstTest', () => { 2 | it('should be valid', () => { 3 | expect(true).toBe(true); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /generators/lint/README.md: -------------------------------------------------------------------------------- 1 | # Adding linting 2 | 3 | *Eslint ensures a consistent coding style. For React Native newcomers it will also help you in your path to learn it.* 4 | 5 | *Prettier autoformats your code as you save. No more wasting time indenting, adding a missing comma or splitting lines* 6 | 7 | Use `yo rn-toolbox:lint` to setup eslint-config-universe with prettier enabled. 8 | -------------------------------------------------------------------------------- /generators/lint/index.js: -------------------------------------------------------------------------------- 1 | const Base = require('yeoman-generator'); 2 | const analytics = require('../../analytics'); 3 | 4 | class LintGenerator extends Base { 5 | initializing() { 6 | analytics.pageview('/lint').send(); 7 | this.composeWith('rn-toolbox:checkversion'); 8 | } 9 | 10 | install() { 11 | this.yarnInstall(['prettier', 'eslint', 'eslint-config-universe-error'], { 12 | dev: true, 13 | cwd: this.destinationRoot(), 14 | }).then(() => { 15 | this.spawnCommand('yarn', ['lint', '--', '--fix'], { 16 | cwd: this.destinationPath(), 17 | }); 18 | }); 19 | } 20 | 21 | writing() { 22 | this.fs.copyTpl( 23 | this.templatePath('eslintrc'), 24 | this.destinationPath('.eslintrc') 25 | ); 26 | this.fs.copyTpl( 27 | this.templatePath('eslintignore'), 28 | this.destinationPath('.eslintignore') 29 | ); 30 | this.fs.copyTpl( 31 | this.templatePath('prettierrc'), 32 | this.destinationPath('.prettierrc') 33 | ); 34 | this.fs.extendJSON( 35 | 'package.json', 36 | { 37 | scripts: { lint: 'eslint . --quiet' }, 38 | }, 39 | null, 40 | 2 41 | ); 42 | } 43 | 44 | end() { 45 | this.config.set('lint', true); 46 | this.config.save(); 47 | } 48 | } 49 | 50 | module.exports = LintGenerator; 51 | -------------------------------------------------------------------------------- /generators/lint/templates/eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/android 3 | **/ios 4 | **/vendors 5 | -------------------------------------------------------------------------------- /generators/lint/templates/eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["universe-error/native"], 3 | "rules": { 4 | "prettier/prettier": "error" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /generators/lint/templates/prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "singleQuote": true, 4 | "bracketSpacing": true, 5 | "tabWidth": 2, 6 | "printWidth": 100 7 | } 8 | -------------------------------------------------------------------------------- /generators/travisci/README.md: -------------------------------------------------------------------------------- 1 | # TravisCI setup for continuous integration 2 | 3 | *TravisCI is a continuous integration solution allowing you to run your tests each time you do a pull request. We advocate using it for unit tests as it is faster than Bitrise to execute them.* 4 | 5 | In order to make Travis working on your app, you need to create a .travis.yml file by running 6 | 7 | We recommend using Travis for the tests as it comes with yarn preinstalled and allows you to save your Jest cache 8 | 9 | `yo rn-toolbox:travisci` 10 | 11 | Then you have to configure the branch on which you want to trigger travisCI webhook on :) 12 | -------------------------------------------------------------------------------- /generators/travisci/index.js: -------------------------------------------------------------------------------- 1 | const Base = require('yeoman-generator'); 2 | const analytics = require('../../analytics'); 3 | 4 | class CircleGenerator extends Base { 5 | initializing() { 6 | analytics.pageview('/travisci').send(); 7 | this.composeWith('rn-toolbox:checkversion'); 8 | } 9 | 10 | writing() { 11 | this.fs.copyTpl( 12 | this.templatePath('travis.yml'), 13 | this.destinationPath('.travis.yml') 14 | ); 15 | } 16 | 17 | end() { 18 | this.config.set('travis', true); 19 | this.config.save(); 20 | } 21 | } 22 | 23 | module.exports = CircleGenerator; 24 | -------------------------------------------------------------------------------- /generators/travisci/templates/travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: 3 | directories: 4 | - jest/tmp 5 | - node_modules 6 | -------------------------------------------------------------------------------- /generators/vscode/README.md: -------------------------------------------------------------------------------- 1 | # Visual Studio Code Setup 2 | 3 | *Sets up VSCode for ultimate productivity with React Native* 4 | 5 | Use `yo rn-toolbox:vscode` to set it up 6 | -------------------------------------------------------------------------------- /generators/vscode/index.js: -------------------------------------------------------------------------------- 1 | const Base = require('yeoman-generator'); 2 | const templateSettings = require('./templates/settings.json'); 3 | const analytics = require('../../analytics'); 4 | 5 | class VSCodeGenerator extends Base { 6 | initializing() { 7 | analytics.pageview('/vscode').send(); 8 | this.composeWith('rn-toolbox:checkversion'); 9 | } 10 | 11 | prompting() { 12 | const config = this.fs.readJSON(this.destinationPath('package.json')); 13 | return this.prompt([ 14 | { 15 | type: 'input', 16 | name: 'appName', 17 | message: 'Your react native app directory name', 18 | default: config.name, 19 | }, 20 | ]).then(answers => { 21 | this.answers = answers; 22 | }); 23 | } 24 | writing() { 25 | this.fs.copyTpl( 26 | this.templatePath('jsconfig.json'), 27 | this.destinationPath('jsconfig.json'), 28 | this.answers 29 | ); 30 | this.fs.extendJSON( 31 | this.destinationPath('.vscode/settings.json'), 32 | templateSettings 33 | ); 34 | } 35 | 36 | end() { 37 | this.config.set('vscode', true); 38 | this.config.save(); 39 | } 40 | } 41 | 42 | module.exports = VSCodeGenerator; 43 | -------------------------------------------------------------------------------- /generators/vscode/templates/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "experimentalDecorators": true, 4 | "allowSyntheticDefaultImports": true, 5 | "baseUrl": ".", 6 | "paths": { 7 | "<%= appName %>/*": "./*" 8 | } 9 | }, 10 | "exclude": [ 11 | "node_modules" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /generators/vscode/templates/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "javascript.validate.enable": false 3 | } 4 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6" 4 | }, 5 | "exclude": [ 6 | "node_modules", 7 | "**/node_modules/*" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-rn-toolbox", 3 | "version": "0.0.0-managed-by-semantic-release", 4 | "description": "React-Native generators to kickstart your project", 5 | "scripts": { 6 | "lint": "eslint .", 7 | "test": "echo \"Error: no test specified\" && exit 0", 8 | "commitmsg": "validate-commit-msg", 9 | "semantic-release": "semantic-release", 10 | "commit": "git-cz", 11 | "travis-deploy-once": "travis-deploy-once" 12 | }, 13 | "keywords": [ 14 | "yeoman-generator", 15 | "react-native", 16 | "generator", 17 | "react", 18 | "native", 19 | "toolbox", 20 | "fastlane", 21 | "eslint", 22 | "boilerplate", 23 | "environments", 24 | "circleci", 25 | "bitrise", 26 | "travisci", 27 | "circleci", 28 | "ci", 29 | "wallabyjs", 30 | "visual studio code", 31 | "vscode" 32 | ], 33 | "repository": { 34 | "type": "git", 35 | "url": "https://github.com/bamlab/generator-rn-toolbox" 36 | }, 37 | "dependencies": { 38 | "bluebird": "^3.5.0", 39 | "color-js": "^1.0.4", 40 | "colors": "^1.1.2", 41 | "compare-version": "^0.1.2", 42 | "download-file-sync": "^1.0.4", 43 | "fs-extra": "^4.0.2", 44 | "gm": "^1.23.0", 45 | "randomstring": "^1.1.5", 46 | "universal-analytics": "^0.4.20", 47 | "yeoman-generator": "^2.0.1" 48 | }, 49 | "devDependencies": { 50 | "commitizen": "^2.9.6", 51 | "cross-spawn": "^5.1.0", 52 | "cz-conventional-changelog": "^2.0.0", 53 | "eslint": "^4.10.0", 54 | "eslint-config-universe": "^1.0.7", 55 | "husky": "^0.14.3", 56 | "jest": "^21.2.1", 57 | "prettier": "^1.11.1", 58 | "semantic-release": "^15.9.9", 59 | "travis-deploy-once": "^5.0.2", 60 | "validate-commit-msg": "^2.14.0", 61 | "yeoman-environment": "^2.0.5", 62 | "yeoman-test": "^1.7.0" 63 | }, 64 | "config": { 65 | "commitizen": { 66 | "path": "./node_modules/cz-conventional-changelog" 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | require('colors'); 3 | const path = require('path'); 4 | const spawn = require('cross-spawn'); 5 | const helpers = require('yeoman-test'); 6 | 7 | const appName = 'TestApp'; 8 | 9 | function createProject() { 10 | console.log('## Creating project ##'.cyan); 11 | spawn.sync('react-native', ['init', appName], { 12 | cwd: __dirname, 13 | stdio: 'inherit', 14 | }); 15 | } 16 | 17 | function installLint() { 18 | console.log('## Installing Lint ##'.cyan); 19 | return helpers 20 | .run(path.join(__dirname, 'generators/lint')) 21 | .cd(path.join(__dirname, appName)) 22 | .withOptions({ skipInstall: false }) 23 | .toPromise(); 24 | } 25 | 26 | function installBase() { 27 | console.log('## Installing Base Project ##'.cyan); 28 | return helpers 29 | .run(path.join(__dirname, 'generators/base')) 30 | .cd(path.join(__dirname, appName)) 31 | .withOptions({ skipInstall: false }) 32 | .withPrompts({ appName }) 33 | .toPromise(); 34 | } 35 | 36 | function installJest() { 37 | console.log('## Installing Jest ##'.cyan); 38 | return helpers 39 | .run(path.join(__dirname, 'generators/jest')) 40 | .cd(path.join(__dirname, appName)) 41 | .withOptions({ skipInstall: false }) 42 | .withPrompts({ appName }) 43 | .toPromise(); 44 | } 45 | 46 | function installFastlane() { 47 | console.log('## Installing Fastlane ##'.cyan); 48 | return helpers 49 | .run(path.join(__dirname, 'generators/fastlane')) 50 | .cd(path.join(__dirname, appName)) 51 | .withOptions({ skipInstall: false }) 52 | .withPrompts({ 53 | companyName: 'BAM', 54 | appName, 55 | projectName: appName, 56 | stagingAppId: 'tech.bam.rntest.staging', 57 | prodAppId: 'tech.bam.rntest', 58 | matchGit: process.env.RN_MATCH_GIT, 59 | appleId: process.env.RN_APPLE_ID, 60 | stagingAppleTeamId: process.env.RN_STAGING_APPLE_TEAM_ID, 61 | prodAppleTeamId: process.env.RN_PROD_APPLE_TEAM_ID, 62 | itunesTeamId: process.env.RN_ITUNES_TEAM_ID, 63 | keystorePassword: 'TestTest', 64 | hockeyAppToken: process.env.RN_HOCKEY_APP_TOKEN, 65 | }) 66 | .toPromise(); 67 | } 68 | 69 | function installBitrise() { 70 | console.log('## Installing Bitrise ##'.cyan); 71 | return helpers 72 | .run(path.join(__dirname, 'generators/bitrise')) 73 | .cd(path.join(__dirname, appName)) 74 | .withOptions({ skipInstall: false }) 75 | .withPrompts({ 76 | reactNativeDirectory: '.', 77 | androidProdAppId: 'tech.bam.rntest', 78 | }) 79 | .toPromise(); 80 | } 81 | 82 | function testProject() { 83 | console.log('## Testing Project ##'.cyan); 84 | spawn.sync('npm', ['test'], { 85 | cwd: path.join(__dirname, appName), 86 | stdio: 'inherit', 87 | }); 88 | } 89 | 90 | createProject(); 91 | installLint() 92 | .then(installBase) 93 | .then(installJest) 94 | .then(installFastlane) 95 | .then(installBitrise) 96 | .then(testProject); 97 | --------------------------------------------------------------------------------