├── .commitlintrc.js ├── .editorconfig ├── .github └── workflows │ └── release-notes.yaml ├── .gitignore ├── .prettierrc ├── .storybook ├── addons.js └── config.js ├── .vscode └── settings.json ├── README.md ├── config-overrides.js ├── husky.config.js ├── json-server.json ├── mock ├── auth.js ├── dashboard.js ├── db.js └── routes.json ├── package-lock.json ├── package.json ├── public ├── css │ └── nprogress.css ├── images │ ├── Screen Shot 2019-03-16 at 5.45.08 PM.png │ ├── exception_403.svg │ ├── exception_404.svg │ ├── exception_500.svg │ ├── logo.svg │ └── react-typescript-admin.png ├── index.html └── manifest.json ├── src ├── App.css ├── App.test.tsx ├── App.tsx ├── Page.tsx ├── __snapshots__ │ └── App.test.tsx.snap ├── components │ ├── BreadCrumbs │ │ ├── BreadCrumbs.stories.tsx │ │ ├── BreadCrumbs.tsx │ │ └── __tests__ │ │ │ ├── BreadCrumbs.test.tsx │ │ │ └── __snapshots__ │ │ │ └── BreadCrumbs.test.tsx.snap │ ├── Content │ │ └── Content.tsx │ ├── ErrorBoundary │ │ └── ErrorBoundary.tsx │ ├── Footer │ │ └── Footer.tsx │ ├── Header │ │ ├── Header.module.scss │ │ ├── Header.tsx │ │ └── NoticePane.tsx │ ├── Loading │ │ ├── Loading.module.scss │ │ ├── Loading.stories.tsx │ │ └── Loading.tsx │ ├── SideBar │ │ ├── BaseMenu.tsx │ │ ├── Logo.tsx │ │ ├── SideBar.module.scss │ │ └── SideBar.tsx │ └── index.ts ├── env.ts ├── index.css ├── index.tsx ├── logo.svg ├── models │ ├── global.ts │ ├── index.ts │ └── typed.d.ts ├── pages │ ├── Dashboard │ │ ├── Dashboard.module.scss │ │ ├── Dashboard.tsx │ │ ├── index.tsx │ │ └── models │ │ │ └── dashboard.ts │ ├── Exception │ │ ├── 403.tsx │ │ ├── 404.tsx │ │ ├── 500.tsx │ │ └── index.ts │ ├── Login │ │ ├── Login.module.scss │ │ └── Login.tsx │ └── index.ts ├── react-app-env.d.ts ├── routes │ ├── AppRoutes.tsx │ ├── RouteWithSubRoutes.tsx │ ├── config.ts │ ├── index.ts │ └── routes.ts ├── services │ ├── ApiConfig.ts │ ├── AxiosInstance.ts │ ├── DashboardService.ts │ └── GlobalService.ts ├── setupTests.ts ├── styles │ ├── _global.scss │ └── animate.css ├── typings │ └── types.d.ts └── utils │ ├── __test__ │ └── utils.test.ts │ ├── constant.ts │ ├── errorHandle.ts │ ├── regTool.ts │ └── utils.ts ├── tsconfig.json ├── tslint.json └── yarn.lock /.commitlintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] } 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | max_line_length = 120 12 | -------------------------------------------------------------------------------- /.github/workflows/release-notes.yaml: -------------------------------------------------------------------------------- 1 | name: Release-Notes-Preview 2 | 3 | on: 4 | pull_request: 5 | branches: [master] 6 | issue_comment: 7 | types: [edited] 8 | 9 | jobs: 10 | preview: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - run: | 15 | git fetch --prune --unshallow --tags 16 | - uses: snyk/release-notes-preview@v1.6.1 17 | with: 18 | releaseBranch: master 19 | env: 20 | GITHUB_PR_USERNAME: ${{ github.actor }} 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "singleQuote": true, 4 | "trailingComma": "es5", 5 | "arrowParens": "always" 6 | } 7 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-actions/register'; 2 | import '@storybook/addon-links/register'; 3 | import '@storybook/addon-knobs/register'; 4 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import { configure } from '@storybook/react'; 2 | 3 | import 'antd/dist/antd.css'; 4 | import '../src/index.css'; 5 | 6 | // automatically import all files ending in *.stories.tsx 7 | const req = require.context('../src', true, /\.stories\.tsx$/); 8 | 9 | function loadStories() { 10 | req.keys().forEach(req); 11 | } 12 | 13 | configure(loadStories, module); 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.tabSize": 2 4 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Typescript Admin 开发说明文档 2 | 3 | 该项目由 [Create React App](https://github.com/facebook/create-react-app) 提供技术支持 4 | 5 | ![Github issues](https://img.shields.io/github/issues/chachaxw/react-typescript-admin) 6 | ![Github forks](https://img.shields.io/github/forks/chachaxw/react-typescript-admin) 7 | ![Github stars](https://img.shields.io/github/stars/chachaxw/react-typescript-admin) 8 | 9 | ## 🔨 运行环境 10 | 11 | * node >= 8.9.0 12 | * typescript >= 3.0 13 | * yarn >= 1.14.0 or npm >= 6.7.0 14 | * git >= 2.10.1 15 | 16 | ## 🔧 开发环境 17 | 18 | * [VS Code](https://code.visualstudio.com/) 19 | * [Chrome](https://www.google.com/chrome/) 20 | * [React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en-US) 21 | * [Redux DevTools](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=en-US) 22 | * [Node](https://nodejs.org/en/) 23 | * [Typescript](https://github.com/Microsoft/TypeScript) 24 | * [Mac命令行工具](https://zhuanlan.zhihu.com/p/53380250) 25 | 26 | ## ✨ VSCode插件推荐 27 | 28 | * [GitLens](https://gitlens.amod.io) 29 | * [Auto Close Tag](https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-close-tag) 30 | * [Auto Rename Tag](https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag) 31 | * [ES7 React/Redux/GraphQL/React-Native snippets](https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets) 32 | * [TSLint](https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-typescript-tslint-plugin) 33 | * [Path Autocomplete](https://marketplace.visualstudio.com/items?itemName=ionutvmi.path-autocomplete) 34 | * [Bracket Pair Colorizer](https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer) 35 | * [TODO Highlight](https://marketplace.visualstudio.com/items?itemName=wayou.vscode-todo-highlight) 36 | * [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) 37 | 38 | ## 👣 可运行的命令 39 | 40 | 在该项目目录下, 你可以运行以下命令: 41 | 42 | `yarn start` or `npm start` 43 | 44 | 以开发模式运行该项目 45 | 然后打开Chrome浏览器访问[http://localhost:3000](http://localhost:3000). 46 | 47 | `yarn mock` or `npm run mock` 48 | 49 | 运行mock模拟数据服务, 启动后可以用Chrome浏览器访问[http://localhost:3031](http://localhost:3031) 50 | 查看模拟数据服务是否启动 51 | 相关详情请阅读[json-server](https://github.com/typicode/json-server), [faker](https://github.com/Marak/faker.js) 52 | 53 | `yarn test` or `npm test` 54 | 55 | 以监控模式运行Jest测试用例,编写测试的时候可以用此命令 56 | 相关详情请阅读[running tests](https://facebook.github.io/create-react-app/docs/running-tests) 57 | 58 | `yarn jest` or `npm jest` 59 | 60 | 以普通模式运行Jest测试用例 61 | 62 | `yarn build` or `npm run build` 63 | 64 | 构建生产资源到 `build` 目录, 此时环境变量为`production` 65 | 相关详情请阅读 [deployment](https://facebook.github.io/create-react-app/docs/deployment) 66 | 67 | `yarn check` or `npm run check` 68 | 69 | TSLint 语法检查,检查Typescript文件是否符合 tslint.json 配置规范 70 | 相关详情请阅读 [TSLint Rules](https://github.com/palantir/tslint/tree/master/test/rules) 71 | 72 | `yarn tslint` or `npm run tslint` 73 | 74 | 自动修复不符合tslint.json规范的代码,遇到`git commit`提交报tslint错误时,可以运行此命令修复 75 | 76 | ## 🏯项目架构说明 77 | 78 | ### 项目目录结构 79 | 80 | ``` Typescript 81 | . 82 | ├── mock/ # 模拟数据服务 83 | │ ├── db.js # 模拟数据DB 84 | │ └── routes.json # 模拟数据API路由配置 85 | │ └── ... 86 | ├── public/ # 静态资源文件(包括css, images, fonts, index.html等) 87 | │ └── ... 88 | ├── src/ 89 | │ ├── components/ # 公用React组件 90 | │ │ └── ... 91 | │ ├── models/ # Dva数据Store层 92 | │ │ └── ... 93 | │ ├── pages/ # 页面模块 94 | │ │ └── ... 95 | │ ├── routes/ # App页面路由配置 96 | │ │ └── ... 97 | │ ├── services/ # API请求服务 98 | │ │ └── ... 99 | │ ├── style/ # 通用CSS样式 100 | │ │ └── ... 101 | │ ├── utils/ # 通用工具模块 102 | │ │ └── ... 103 | │ ├── App.css # App 页面CSS样式 104 | │ ├── App.tsx # App 全局页面 105 | │ ├── App.test.tsx # App 页面Jest测试用例 106 | │ ├── ent.ts # App 环境变量配置 107 | │ ├── index.css # 全局CSS样式 108 | │ ├── index.tsx # React入口文件 109 | │ ├── logo.svg # App logo 110 | │ ├── Page.tsx # 全局页面路由 111 | │ │ 112 | ├── build/ # 生成环境静态资源文件 113 | ├── .gitignore # Git ignore 配置(禁止随意篡改配置!!!) 114 | ├── .editorconfig # 编辑器配置(禁止随意篡改配置!!!) 115 | ├── config-overrides.js # Webpack 默认配置覆盖操作 116 | ├── tsconfig.json # Typescript规则配置(禁止随意篡改规则) 117 | ├── tslint.json # tslint规则配置(禁止随意篡改规则) 118 | └── package.json # 构建脚本和依赖配置(禁止随意篡改配置) 119 | └── yarn.lock # Yarn文件 120 | 121 | ``` 122 | 123 | ### 技术栈 124 | 125 | [`React`](https://github.com/facebook/react) [`Create React App`](https://facebook.github.io/create-react-app/docs/getting-started) [`Typescript`](https://github.com/Microsoft/TypeScript) [`React Router`](https://github.com/ReactTraining/react-router) [`Redux`](https://github.com/reduxjs/redux) [`Dva`](https://github.com/dvajs/dva) 126 | [`Ant Design`](https://github.com/ant-design/ant-design) [`Jest`](https://github.com/facebook/jest) [`ECharts`](https://github.com/apache/incubator-echarts) [`faker.js`](https://github.com/Marak/faker.js) [`React Hot Loader`](https://github.com/gaearon/react-hot-loader) [`React Loadable`](https://github.com/jamiebuilds/react-loadable) 127 | [`Webpack`](https://github.com/webpack/webpack) [`Babel`](https://github.com/babel/babel) [`enzyme`](https://github.com/airbnb/enzyme) [`json-server`](https://github.com/typicode/json-server) 128 | 129 | ### React Typescript编写规范 130 | 131 | [react-redux-typescript-guide](https://github.com/piotrwitek/react-redux-typescript-guide) 132 | 133 | ### 引入资源说明 134 | 135 | 1. 图片资源需放入`public/images/`下, 在组件和CSS中引入图片资源时, 需用[create react app 环境变量](https://facebook.github.io/create-react-app/docs/using-the-public-folder) `process.env.PUBLIC_URL` 来引入, 避免大量的图片资源在TS中import 136 | 137 | ### CSS样式说明 138 | 139 | 1. CSS样式推荐采用的方式来写,Create React App原生支持 140 | 141 | * 可以避免全局样式和局部样式的冲突 142 | * JS和CSS可以共享变量,支持局部作用域和全局作用域 143 | * 可以与Sass或Less灵活搭配使用 144 | 145 | 2. 编写CSS样式时需结构清晰, 避免嵌套过深, 特别是在写Sass或Less的时候, 尤其容易层级嵌套过深,层级最好不大于4级, 尽量使用`AntDesign`原生的布局组件和样式. 样式需适当的空行, 例如: 146 | 147 | ```CSS 148 | .exampleWrapper { 149 | background-color: #f2f2f2; 150 | 151 | .exampleChild1 { 152 | color: #666666; 153 | } 154 | 155 | .exampleChild2 { 156 | font-size: 16px; 157 | } 158 | } 159 | ``` 160 | 161 | 3. 每一个组件或页面需要有独立的CSS文件, 常用页面或组件样式可以写成全局的CSS样式模块, 对于样式相对较少的组件或页面, 可以以JS对象的形式编写在组件内 162 | 4. CSS的类名和ID命名需语义清晰, 避免含糊不清的命名, 类名的英文单词和简写需符合常用英文语法习惯, 禁止自造英文单词和不那么规范的简写形式 163 | 5. 禁止在css中使用*选择器和`!important` 164 | * *选择器因为需要遍历页面的所有元素,所以编译的时候会非常消耗时间 165 | * `!important`会覆盖所以样式, 破坏CSS样式的权重关系, 导致样式难以维护 166 | 167 | 更多CSS规范请求阅读 [CSS编码规范](https://github.com/fex-team/styleguide/blob/master/css.md) 168 | 169 | #### CSS相关学习资源 170 | 171 | [CSS Modules 详解及 React 中实践](https://github.com/camsong/blog/issues/5) 172 | [Sass中文文档](http://sass.bootcss.com/docs/sass-reference/) 173 | 174 | ## 🌿Git分支管理说明 175 | 176 | ```Git 177 | git-flow 是目前流传最广的 Git 分支管理实践。git-flow 围绕的核心概念是版本发布(release) 178 | git-flow 流程中包含 5 类分支,分别是 master、develop、新功能分支(feature)、发布分支(release)和 hotfix 179 | ``` 180 | 181 | ### 相关分支说明 182 | 183 | | 分支类型 | 命名规范 | 创建自 | 合并到 | 说明 | 184 | | ------ | ------ | ------ | ------ | ------ | 185 | | feature | feature/* | develop | develop | 新功能 | 186 | | release | release/* | develop | develop 和 master | 新版本发布 | 187 | | hotfix | hotfix/* | master 或 release | release 和 master | production 或 release 中bug修复 | 188 | 189 | 1. `master` 是部署到生产环境中的代码, 一般不允许随意合并其他分支到此分支上 190 | 2. `develop`为开发分支, 是一个进行代码集成的分支, 该分支会及时合并最新代码, 新需求的开发都从此分支上创建 191 | 3. `feature/my-awesome-feature` 为新功能分支, 开发新需求时, 需从`develop`分支创建 192 | 4. `hotfix/fix-bug` 为热修复bug分支, 主要是针对`release`或`master`分支测试出现的bug进行修复 193 | 5. `release/0.0.1`分支为部署到持续集成服务器上进行测试的分支, 是一个相对稳定的可供测试的分支 194 | 195 | ### `feature`分支创建流程 196 | 197 | 1. 从 `develop`分支创建一个新的`feature`分支, 如`feature/my-awesome-feature` 198 | 2. 在该`feature`分支上进行开发相关需求,完成后提交代码并 push 到远端仓库 199 | 3. 当代码完成之后,提`pull request`, 代码审核通过后合并到`develop`分支, 之后可删除当前`feature`分支 200 | 201 | ### `hotfix`分支创建流程 202 | 203 | 1. 从`develop`分支创建一个新的`release`分支,如 `release/0.0.1` 204 | 2. 把`release`分支部署到持续集成服务器上, 并交给相关测试人员进行测试 205 | 3. 对于测试中发现的问题,直接在`release`分支上创建`hotfix/fix-bug`分支, 进行相关的bug修复 206 | 4. 合并`hotfix/fix-bug`分支到`release`分支, 再次部署并交给测试人员进行测试 207 | 208 | ### 代码提交说明 209 | 210 | [Commit message 和 Change log 编写指南](http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html) 211 | 212 | ## Jest测试 213 | 214 | Jest 测试框架官方网站[Jest](https://jestjs.io/) 215 | 216 | ## 🔭 学习更多 217 | 218 | 想获取更多信息,可以访问[Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 219 | 220 | 想学习更多React内容,可访问React官方网站 [React documentation](https://reactjs.org/). 221 | -------------------------------------------------------------------------------- /config-overrides.js: -------------------------------------------------------------------------------- 1 | /* config-overrides.js */ 2 | const { override, fixBabelImports } = require('customize-cra'); 3 | const reactHotLoader = require('react-app-rewire-hot-loader'); 4 | 5 | // Webpack 默认配置覆盖操作,慎改!!! 6 | module.exports = override( 7 | fixBabelImports('import', { 8 | libraryName: 'antd', 9 | libraryDirectory: 'es', 10 | style: 'css', 11 | }), 12 | // React hot loader 13 | reactHotLoader, 14 | ); 15 | -------------------------------------------------------------------------------- /husky.config.js: -------------------------------------------------------------------------------- 1 | const isWin = process.platform === 'win32'; 2 | const commands = ['lint-staged', isWin ? 'npm run jest:win' : 'npm run jest']; 3 | 4 | const tasks = (arr) => arr.join(' && '); 5 | 6 | module.exports = { 7 | hooks: { 8 | 'commit-msg': 'commitlint -E HUSKY_GIT_PARAMS', 9 | 'pre-commit': tasks(commands), 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /json-server.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": "3031", 3 | "watch": true, 4 | "delay": "2000", 5 | "routes": "mock/routes.json" 6 | } 7 | -------------------------------------------------------------------------------- /mock/auth.js: -------------------------------------------------------------------------------- 1 | const faker = require('faker'); 2 | const Random = faker.random; 3 | 4 | module.exports = function () { 5 | return { 6 | isAuthenticated: true, 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /mock/dashboard.js: -------------------------------------------------------------------------------- 1 | const faker = require('faker'); 2 | const Random = faker.random; 3 | 4 | module.exports = function() { 5 | let dashboard = []; 6 | 7 | for (let i = 0; i < 10; i++) { 8 | dashboard.push({ 9 | id: Random.uuid(), 10 | title: Random.word(4, 8), 11 | desc: Random.words(30, 50), 12 | tag: Random.word(2, 5), 13 | views: Random.number(), 14 | images: Random.image(), 15 | }); 16 | } 17 | 18 | return dashboard; 19 | } 20 | -------------------------------------------------------------------------------- /mock/db.js: -------------------------------------------------------------------------------- 1 | const auth = require('./auth'); 2 | const dashboard = require('./dashboard'); 3 | 4 | module.exports = function () { 5 | return { 6 | auth: auth(), 7 | dashboard: dashboard(), 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /mock/routes.json: -------------------------------------------------------------------------------- 1 | { 2 | "/api/auth": "/auth", 3 | "/api/dashboard/comments": "/dashboard" 4 | } 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-typescript-admin", 3 | "description": "A starter template for TypeScript and React with AntDesign and Dva", 4 | "version": "1.0.1", 5 | "private": true, 6 | "dependencies": { 7 | "@ant-design/compatible": "^1.0.8", 8 | "@commitlint/cli": "^12.0.1", 9 | "@commitlint/config-conventional": "^12.0.1", 10 | "@storybook/addon-knobs": "^6.1.21", 11 | "@testing-library/react": "^11.2.5", 12 | "@types/classnames": "^2.2.11", 13 | "@types/dva": "^1.1.0", 14 | "@types/enzyme": "^3.10.8", 15 | "@types/enzyme-adapter-react-16": "^1.0.6", 16 | "@types/jest": "^26.0.20", 17 | "@types/node": "^14.14.34", 18 | "@types/nprogress": "^0.2.0", 19 | "@types/qs": "^6.9.6", 20 | "@types/react": "^17.0.3", 21 | "@types/react-document-title": "^2.0.4", 22 | "@types/react-dom": "^17.0.2", 23 | "@types/react-infinite-scroller": "^1.2.1", 24 | "@types/react-loadable": "^5.5.4", 25 | "@types/react-motion": "^0.0.29", 26 | "@types/redux-logger": "^3.0.8", 27 | "@types/storybook__addon-knobs": "^5.0.4", 28 | "@types/storybook__react": "^5.2.1", 29 | "antd": "^4.14.0", 30 | "axios": "^0.21.1", 31 | "classnames": "^2.2.6", 32 | "commitizen": "^4.2.3", 33 | "date-fns": "^2.19.0", 34 | "dva": "^2.4.1", 35 | "dva-loading": "^3.0.22", 36 | "enzyme": "^3.11.0", 37 | "enzyme-adapter-react-16": "^1.15.6", 38 | "enzyme-to-json": "^3.6.1", 39 | "faker": "^5.4.0", 40 | "history": "^5.0.0", 41 | "jest-fetch-mock": "^3.0.3", 42 | "lodash": "^4.17.21", 43 | "lodash-decorators": "^6.0.1", 44 | "node-sass": "^5.0.0", 45 | "nprogress": "^0.2.0", 46 | "path-to-regexp": "^6.2.0", 47 | "qs": "^6.9.6", 48 | "query-string": "^6.14.1", 49 | "react": "^17.0.1", 50 | "react-document-title": "^2.0.3", 51 | "react-dom": "^17.0.1", 52 | "react-hot-loader": "^4.13.0", 53 | "react-infinite-scroller": "^1.2.4", 54 | "react-loadable": "^5.5.0", 55 | "react-motion": "^0.5.2", 56 | "react-test-renderer": "^17.0.1", 57 | "redux-logger": "^3.0.6", 58 | "source-map-explorer": "^2.5.2", 59 | "typescript": "^4.2.3" 60 | }, 61 | "scripts": { 62 | "analyze": "source-map-explorer build/static/js/main.*", 63 | "check": "tslint --project ./tsconfig.json", 64 | "start": "react-app-rewired start", 65 | "build": "react-app-rewired build", 66 | "staging": "cross-env REACT_APP_BUILD=staging react-app-rewired start", 67 | "test": "react-app-rewired test", 68 | "jest": "CI=true yarn test", 69 | "jest:win": "set CI=true&&yarn test", 70 | "coverage": "npm test -- --coverage", 71 | "tslint": "tslint --fix 'src/**/*.(ts|tsx)'", 72 | "mock": "json-server mock/db.js", 73 | "storybook": "start-storybook -p 9009 -s public", 74 | "build-storybook": "build-storybook -s public" 75 | }, 76 | "lint-staged": { 77 | "*.(ts|tsx)": [ 78 | "npm run check" 79 | ] 80 | }, 81 | "eslintConfig": { 82 | "extends": "react-app" 83 | }, 84 | "browserslist": [ 85 | ">0.2%", 86 | "not dead", 87 | "not ie <= 11", 88 | "not op_mini all" 89 | ], 90 | "devDependencies": { 91 | "@storybook/addon-actions": "^6.1.21", 92 | "@storybook/addon-info": "^5.3.21", 93 | "@storybook/addon-links": "^6.1.21", 94 | "@storybook/addons": "^6.1.21", 95 | "@storybook/react": "^6.1.21", 96 | "babel-plugin-import": "^1.13.3", 97 | "cross-env": "^7.0.3", 98 | "customize-cra": "^1.0.0", 99 | "husky": "^5.1.3", 100 | "lint-staged": "^10.5.4", 101 | "react-app-rewire-hot-loader": "^2.0.1", 102 | "react-app-rewired": "^2.1.8", 103 | "react-scripts": "^4.0.3", 104 | "redux-mock-store": "^1.5.4", 105 | "tslint": "^6.1.3", 106 | "tslint-eslint-rules": "^5.4.0", 107 | "tslint-lines-between-class-members": "^1.3.4", 108 | "tslint-react": "^5.0.0", 109 | "tslint-react-hooks": "^2.2.2", 110 | "webpack-cli": "^4.5.0" 111 | }, 112 | "engines": { 113 | "node": ">= 8.9.0" 114 | }, 115 | "config": { 116 | "commitizen": { 117 | "path": "./node_modules/cz-conventional-changelog" 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /public/css/nprogress.css: -------------------------------------------------------------------------------- 1 | /* Make clicks pass-through */ 2 | #nprogress { 3 | pointer-events: none; 4 | } 5 | 6 | #nprogress .bar { 7 | background: #29d; 8 | 9 | position: fixed; 10 | z-index: 1031; 11 | top: 0; 12 | left: 0; 13 | 14 | width: 100%; 15 | height: 2px; 16 | } 17 | 18 | /* Fancy blur effect */ 19 | #nprogress .peg { 20 | display: block; 21 | position: absolute; 22 | right: 0px; 23 | width: 100px; 24 | height: 100%; 25 | box-shadow: 0 0 10px #29d, 0 0 5px #29d; 26 | opacity: 1.0; 27 | 28 | -webkit-transform: rotate(3deg) translate(0px, -4px); 29 | -ms-transform: rotate(3deg) translate(0px, -4px); 30 | transform: rotate(3deg) translate(0px, -4px); 31 | } 32 | 33 | /* Remove these to get rid of the spinner */ 34 | #nprogress .spinner { 35 | display: block; 36 | position: fixed; 37 | z-index: 1031; 38 | top: 15px; 39 | right: 15px; 40 | } 41 | 42 | #nprogress .spinner-icon { 43 | width: 18px; 44 | height: 18px; 45 | box-sizing: border-box; 46 | 47 | border: solid 2px transparent; 48 | border-top-color: #29d; 49 | border-left-color: #29d; 50 | border-radius: 50%; 51 | 52 | -webkit-animation: nprogress-spinner 400ms linear infinite; 53 | animation: nprogress-spinner 400ms linear infinite; 54 | } 55 | 56 | .nprogress-custom-parent { 57 | overflow: hidden; 58 | position: relative; 59 | } 60 | 61 | .nprogress-custom-parent #nprogress .spinner, 62 | .nprogress-custom-parent #nprogress .bar { 63 | position: absolute; 64 | } 65 | 66 | @-webkit-keyframes nprogress-spinner { 67 | 0% { -webkit-transform: rotate(0deg); } 68 | 100% { -webkit-transform: rotate(360deg); } 69 | } 70 | @keyframes nprogress-spinner { 71 | 0% { transform: rotate(0deg); } 72 | 100% { transform: rotate(360deg); } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /public/images/Screen Shot 2019-03-16 at 5.45.08 PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/react-typescript-admin/4a8381932f232a79cb19f26341f67e0e24e3f23e/public/images/Screen Shot 2019-03-16 at 5.45.08 PM.png -------------------------------------------------------------------------------- /public/images/exception_403.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 9 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | -------------------------------------------------------------------------------- /public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | logo 5 | Created with Sketch. 6 | 7 | 8 | C 9 | HA 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | C 18 | H 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /public/images/react-typescript-admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/react-typescript-admin/4a8381932f232a79cb19f26341f67e0e24e3f23e/public/images/react-typescript-admin.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 15 | 16 | 17 | 26 | React Typescript Admin Starter Template 27 | 28 | 29 | 35 | 36 | 37 | 38 | 39 |
40 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | height: 100%; 3 | } 4 | 5 | .Footer { 6 | text-align: center; 7 | padding: 12px 50px; 8 | } 9 | -------------------------------------------------------------------------------- /src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import dva from 'dva'; 2 | import { StaticRouter } from 'dva/router'; 3 | import { shallow } from 'enzyme'; 4 | import toJson from 'enzyme-to-json'; 5 | import React from 'react'; 6 | 7 | import App from './App'; 8 | import { Global } from './models'; 9 | 10 | let app: any; 11 | let wrapper: any; 12 | 13 | beforeAll(() => { 14 | app = dva(); 15 | app.model(Global); 16 | app.router(() => ({})); 17 | app.start(); 18 | wrapper = shallow( 19 | 20 | 21 | 22 | ); 23 | }); 24 | 25 | afterAll(() => { 26 | wrapper.unmount(); 27 | }); 28 | 29 | describe('App Test', () => { 30 | it('Capturing Snapshot of APP', () => { 31 | expect(toJson(wrapper)).toMatchSnapshot(); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { Layout } from 'antd'; 2 | import { connect } from 'dva'; 3 | import React, { FC } from 'react'; 4 | 5 | import { BreadCrumbs, Content, ErrorBoundary, Footer, Header, SideBar } from './components'; 6 | import { Auth } from './models/global'; 7 | import { AppRoutes } from './routes'; 8 | import { appRoutes } from './routes/config'; 9 | import { getFlatMenuKeys } from './utils/utils'; 10 | 11 | import './App.css'; 12 | 13 | const menu = appRoutes.app; 14 | const flatMenuKeys = getFlatMenuKeys(menu); 15 | 16 | interface DvaProps { 17 | auth: Auth; 18 | location: Location; 19 | collapsed: boolean; 20 | onCollapse: (collapsed: boolean) => void; 21 | } 22 | 23 | interface Props extends DvaProps { 24 | app: any; 25 | } 26 | 27 | const App: FC = (props: Props) => { 28 | const { app, auth, collapsed, location, onCollapse } = props; 29 | 30 | return ( 31 | 32 | 39 | 40 |
41 | 42 | 43 | 44 | 45 | 46 | 47 |