├── .all-contributorsrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── issue-close-app.yml └── lock.yml ├── .gitignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .stylelintrc ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── app ├── .htaccess ├── .nginx.conf ├── app.tsx ├── components │ ├── A │ │ ├── index.ts │ │ └── tests │ │ │ └── index.test.tsx │ ├── Button │ │ ├── A.ts │ │ ├── StyledButton.ts │ │ ├── Wrapper.ts │ │ ├── buttonStyles.ts │ │ ├── index.tsx │ │ └── tests │ │ │ ├── A.test.tsx │ │ │ ├── StyledButton.test.tsx │ │ │ ├── Wrapper.test.tsx │ │ │ └── index.test.tsx │ ├── Footer │ │ ├── Wrapper.ts │ │ ├── index.tsx │ │ ├── messages.ts │ │ └── tests │ │ │ ├── Wrapper.test.tsx │ │ │ ├── __snapshots__ │ │ │ └── index.test.tsx.snap │ │ │ └── index.test.tsx │ ├── H1 │ │ ├── index.ts │ │ └── tests │ │ │ └── index.test.tsx │ ├── H2 │ │ ├── index.ts │ │ └── tests │ │ │ └── index.test.tsx │ ├── H3 │ │ ├── index.tsx │ │ └── tests │ │ │ └── index.test.tsx │ ├── Header │ │ ├── A.ts │ │ ├── HeaderLink.ts │ │ ├── Img.ts │ │ ├── NavBar.ts │ │ ├── banner.jpg │ │ ├── index.tsx │ │ ├── messages.ts │ │ └── tests │ │ │ ├── A.test.tsx │ │ │ ├── Img.test.tsx │ │ │ ├── __snapshots__ │ │ │ ├── A.test.tsx.snap │ │ │ ├── Img.test.tsx.snap │ │ │ └── index.test.tsx.snap │ │ │ └── index.test.tsx │ ├── Img │ │ ├── index.tsx │ │ └── tests │ │ │ └── index.test.tsx │ ├── IssueIcon │ │ ├── index.tsx │ │ └── tests │ │ │ └── index.test.tsx │ ├── List │ │ ├── Ul.ts │ │ ├── Wrapper.ts │ │ ├── index.tsx │ │ └── tests │ │ │ ├── Ul.test.tsx │ │ │ ├── Wrapper.test.tsx │ │ │ └── index.test.tsx │ ├── ListItem │ │ ├── Item.ts │ │ ├── Wrapper.ts │ │ ├── index.tsx │ │ └── tests │ │ │ ├── Item.test.tsx │ │ │ ├── Wrapper.test.tsx │ │ │ └── index.test.tsx │ ├── LoadingIndicator │ │ ├── Circle.tsx │ │ ├── Wrapper.ts │ │ ├── index.tsx │ │ └── tests │ │ │ ├── Circle.test.tsx │ │ │ ├── Wrapper.test.tsx │ │ │ ├── __snapshots__ │ │ │ └── index.test.tsx.snap │ │ │ └── index.test.tsx │ ├── ReposList │ │ ├── index.tsx │ │ └── tests │ │ │ ├── __snapshots__ │ │ │ └── index.test.tsx.snap │ │ │ └── index.test.tsx │ ├── Toggle │ │ ├── Select.ts │ │ ├── index.tsx │ │ └── tests │ │ │ ├── Select.test.tsx │ │ │ ├── __snapshots__ │ │ │ └── index.test.tsx.snap │ │ │ └── index.test.tsx │ └── ToggleOption │ │ ├── index.tsx │ │ └── tests │ │ ├── __snapshots__ │ │ └── index.test.tsx.snap │ │ └── index.test.tsx ├── configureStore.ts ├── containers │ ├── App │ │ ├── actions.ts │ │ ├── constants.ts │ │ ├── index.tsx │ │ ├── reducer.ts │ │ ├── selectors.ts │ │ ├── tests │ │ │ ├── __snapshots__ │ │ │ │ └── index.test.tsx.snap │ │ │ ├── actions.test.ts │ │ │ ├── index.test.tsx │ │ │ ├── reducer.test.ts │ │ │ └── selectors.test.ts │ │ └── types.ts │ ├── FeaturePage │ │ ├── List.ts │ │ ├── ListItem.ts │ │ ├── ListItemTitle.ts │ │ ├── Loadable.tsx │ │ ├── index.tsx │ │ ├── messages.ts │ │ └── tests │ │ │ ├── List.test.tsx │ │ │ ├── ListItem.test.tsx │ │ │ ├── ListItemTitle.test.tsx │ │ │ ├── __snapshots__ │ │ │ └── index.test.tsx.snap │ │ │ └── index.test.tsx │ ├── HomePage │ │ ├── AtPrefix.ts │ │ ├── CenteredSection.ts │ │ ├── Form.ts │ │ ├── Input.ts │ │ ├── Loadable.tsx │ │ ├── Section.ts │ │ ├── actions.ts │ │ ├── constants.ts │ │ ├── index.tsx │ │ ├── messages.ts │ │ ├── reducer.ts │ │ ├── saga.ts │ │ ├── selectors.ts │ │ ├── tests │ │ │ ├── AtPrefix.test.tsx │ │ │ ├── CenteredSection.test.tsx │ │ │ ├── Form.test.tsx │ │ │ ├── Input.test.tsx │ │ │ ├── Section.test.tsx │ │ │ ├── __snapshots__ │ │ │ │ ├── index.test.tsx.snap │ │ │ │ └── saga.test.ts.snap │ │ │ ├── actions.test.ts │ │ │ ├── index.test.tsx │ │ │ ├── reducer.test.ts │ │ │ ├── saga.test.ts │ │ │ └── selectors.test.ts │ │ └── types.ts │ ├── LanguageProvider │ │ ├── actions.ts │ │ ├── constants.ts │ │ ├── index.tsx │ │ ├── reducer.ts │ │ ├── selectors.ts │ │ ├── tests │ │ │ ├── actions.test.ts │ │ │ ├── index.test.tsx │ │ │ ├── reducer.test.ts │ │ │ └── selectors.test.ts │ │ └── types.ts │ ├── LocaleToggle │ │ ├── Wrapper.ts │ │ ├── index.tsx │ │ ├── messages.ts │ │ └── tests │ │ │ ├── Wrapper.test.tsx │ │ │ ├── __snapshots__ │ │ │ └── index.test.tsx.snap │ │ │ └── index.test.tsx │ ├── NotFoundPage │ │ ├── Loadable.tsx │ │ ├── index.tsx │ │ ├── messages.ts │ │ └── tests │ │ │ └── index.test.tsx │ └── RepoListItem │ │ ├── IssueIcon.ts │ │ ├── IssueLink.ts │ │ ├── RepoLink.ts │ │ ├── Wrapper.ts │ │ ├── index.tsx │ │ ├── tests │ │ ├── IssueIcon.test.tsx │ │ ├── IssueLink.test.tsx │ │ ├── RepoLink.test.tsx │ │ ├── Wrapper.test.tsx │ │ ├── __snapshots__ │ │ │ ├── IssueIcon.test.tsx.snap │ │ │ ├── IssueLink.test.tsx.snap │ │ │ ├── RepoLink.test.tsx.snap │ │ │ └── index.test.tsx.snap │ │ └── index.test.tsx │ │ └── types.ts ├── global-styles.ts ├── i18n.ts ├── images │ ├── favicon.ico │ └── icon-512x512.png ├── index.html ├── locales.ts ├── reducers.ts ├── styles │ └── styled-components.ts ├── tests │ ├── i18n.test.ts │ └── store.test.ts ├── translations │ ├── de.json │ └── en.json ├── types │ ├── index.ts │ ├── jest-dom.d.ts │ └── react-intl.d.ts ├── utils.d.ts └── utils │ ├── history.ts │ ├── loadable.tsx │ ├── redux-injectors.tsx │ ├── request.ts │ └── tests │ ├── __snapshots__ │ └── loadable.test.tsx.snap │ ├── loadable.index.tsx │ ├── loadable.test.tsx │ └── request.test.ts ├── appveyor.yml ├── babel.config.js ├── docs ├── README.md └── general │ ├── code-samples.md │ └── key-notes.md ├── internals ├── generators │ ├── component │ │ ├── index.js │ │ ├── index.tsx.hbs │ │ ├── loadable.ts.hbs │ │ ├── messages.ts.hbs │ │ └── test.tsx.hbs │ ├── container │ │ ├── actions.test.ts.hbs │ │ ├── actions.ts.hbs │ │ ├── appendApplicationRootState.hbs │ │ ├── constants.ts.hbs │ │ ├── importContainerState.hbs │ │ ├── index.js │ │ ├── index.tsx.hbs │ │ ├── messages.ts.hbs │ │ ├── reducer.test.ts.hbs │ │ ├── reducer.ts.hbs │ │ ├── saga.test.ts.hbs │ │ ├── saga.ts.hbs │ │ ├── selectors.test.ts.hbs │ │ ├── selectors.ts.hbs │ │ ├── test.tsx.hbs │ │ └── types.ts.hbs │ ├── index.js │ ├── language │ │ ├── add-locale-data.hbs │ │ ├── app-locale.hbs │ │ ├── format-translation-messages.hbs │ │ ├── index.js │ │ ├── intl-locale-data.hbs │ │ ├── polyfill-intl-locale.hbs │ │ ├── translation-messages.hbs │ │ └── translations-json.hbs │ └── utils │ │ └── componentExists.js ├── mocks │ ├── cssModule.js │ └── image.js ├── scripts │ ├── analyze.js │ ├── clean.js │ ├── extract-intl.js │ ├── generate-templates-for-linting.js │ ├── helpers │ │ ├── checkmark.js │ │ ├── get-required-node-npm-versions.js │ │ ├── git-utils.js │ │ ├── progress.js │ │ └── xmark.js │ ├── npmcheckversion.js │ └── setup.js ├── templates │ ├── app.tsx │ ├── configureStore.ts │ ├── containers │ │ ├── App │ │ │ ├── constants.ts │ │ │ ├── index.tsx │ │ │ ├── selectors.ts │ │ │ └── tests │ │ │ │ ├── __snapshots__ │ │ │ │ └── index.test.tsx.snap │ │ │ │ ├── index.test.tsx │ │ │ │ └── selectors.test.ts │ │ ├── HomePage │ │ │ ├── Loadable.ts │ │ │ ├── index.tsx │ │ │ ├── messages.ts │ │ │ └── tests │ │ │ │ ├── __snapshots__ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ ├── LanguageProvider │ │ │ ├── actions.ts │ │ │ ├── constants.ts │ │ │ ├── index.tsx │ │ │ ├── reducer.ts │ │ │ ├── selectors.ts │ │ │ └── types.ts │ │ └── NotFoundPage │ │ │ ├── Loadable.ts │ │ │ ├── index.tsx │ │ │ ├── messages.ts │ │ │ └── tests │ │ │ ├── __snapshots__ │ │ │ └── index.test.tsx.snap │ │ │ └── index.test.tsx │ ├── global-styles.ts │ ├── i18n.ts │ ├── index.html │ ├── locales.ts │ ├── reducers.ts │ ├── tests │ │ ├── i18n.test.ts │ │ └── store.test.ts │ ├── translations │ │ └── en.json │ ├── types │ │ └── index.ts │ └── utils │ │ ├── history.ts │ │ ├── loadable.tsx │ │ ├── redux-injectors.tsx │ │ ├── request.ts │ │ └── tests │ │ ├── __snapshots__ │ │ └── loadable.test.tsx.snap │ │ ├── loadable.index.tsx │ │ ├── loadable.test.tsx │ │ └── request.test.ts ├── testing │ └── test-bundler.js └── webpack │ ├── webpack.base.babel.js │ ├── webpack.dev.babel.js │ └── webpack.prod.babel.js ├── jest.config.js ├── package-lock.json ├── package.json ├── server ├── argv.js ├── index.js ├── logger.js ├── middlewares │ ├── addDevMiddlewares.js │ ├── addProdMiddlewares.js │ └── frontendMiddleware.js └── port.js ├── tsconfig.eslint.json └── tsconfig.json /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "react-boilerplate-typescript", 3 | "projectOwner": "react-boilerplate-typescript", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 80, 10 | "commit": true, 11 | "contributors": [ 12 | { 13 | "login": "Can-Sahin", 14 | "name": "Can Sahin", 15 | "avatar_url": "https://avatars2.githubusercontent.com/u/33245689?v=4", 16 | "profile": "https://github.com/Can-Sahin", 17 | "contributions": [ 18 | "code", 19 | "doc", 20 | "ideas", 21 | "review", 22 | "test" 23 | ] 24 | }, 25 | { 26 | "login": "GrayStrider", 27 | "name": "Gray Strider", 28 | "avatar_url": "https://avatars0.githubusercontent.com/u/43771776?s=460&v=4", 29 | "profile": "https://github.com/GrayStrider", 30 | "contributions": [ 31 | "code", 32 | "tool", 33 | "review" 34 | ] 35 | }, 36 | { 37 | "login": "rajatkantinandi", 38 | "name": "Rajat Kanti Nandi", 39 | "avatar_url": "https://avatars1.githubusercontent.com/u/17743895?v=4", 40 | "profile": "https://twitter.com/rajatkantinandi", 41 | "contributions": [ 42 | "tool" 43 | ] 44 | } 45 | ], 46 | "contributorsPerLine": 8, 47 | "commitConvention": "none" 48 | } 49 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | insert_final_newline = true 9 | indent_style = space 10 | indent_size = 2 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | internals/scripts 2 | internals/generators 3 | internals/templates 4 | server/ 5 | *.html 6 | node_modules 7 | coverage 8 | build 9 | node_modules -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # From https://github.com/Danimoth/gitattributes/blob/master/Web.gitattributes 2 | 3 | # Handle line endings automatically for files detected as text 4 | # and leave all files detected as binary untouched. 5 | * text=auto 6 | 7 | # 8 | # The above will handle all files NOT found below 9 | # 10 | 11 | # 12 | ## These files are text and should be normalized (Convert crlf => lf) 13 | # 14 | 15 | # source code 16 | *.php text 17 | *.css text 18 | *.sass text 19 | *.scss text 20 | *.less text 21 | *.styl text 22 | *.js text eol=lf 23 | *.coffee text 24 | *.json text 25 | *.htm text 26 | *.html text 27 | *.xml text 28 | *.svg text 29 | *.txt text 30 | *.ini text 31 | *.inc text 32 | *.pl text 33 | *.rb text 34 | *.py text 35 | *.scm text 36 | *.sql text 37 | *.sh text 38 | *.bat text 39 | 40 | # templates 41 | *.ejs text 42 | *.hbt text 43 | *.jade text 44 | *.haml text 45 | *.hbs text 46 | *.dot text 47 | *.tmpl text 48 | *.phtml text 49 | 50 | # server config 51 | .htaccess text 52 | .nginx.conf text 53 | 54 | # git config 55 | .gitattributes text 56 | .gitignore text 57 | .gitconfig text 58 | 59 | # code analysis config 60 | .jshintrc text 61 | .jscsrc text 62 | .jshintignore text 63 | .csslintrc text 64 | 65 | # misc config 66 | *.yaml text 67 | *.yml text 68 | .editorconfig text 69 | 70 | # build config 71 | *.npmignore text 72 | *.bowerrc text 73 | 74 | # Heroku 75 | Procfile text 76 | .slugignore text 77 | 78 | # Documentation 79 | *.md text 80 | LICENSE text 81 | AUTHORS text 82 | 83 | 84 | # 85 | ## These files are binary and should be left untouched 86 | # 87 | 88 | # (binary is a macro for -text -diff) 89 | *.png binary 90 | *.jpg binary 91 | *.jpeg binary 92 | *.gif binary 93 | *.ico binary 94 | *.mov binary 95 | *.mp4 binary 96 | *.mp3 binary 97 | *.flv binary 98 | *.fla binary 99 | *.swf binary 100 | *.gz binary 101 | *.zip binary 102 | *.7z binary 103 | *.ttf binary 104 | *.eot binary 105 | *.woff binary 106 | *.pyc binary 107 | *.pdf binary 108 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Global owners 2 | * @Can-Sahin 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | Before opening a new issue, please take a moment to review our [**community guidelines**](https://github.com/react-boilerplate/react-boilerplate/blob/master/CONTRIBUTING.md) to make the contribution process easy and effective for everyone involved. 8 | 9 | ## Description 10 | A clear and concise description of what the bug is. 11 | 12 | ## Steps to reproduce 13 | Steps to reproduce the behavior: 14 | 15 | (Add link to a demo on https://jsfiddle.net or similar if possible) 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | ## Versions 24 | 25 | - React-Boilerplate: 26 | - Node/NPM: 27 | - Browser: 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## React Boilerplate 2 | 3 | Thank you for contributing! Please take a moment to review our [**contributing guidelines**](https://github.com/react-boilerplate/react-boilerplate/blob/master/CONTRIBUTING.md) 4 | to make the process easy and effective for everyone involved. 5 | 6 | **Please open an issue** before embarking on any significant pull request, especially those that 7 | add a new library or change existing tests, otherwise you risk spending a lot of time working 8 | on something that might not end up being merged into the project. 9 | 10 | Before opening a pull request, please ensure: 11 | 12 | - [ ] You have followed our [**contributing guidelines**](https://github.com/react-boilerplate/react-boilerplate/blob/master/CONTRIBUTING.md) 13 | - [ ] Double-check your branch is based on `dev` and targets `dev` 14 | - [ ] Pull request has tests (we are going for 100% coverage!) 15 | - [ ] Code is well-commented, linted and follows project conventions 16 | - [ ] Documentation is updated (if necessary) 17 | - [ ] Internal code generators and templates are updated (if necessary) 18 | - [ ] Description explains the issue/use-case resolved and auto-closes related issues 19 | 20 | Be kind to code reviewers, please try to keep pull requests as small and focused as possible :) 21 | 22 | **IMPORTANT**: By submitting a patch, you agree to allow the project 23 | owners to license your work under the terms of the [MIT License](https://github.com/react-boilerplate/react-boilerplate/blob/master/LICENSE.md). 24 | -------------------------------------------------------------------------------- /.github/issue-close-app.yml: -------------------------------------------------------------------------------- 1 | comment: This issue was automatically closed because it does not follow either one of our templates. Please open a new issue and fill out the template that appears instead of deleting it. If you're reporting an issue, it's especially important that you provide detailed steps for how to reproduce it. 2 | 3 | issueConfigs: 4 | 5 | - content: 6 | - Description 7 | - Steps to reproduce 8 | - Versions 9 | 10 | - content: 11 | - Is your feature request related to a problem 12 | - Describe the solution you'd like 13 | - Describe alternatives you've considered 14 | - Additional context 15 | -------------------------------------------------------------------------------- /.github/lock.yml: -------------------------------------------------------------------------------- 1 | # Configuration for lock-threads - https://github.com/dessant/lock-threads 2 | 3 | # Number of days of inactivity before a closed issue or pull request is locked 4 | daysUntilLock: 30 5 | 6 | # Issues and pull requests with these labels will not be locked. Set to `[]` to disable 7 | exemptLabels: [] 8 | 9 | # Label to add before locking, such as `outdated`. Set to `false` to disable 10 | lockLabel: false 11 | 12 | # Comment to post before locking. Set to `false` to disable 13 | lockComment: > 14 | This thread has been automatically locked since there has not been 15 | any recent activity after it was closed. Please open a new issue for 16 | related bugs. 17 | 18 | # Limit to only `issues` or `pulls` 19 | # only: issues 20 | 21 | # Optionally, specify configuration settings just for `issues` or `pulls` 22 | # issues: 23 | # exemptLabels: 24 | # - help-wanted 25 | # lockLabel: outdated 26 | 27 | # pulls: 28 | # daysUntilLock: 30 29 | 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Don't check auto-generated stuff into git 2 | coverage 3 | build 4 | node_modules 5 | stats.json 6 | 7 | # Cruft 8 | .DS_Store 9 | npm-debug.log 10 | .idea 11 | .awcache 12 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact = true 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/dubnium 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules/ 3 | internals/generators/ 4 | internals/scripts/ 5 | package-lock.json 6 | yarn.lock 7 | package.json 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "trailingComma": "all", 8 | "arrowParens": "avoid" 9 | } 10 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "processors": ["stylelint-processor-styled-components"], 3 | "extends": [ 4 | "stylelint-config-recommended", 5 | "stylelint-config-styled-components" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "node" 5 | - "lts/*" 6 | 7 | services: 8 | - xvfb 9 | 10 | script: 11 | - node ./internals/scripts/generate-templates-for-linting 12 | - npm test -- --maxWorkers=4 13 | - npm run build 14 | 15 | before_install: 16 | - export CHROME_BIN=chromium-browser 17 | - export DISPLAY=:99.0 18 | 19 | notifications: 20 | email: 21 | on_failure: change 22 | 23 | after_success: "npm run coveralls" 24 | 25 | cache: 26 | directories: 27 | - node_modules 28 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Maximilian Stoiber 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ⚠️ Moved to https://github.com/react-boilerplate/react-boilerplate-cra-template 2 | 3 | ## This boilerplate is now being developed as a custom `create-react-app` template. Much better and stronger with many more features. Powered by Create React App. 4 | 5 | Please support us there with your opinions and pull requests :) And with stars ofc :) 6 | 7 |
8 | 9 | --- 10 | 11 | react boilerplate typescript banner 12 | 13 |
14 | 15 |
Start your next react project in seconds
16 | 17 |
A highly scalable, offline-first foundation with the best DX and a focus on performance and best practices
18 | 19 |
20 | 21 | This is the **TYPESCRIPT** implementation of the original [**react-boilerplate**](https://github.com/react-boilerplate/react-boilerplate) with extra features and powers of `Typescript` 22 | 23 | > ⚠️ Please refer to the [react-boilerplate](https://github.com/react-boilerplate/react-boilerplate) for the details and the documentation 24 | 25 | --- 26 | 27 | ## Getting Started & Features & Documentations and More... 28 | 29 | You can find all the documentation in the original [**react-boilerplate**](https://github.com/react-boilerplate/react-boilerplate) 30 | 31 | For the typescript related documentation: [**Typescript Docs**](docs/README.md) 32 | 33 | ## License 34 | 35 | This project is licensed under the MIT license, Copyright (c) 2019 Maximilian 36 | Stoiber. For more information see `LICENSE.md`. 37 | -------------------------------------------------------------------------------- /app/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ####################################################################### 5 | # GENERAL # 6 | ####################################################################### 7 | 8 | # Make apache follow sym links to files 9 | Options +FollowSymLinks 10 | # If somebody opens a folder, hide all files from the resulting folder list 11 | IndexIgnore */* 12 | 13 | 14 | ####################################################################### 15 | # REWRITING # 16 | ####################################################################### 17 | 18 | # Enable rewriting 19 | RewriteEngine On 20 | 21 | # If its not HTTPS 22 | RewriteCond %{HTTPS} off 23 | 24 | # Comment out the RewriteCond above, and uncomment the RewriteCond below if you're using a load balancer (e.g. CloudFlare) for SSL 25 | # RewriteCond %{HTTP:X-Forwarded-Proto} !https 26 | 27 | # Redirect to the same URL with https://, ignoring all further rules if this one is in effect 28 | RewriteRule ^(.*) https://%{HTTP_HOST}/$1 [R,L] 29 | 30 | # If we get to here, it means we are on https:// 31 | 32 | # If the file with the specified name in the browser doesn't exist 33 | RewriteCond %{REQUEST_FILENAME} !-f 34 | 35 | # and the directory with the specified name in the browser doesn't exist 36 | RewriteCond %{REQUEST_FILENAME} !-d 37 | 38 | # and we are not opening the root already (otherwise we get a redirect loop) 39 | RewriteCond %{REQUEST_FILENAME} !\/$ 40 | 41 | # Rewrite all requests to the root 42 | RewriteRule ^(.*) / 43 | 44 | 45 | 46 | 47 | # Do not cache sw.js, required for offline-first updates. 48 | 49 | Header set Cache-Control "private, no-cache, no-store, proxy-revalidate, no-transform" 50 | Header set Pragma "no-cache" 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/components/A/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A link to a certain page, an anchor tag 3 | */ 4 | 5 | import styled from 'styles/styled-components'; 6 | 7 | const A = styled.a` 8 | color: #41addd; 9 | 10 | &:hover { 11 | color: #6cc0e5; 12 | } 13 | `; 14 | 15 | export default A; 16 | -------------------------------------------------------------------------------- /app/components/A/tests/index.test.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Testing our link component 3 | */ 4 | 5 | import React from 'react'; 6 | import { render } from '@testing-library/react'; 7 | 8 | import A from '../index'; 9 | 10 | const href = 'http://mxstbr.com/'; 11 | const children =

Test

; 12 | const renderComponent = (props = {}) => { 13 | const utils = render( 14 | 15 | {children} 16 | , 17 | ); 18 | const link = utils.container.querySelector('a')!; 19 | return { ...utils, link }; 20 | }; 21 | 22 | describe('', () => { 23 | it('should render an tag', () => { 24 | const { link } = renderComponent(); 25 | expect(link).toBeInTheDocument(); 26 | }); 27 | 28 | it('should have an href attribute', () => { 29 | const { link } = renderComponent(); 30 | expect(link).toHaveAttribute('href', href); 31 | }); 32 | 33 | it('should have children', () => { 34 | const { link } = renderComponent(); 35 | expect(link.children).toHaveLength(1); 36 | }); 37 | 38 | it('should have a class attribute', () => { 39 | const className = 'test'; 40 | const { link } = renderComponent({ className }); 41 | expect(link).toHaveClass(className); 42 | }); 43 | 44 | it('should adopt a target attribute', () => { 45 | const target = '_blank'; 46 | const { link } = renderComponent({ target }); 47 | expect(link).toHaveAttribute('target', target); 48 | }); 49 | 50 | it('should adopt a type attribute', () => { 51 | const type = 'text/html'; 52 | const { link } = renderComponent({ type }); 53 | expect(link).toHaveAttribute('type', type); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /app/components/Button/A.ts: -------------------------------------------------------------------------------- 1 | import styled from 'styles/styled-components'; 2 | 3 | import buttonStyles from './buttonStyles'; 4 | 5 | const A = styled.a` 6 | ${buttonStyles}; 7 | `; 8 | 9 | export default A; 10 | -------------------------------------------------------------------------------- /app/components/Button/StyledButton.ts: -------------------------------------------------------------------------------- 1 | import styled from 'styles/styled-components'; 2 | 3 | import buttonStyles from './buttonStyles'; 4 | 5 | const StyledButton = styled.button` 6 | ${buttonStyles}; 7 | `; 8 | 9 | export default StyledButton; 10 | -------------------------------------------------------------------------------- /app/components/Button/Wrapper.ts: -------------------------------------------------------------------------------- 1 | import styled from 'styles/styled-components'; 2 | 3 | const Wrapper = styled.div` 4 | width: 100%; 5 | text-align: center; 6 | margin: 4em 0; 7 | `; 8 | 9 | export default Wrapper; 10 | -------------------------------------------------------------------------------- /app/components/Button/buttonStyles.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'styles/styled-components'; 2 | 3 | const buttonStyles = css` 4 | display: inline-block; 5 | box-sizing: border-box; 6 | padding: 0.25em 2em; 7 | text-decoration: none; 8 | border-radius: 4px; 9 | -webkit-font-smoothing: antialiased; 10 | -webkit-touch-callout: none; 11 | user-select: none; 12 | cursor: pointer; 13 | outline: 0; 14 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 15 | font-weight: bold; 16 | font-size: 16px; 17 | border: 2px solid #41addd; 18 | color: #41addd; 19 | 20 | &:active { 21 | background: #41addd; 22 | color: #fff; 23 | } 24 | `; 25 | 26 | export default buttonStyles; 27 | -------------------------------------------------------------------------------- /app/components/Button/index.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Button.js 4 | * 5 | * A common button, if you pass it a prop "route" it'll render a link to a react-router route 6 | * otherwise it'll render a link with an onclick 7 | */ 8 | 9 | import React, { Children, ReactNode } from 'react'; 10 | 11 | import A from './A'; 12 | import StyledButton from './StyledButton'; 13 | import Wrapper from './Wrapper'; 14 | 15 | export interface Props { 16 | handleRoute?(): void; 17 | href?: string; 18 | onClick?(): void; 19 | children?: ReactNode; 20 | } 21 | function Button(props: Props) { 22 | // Render an anchor tag 23 | let button = ( 24 | 25 | {Children.toArray(props.children)} 26 | 27 | ); 28 | 29 | // If the Button has a handleRoute prop, we want to render a button 30 | if (props.handleRoute) { 31 | button = ( 32 | 33 | {Children.toArray(props.children)} 34 | 35 | ); 36 | } 37 | 38 | return {button}; 39 | } 40 | 41 | export default Button; 42 | -------------------------------------------------------------------------------- /app/components/Button/tests/A.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import A from '../A'; 5 | 6 | const renderComponent = (props = {}) => { 7 | const utils = render(Link); 8 | const link = utils.queryByText('Link')!; 9 | return { ...utils, link }; 10 | }; 11 | 12 | describe('', () => { 13 | it('should render an tag', () => { 14 | const { link } = renderComponent(); 15 | expect(link).toBeInTheDocument(); 16 | expect(link.tagName).toBe('A'); 17 | }); 18 | 19 | it('should have a class attribute', () => { 20 | const { link } = renderComponent(); 21 | expect(link).toHaveAttribute('class'); 22 | }); 23 | 24 | it('should adopt a valid attribute', () => { 25 | const id = 'test'; 26 | const { link } = renderComponent({ id }); 27 | expect(link).toHaveAttribute('id', id); 28 | }); 29 | 30 | it('should not adopt an invalid attribute', () => { 31 | const { link } = renderComponent({ attribute: 'test' }); 32 | expect(link).not.toHaveAttribute('attribute'); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /app/components/Button/tests/StyledButton.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import StyledButton from '../StyledButton'; 5 | 6 | const renderComponent = (props = {}) => { 7 | const utils = render(Button); 8 | const button = utils.queryByText('Button')!; 9 | return { ...utils, button }; 10 | }; 11 | 12 | describe('', () => { 13 | it('should render a , 18 | ); 19 | 20 | const button = utils.queryByText('Test')!.parentNode! as HTMLElement; 21 | return { ...utils, button }; 22 | }; 23 | 24 | describe('