diff --git a/.babelrc b/.babelrc index 90ca27d..b7a8e9d 100644 --- a/.babelrc +++ b/.babelrc @@ -21,6 +21,13 @@ "plugins": [ "react-hot-loader/babel", "@babel/plugin-syntax-dynamic-import", + [ + "import", + { + "libraryName": "antd-mobile", + "style": true + } + ], [ "@babel/plugin-proposal-decorators", { diff --git a/.eslintignore b/.eslintignore index 363b7dc..9880d5a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,3 +2,6 @@ node_modules/ build dist config +server +app/mobx +app/tools diff --git a/.eslintrc b/.eslintrc index 2307d32..cd3f937 100644 --- a/.eslintrc +++ b/.eslintrc @@ -36,10 +36,7 @@ ], "comma-dangle": [ "error", - "always-multiline", - { - "functions": "ignore" - } + "always-multiline" ], "quotes": [ "error", @@ -51,6 +48,13 @@ "args": "after-used" } ], + "no-use-before-define": [ + "error", + { + "functions": false, + "classes": false + } + ], "no-console": "off", "consistent-return": "off", "react/jsx-filename-extension": [ diff --git a/.gitignore b/.gitignore index b89ab98..f9d0647 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ .idea .project +# vscode +.vscode + # npm node_modules npm-debug.log @@ -17,5 +20,8 @@ package-lock.json build dist +# bak +*.bak + # cache .cache diff --git a/README.md b/README.md index 181b78a..bcfe2f4 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,152 @@ -# init-react-project -To initialize your react project +# react-lighter -## 初始化 react 项目 +to initialize your react project as simple as lighting a fire + +初始化 react 项目 + +## 技术栈 + +react + mobx + router + antd + axios + +## 目录结构 + +```markdown +├── src // 项目主目录 +│ ├── assets +│   ├── components // 可重用组件 +│   ├── index.tsx +│   ├── interface.ts +│   ├── mobx // mobx 注入工具 +│   ├── pages // 项目界面 +│   │   ├── 404 +│   │   └── Example +│   ├── routes +│   ├── tools // 脚手架 +│   ├── utils +│   └── websocket +└── config // webpack 配置 +``` + +## 运行 ```bash -yarn or npm i // 下载包 -yarn dll // 预编译 -yarn start // 本地开发 -yarn build // 项目打包 -yarn server // 加载打包后的项目 +yarn or npm i + +yarn dll + +yarn start // for dev + +yarn build && yarn server // for prod ``` ## 特点 -待更新 +### 一、热加载 + +采用 [react-hot-loader](https://github.com/gaearon/react-hot-loader) 配合 babel,可实现样式替换、节点改变不影响 state 等功能,达到局部热加载的效果 + +### 二、抽离 dll + +使用 webpack DllReferencePlugin 插件,先把 react 抽离成 dll,在后续开发中能更快加载 + +### 三、多线程打包 + +使用 [happypack](https://github.com/amireh/happypack) 启动多线程,实现光速打包 + +### 四、css 处理 + +1. 使用 [postcss](https://github.com/postcss/postcss) 提供样式兼容 + +2. 使用 [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) 抽离 css + +3. 使用 [purgecss-webpack-plugin](https://github.com/FullHuman/purgecss-webpack-plugin) 去除无用 css + +4. 使用 [postcss-px-to-viewport](https://github.com/evrone/postcss-px-to-viewport) 规范长度单位 + +### 五、mobx 注入 + +参考: + +- [用mobx构建大型项目的最佳实践](https://juejin.im/post/5c627df76fb9a049c232e990) + +- [mobx 项目最佳实践](https://github.com/luruozhou/mobx-example) + +1. mobx 分层:views、actions、stores + +> views 派发 actions,由 actions 做逻辑处理后调用 stores 做数据持久化,views 通过注入的 stores 获取到最新的数据。典型的 MVC 架构 +> +> 解决了 mobx 中数据随处可定义、逻辑交互方法随处可声明等问题 + +2. 唯一数据源 -## TODO +> 每个 view 绑定 store 数据源,顶层 view 保存着全局数据源,类似于 redux 的 createStore 机制 +> +> 实现了 stores 间交叉引用的可能,同时能够达到 redux 中 initialState 的“数据恢复”机制 -1. react-hot-loader 监听 css 变化(react-hot-loader 不能监听抽离的 css 代码) √ +3. 按需实例化 + +> 通过 [ts-plugin-mmlpx 插件](https://github.com/mmlpxjs/ts-plugin-mmlpx),实现 stores 和 actions 的自动查找和绑定、通过 Object.defineProperty 实现按需实例化,提高性能 + +4. tools 脚手架使用 + +> 参见 [mobx example 开发章节](https://github.com/luruozhou/mobx-example#%E5%BC%80%E5%8F%91) + +### 六、Axios 封装 + +参考 + +- [axios restful 封装](https://github.com/zhaotoday/rest) + +将 axios 进行 restful 风格的封装,配合 interceptor 和 histroy 进行权限验证和跳转 + +使用: + +1. GET /users/:id + +```js +request.setPath('users').get({ uri: 'lawler' }) +``` + +2. POST /users + +```js +request.setPath('users').post({ + data: { email: 'lawler61@163.com', password: '123456' } +}) +``` + +3. PUT /users/:id + +```js +request.setPath('users').put({ + uri: 'lawler', data: { name: 'jeffery' } +}) +``` + +4. DELETE /users/:id + +```js +request.setPath('users').delete({ uri: 'lawler' }) +``` + +5. GET /users/:id/articles?page=2&limit=10 + +```js +request.setPath('users/{id}/articles').replace('lawler').get({ + query: { page: 2, limit: 10 } +}) +``` + +6. PATCH /users/:id/articles/:id + +```js +request.setPath('users/{id}/articles/{id}').replace('lawler', 'react 学习之路').patch({ + data: { title: '前端学习' } +}) +``` -2. 懒加载组件 √ +## 项目展示 -3. 去除无用 css 代码 (不能使用 css 分离,否则无法去除)√ +1. [问答系统 前端 -> https://github.com/lawler61/qa-app](https://github.com/lawler61/qa-app) -4. 制作成脚手架 +2. [线上地址,去看看 -> https://qa.omyleon.com](https://qa.omyleon.com) diff --git a/config/createMobxTransformer.js b/config/createMobxTransformer.js new file mode 100644 index 0000000..77274c7 --- /dev/null +++ b/config/createMobxTransformer.js @@ -0,0 +1,116 @@ +// https://github.com/mmlpxjs/ts-plugin-mmlpx + +const ts = require('typescript') + +const defaultOptions = { + bindings: ['mStore', 'mAction'] +} + +const createTransformer = (options = defaultOptions) => { + const transformer = context => { + const bindings = [] + + let fileName, pageName + + const visitor = node => { + if (ts.isSourceFile(node)) { + ;[pageName, fileName] = getFileNameFrom(node.fileName) + return ts.visitEachChild(node, visitor, context) + } + + if (ts.isImportDeclaration(node)) { + node.forEachChild(importChild => { + if ( + ts.isImportClause(importChild) && + importChild.namedBindings && + ts.isNamedImports(importChild.namedBindings) + ) { + importChild.namedBindings.elements.forEach( + ({ propertyName, name }) => { + // import {mStore as otherName} from './store.js' + const lib = node.moduleSpecifier.text // './store.js' 暂时没用到 + const namedBinding = + (propertyName && propertyName.getText()) || name.getText() // mStore + const aliasBinding = propertyName && name.getText() //otherName + if (options.bindings.indexOf(namedBinding) > -1) { + bindings.push(aliasBinding || namedBinding) + } + } + ) + } + }) + + return node + } + + if (node.decorators) { + node.decorators.forEach(decorator => { + const { expression } = decorator + if ( + ts.isIdentifier(expression) && + bindings.indexOf(expression.getText()) > -1 + ) { + // 调用形式 @mStore @mAction + decorator.expression = ts.createCall(expression, undefined, [ + ts.createObjectLiteral([ + ts.createPropertyAssignment( + ts.createLiteral('page'), + ts.createLiteral(`${pageName}`) + ), + ts.createPropertyAssignment( + ts.createLiteral('name'), + ts.createLiteral(`${fileName}`) + ) + ]) + ]) + } else if ( + ts.isCallExpression(expression) && + ts.isIdentifier(expression.expression) && + bindings.indexOf(expression.expression.getText()) > -1 + ) { + // 调用形式 @mStore({...someProps}) @mAction({...someProps}) + let arg0 = expression.arguments[0] + if (ts.isObjectLiteralExpression(arg0)) { + decorator.expression = ts.createCall( + expression.expression, + undefined, + [ + ts.createObjectLiteral([ + ts.createPropertyAssignment( + ts.createLiteral('page'), + ts.createLiteral(`${pageName}`) + ), + ts.createPropertyAssignment( + ts.createLiteral('name'), + ts.createLiteral(`${fileName}`) + ), + ...arg0.properties + ]), + ...expression.arguments.slice(1) + ] + ) + } + } + }) + + return node + } + + return ts.visitEachChild(node, visitor, context) + } + + return node => ts.visitNode(node, visitor) + } + + return transformer +} + +function getFileNameFrom(path) { + let reg = /([^\/]+)\/(?:actions|stores)\/(.+)\.(?:t|j)sx?$/ + let matched = path.match(reg) + let pageName = matched && matched[1] + let fileName = matched && matched[2] + return [pageName, fileName] +} + +module.exports = createTransformer diff --git a/config/options.js b/config/options.js index 5442bf4..719859c 100644 --- a/config/options.js +++ b/config/options.js @@ -1,7 +1,6 @@ -const { main, name, author } = require('../package.json') - -const entryDir = main.split('/')[0] +const { basePath, main, name, author } = require('../package.json') +const entryDir = basePath const outputDir = 'dist' // 必要参数 @@ -14,9 +13,9 @@ const baseOptions = { purifycssFile: [`${entryDir}/*.html`, `${entryDir}/**/*.js`], assetsPath: 'assets', moduleToDll: { - react: ['react', 'react-dom', 'react-router-dom'] + react: ['react', 'react-dom', 'react-router-dom'], }, - dllFiles: ['react.dll.js', 'react.manifest.json'] + dllFiles: ['react.dll.js', 'react.manifest.json'], } // 可选参数 @@ -25,11 +24,16 @@ const extraOptions = { // 选择 true 在开发模式中 react-hot-loader 不能热加载抽离出去的 css [https://github.com/gaearon/react-hot-loader] // 选择 false purifycss-webpack 不能去除无用的 css [https://github.com/FullHuman/purgecss-webpack-plugin] useCssExtract: false, - copyConfig: { // 是否有不需要处理,直接拷贝的文件 - needsCopy: true, + copyConfig: { + // 是否有不需要处理,直接拷贝的文件 + needsCopy: false, fromPath: `${entryDir}/docs`, - toPath: `${outputDir}/docs` - } + toPath: `${outputDir}/docs`, + }, } -module.exports = Object.assign(baseOptions, { entryDir, outputDir }, extraOptions) +module.exports = Object.assign( + baseOptions, + { entryDir, outputDir }, + extraOptions +) diff --git a/config/utils.js b/config/utils.js index 7368f2b..be70ca6 100644 --- a/config/utils.js +++ b/config/utils.js @@ -7,5 +7,5 @@ function resolve(...filePath) { } module.exports = { - resolve + resolve, } diff --git a/config/webpack.base.config.js b/config/webpack.base.config.js index 17291f1..3fd0ba8 100644 --- a/config/webpack.base.config.js +++ b/config/webpack.base.config.js @@ -9,6 +9,8 @@ const glob = require('glob-all') // require('glob') const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin') const HappyPack = require('happypack') const os = require('os') +const tsImportPluginFactory = require('ts-import-plugin') +const createMobxTransformer = require('./createMobxTransformer') const { resolve } = require('./utils') const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }) // 根据系统的内核数量指定线程池个数 @@ -25,7 +27,7 @@ module.exports = ({ useCssExtract, assetsPath, copyConfig, - dllFiles + dllFiles, }) => { const env = process.env.NODE_ENV const isDevMode = env === 'development' @@ -33,7 +35,7 @@ module.exports = ({ const assetOptions = { limit: 10000, name: `${assetsPath}/[name].[ext]`, - publicPath: '../' + publicPath: '../', } const plugins = [ @@ -44,25 +46,25 @@ module.exports = ({ minify: isDevMode ? null : { - removeAttributeQuotes: true, - collapseWhitespace: true - } - // favicon: './favicon.ico', + removeAttributeQuotes: true, + collapseWhitespace: true, + }, + favicon: resolve(entryDir, 'assets/images/favicon.jpg'), }), new webpack.BannerPlugin(`created by ${author}`), new webpack.DllReferencePlugin({ - manifest: dllWebpack + manifest: dllWebpack, }), new AddAssetHtmlPlugin({ filepath: resolve(`${outputDir}/*.dll.js`), - includeSourcemap: false + includeSourcemap: false, }), new MiniCssExtractPlugin({ - filename: `${cssPath}/[name].[hash:8].css` + filename: `${cssPath}/[name].[hash:8].css`, // chunkFilename: "[id].css" }), new PurgecssPlugin({ - paths: glob.sync(purifycssFile.map(url => resolve(url)), { nodir: true }) + paths: glob.sync(purifycssFile.map(url => resolve(url)), { nodir: true }), }), // new PurifycssWebpack({ // paths: glob.sync(purifycssFile.map(url => resolve(url))), @@ -72,18 +74,18 @@ module.exports = ({ id: 'babel', // loader 中指定的 id loaders: ['babel-loader?cacheDirectory'], // 实际匹配处理的 loader threadPool: happyThreadPool, - verbose: true + verbose: true, }), new webpack.SourceMapDevToolPlugin({ - filename: '[file].map' - }) + filename: '[file].map', + }), ] if (!isDevMode) { plugins.push( new CleanWebpackPlugin([resolve(outputDir)], { root: process.cwd(), - exclude: dllFiles + exclude: dllFiles, }) ) } @@ -93,8 +95,8 @@ module.exports = ({ new CopyWebpackPlugin([ { from: resolve(copyConfig.fromPath), - to: resolve(copyConfig.toPath) // 找到 dist 目录下的 docs,并放进去 - } + to: resolve(copyConfig.toPath), // 找到 dist 目录下的 docs,并放进去 + }, ]) ) } @@ -103,35 +105,44 @@ module.exports = ({ entry: ['@babel/polyfill', resolve(entryFile)], output: { filename: '[name].[hash:8].js', - path: resolve(outputDir) + path: resolve(outputDir), }, mode: env, - devtool: isDevMode - ? 'cheap-module-eval-source-map' - : 'cheap-module-source-map', + devtool: isDevMode ? 'cheap-module-eval-source-map' : 'cheap-module-source-map', module: { rules: [ { test: /\.(js|jsx)$/, - enforce: 'pre', - use: { - loader: 'eslint-loader' - }, - exclude: /node_modules/ + // use: ['happypack/loader?id=babel'], + loader: 'babel-loader', + include: resolve(entryDir), + exclude: /node_modules/, }, { - test: /(\.js|\.jsx)$/, - use: ['happypack/loader?id=babel'], + test: /\.(ts|tsx)$/, + use: [ + 'happypack/loader?id=babel', + { + loader: 'awesome-typescript-loader', + options: { + transpileOnly: true, + // compilerOptions: { + // module: 'es2015' + // }, + experimentalWatchApi: true, + getCustomTransformers: () => ({ + before: [createMobxTransformer()], + }), + }, + }, + ], + include: resolve(entryDir), exclude: /node_modules/, - include: resolve(entryDir) + // 优化依赖库体积 }, { test: /\.css$/, - use: [ - useCssExtract ? MiniCssExtractPlugin.loader : 'style-loader', - 'css-loader', - 'postcss-loader' - ] + use: [useCssExtract ? MiniCssExtractPlugin.loader : 'style-loader', 'css-loader', 'postcss-loader'], }, { test: /\.less$/, @@ -143,10 +154,10 @@ module.exports = ({ loader: 'less-loader', options: { javascriptEnabled: true, - sourceMap: true - } - } - ] + sourceMap: true, + }, + }, + ], }, { test: /\.scss$/, @@ -155,40 +166,49 @@ module.exports = ({ 'css-loader', 'postcss-loader', { - loader: 'scss-loader', + loader: 'sass-loader', options: { javascriptEnabled: true, - sourceMap: true - } - } - ] + includePaths: [resolve(entryDir, 'common')], + sourceMap: true, + }, + }, + { + loader: 'sass-resources-loader', // 全局共用 scss 样式 + options: { + sourceMap: true, + resources: resolve(entryDir, 'assets/css/global_vars.scss'), + }, + }, + ], }, { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader', options: Object.assign({}, assetOptions, { - minetype: 'image/svg+xml' - }) + minetype: 'image/svg+xml', + }), }, { test: /\.(png|jpg|jpeg|gif)(\?v=\d+\.\d+\.\d+)?$/i, loader: 'url-loader', - options: assetOptions + options: assetOptions, }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', - options: assetOptions - } - ] + options: assetOptions, + }, + ], // 'noParse': /jquery/ }, resolve: { - extensions: ['.js', '.jsx', '.css', '.less', 'scss'], + extensions: ['.ts', '.tsx', '.js'], modules: [resolve(entryDir), resolve('node_modules')], alias: { - '@': resolve(entryDir) - } + '@': resolve(entryDir), + mobx: resolve('node_modules/mobx/lib/mobx.es6.js'), + }, }, optimization: { splitChunks: { @@ -198,27 +218,27 @@ module.exports = ({ chunks: 'initial', minChunks: 2, maxInitialRequests: 5, - minSize: 0 + minSize: 0, }, vendor: { test: /node_modules/, chunks: 'initial', name: 'vendor', priority: 10, // 优先 - enforce: true + enforce: true, }, styles: { name: 'styles', test: /\.css$/, chunks: 'all', - enforce: true - } - } + enforce: true, + }, + }, }, runtimeChunk: { - name: 'runtime' - } - } + name: 'runtime', + }, + }, } return Object.assign(baseConfig, { plugins }) diff --git a/config/webpack.dev.config.js b/config/webpack.dev.config.js index ecef7db..a906d75 100644 --- a/config/webpack.dev.config.js +++ b/config/webpack.dev.config.js @@ -5,8 +5,6 @@ const options = require('./options') const getBaseConfig = require('./webpack.base.config') const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') -process.env.NODE_ENV = 'development' - function getDevConfig(opts) { return merge(getBaseConfig(opts), { devServer: { @@ -14,20 +12,21 @@ function getDevConfig(opts) { disableHostCheck: true, compress: true, historyApiFallback: true, // 不跳转 + host: '0.0.0.0', port: 3000, inline: true, // 全部刷新,当源文件改变时会自动刷新页面 quiet: true, // 不显示 devServer 的 Console 信息,让 FriendlyErrorsWebpackPlugin 取而代之 open: true, hot: true, // 打开热替换 overlay: { - errors: true - } + errors: true, + }, }, plugins: [ new webpack.HotModuleReplacementPlugin(), // 实现也更新,需要在总 js 入口处判断 module.hot new webpack.NamedModulesPlugin(), - new FriendlyErrorsPlugin() - ] + new FriendlyErrorsPlugin(), + ], }) } diff --git a/config/webpack.dll.config.js b/config/webpack.dll.config.js index 142d0bc..0b54ffe 100644 --- a/config/webpack.dll.config.js +++ b/config/webpack.dll.config.js @@ -9,15 +9,15 @@ function getDllConfig(dll, output) { filename: '[name].dll.js', // 输出动态连接库的文件名称 path: resolve(output), libraryTarget: 'var', // 输出方式 默认 'var' 形式赋给变量 - library: '_dll_[name]_[hash]' // 全局变量名称 + library: '_dll_[name]_[hash]', // 全局变量名称 }, mode: 'production', plugins: [ new webpack.DllPlugin({ name: '_dll_[name]_[hash]', // 和 library 中一致,输出的 manifest.json 中的 name 值 - path: resolve(output, '[name].manifest.json') - }) - ] + path: resolve(output, '[name].manifest.json'), + }), + ], } } diff --git a/config/webpack.prod.config.js b/config/webpack.prod.config.js index e1beedf..1044fdd 100644 --- a/config/webpack.prod.config.js +++ b/config/webpack.prod.config.js @@ -5,26 +5,24 @@ const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin') const options = require('./options') const getBaseConfig = require('./webpack.base.config') -process.env.NODE_ENV = 'production' - function getProdConfig(opts) { return merge(getBaseConfig(opts), { plugins: [ new ParallelUglifyPlugin({ sourceMap: true, workerCount: 4, // 开启几个子进程去并发的执行压缩 - uglifyJS: { + uglifyES: { output: { beautify: false, // 不需要格式化 - comments: false // 保留注释 + comments: false, // 保留注释 }, compress: { warnings: false, // Uglifyjs 删除没有代码时,不输出警告 drop_console: true, collapse_vars: true, - reduce_vars: true - } - } + reduce_vars: true, + }, + }, }), new OptimizeCSSAssetsPlugin({ assetNameRegExp: /\.css\.*(?!.*map)/g, @@ -32,11 +30,11 @@ function getProdConfig(opts) { cssProcessorOptions: { discardComments: { removeAll: true }, safe: true, // 避免 cssnano 重新计算 z-index - autoprefixer: false // 关闭autoprefixer功能 使用postcss的autoprefixer功能 + autoprefixer: false, // 关闭autoprefixer功能 使用postcss的autoprefixer功能 }, - canPrint: true + canPrint: true, }), - ] + ], }) } diff --git a/package.json b/package.json index 0d862c0..b4209f8 100644 --- a/package.json +++ b/package.json @@ -1,83 +1,139 @@ { - "name": "init-project", - "version": "0.0.3", + "name": "react-lighter", + "version": "1.0.0", "description": "initialize react project", - "main": "src/index.js", + "basePath": "src", + "main": "src/index.tsx", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "build": "webpack --config config/webpack.prod.config.js --progress", - "start": "webpack-dev-server --config config/webpack.dev.config.js --progress", - "lint": "eslint --ext .js src", + "start": "cross-env NODE_ENV=development webpack-dev-server --config config/webpack.dev.config.js --progress", + "build": "cross-env NODE_ENV=production webpack --config config/webpack.prod.config.js --progress", + "lint": "tslint --fix --project .", "dll": "webpack --config config/webpack.dll.config.js --progress", - "server": "nodemon server.js" + "server": "hs dist" }, "author": "lawler61", "license": "ISC", "pre-commit": [ "lint" ], - "devDependencies": { - "@babel/cli": "^7.2.3", - "@babel/core": "^7.2.2", - "@babel/plugin-proposal-class-properties": "^7.2.3", - "@babel/plugin-proposal-decorators": "^7.2.3", - "@babel/plugin-syntax-dynamic-import": "^7.2.0", - "@babel/plugin-transform-runtime": "^7.2.0", - "@babel/preset-env": "^7.2.3", - "@babel/preset-react": "^7.0.0", - "add-asset-html-webpack-plugin": "^3.1.2", - "autoprefixer": "^9.4.3", - "babel-eslint": "^10.0.1", - "babel-loader": "^8.0.4", - "babel-plugin-import": "^1.11.0", - "clean-webpack-plugin": "^1.0.0", - "copy-webpack-plugin": "^4.6.0", - "css-loader": "^2.0.2", - "cssnano": "^4.1.8", - "eslint": "^5.10.0", - "eslint-config-airbnb": "^17.1.0", - "eslint-config-prettier": "^3.3.0", - "eslint-loader": "^2.1.1", - "eslint-plugin-babel": "^5.3.0", - "eslint-plugin-import": "^2.14.0", - "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-react": "^7.11.1", - "extract-text-webpack-plugin": "^4.0.0-beta.0", - "file-loader": "^3.0.1", - "friendly-errors-webpack-plugin": "^1.7.0", - "glob": "^7.1.3", - "glob-all": "^3.1.0", - "happypack": "^5.0.0-beta.4", - "html-webpack-plugin": "^3.2.0", - "less": "^3.9.0", - "less-loader": "^4.1.0", - "mini-css-extract-plugin": "^0.5.0", - "nodemon": "^1.18.11", - "optimize-css-assets-webpack-plugin": "^5.0.1", - "postcss-loader": "^3.0.0", - "pre-commit": "^1.2.2", - "purgecss-webpack-plugin": "^1.4.0", - "purify-css": "^1.2.5", - "purifycss-webpack": "^0.7.0", - "scss": "^0.2.4", - "scss-loader": "^0.0.1", - "style-loader": "^0.23.1", - "url-loader": "^1.1.2", - "webpack": "^4.28.1", - "webpack-cli": "^3.1.2", - "webpack-dev-server": "^3.1.11", - "webpack-merge": "^4.1.5", - "webpack-parallel-uglify-plugin": "^1.1.0" + "keywords": [ + "react", + "mobx", + "router", + "axios" + ], + "browserslist": [ + "> 1%", + "last 2 versions", + "iOS >= 8", + "Android >= 4", + "ie >= 9", + "Firefox ESR" + ], + "resolutions": { + "browserslist": "4.6.2", + "caniuse-lite": "1.0.30000974" }, "dependencies": { - "@babel/polyfill": "^7.2.5", - "ejs": "^2.6.1", - "prop-types": "^15.6.2", - "react": "^16.7.0", - "react-dom": "^16.7.0", - "react-helmet": "^5.2.0", - "react-hot-loader": "^4.6.3", - "react-loadable": "^5.5.0", - "react-router-dom": "^4.3.1" + "@babel/polyfill": "7.2.5", + "antd-mobile": "2.2.11", + "axios": "0.18.0", + "helmet": "3.16.0", + "mobx": "5.9.4", + "mobx-react": "5.4.3", + "qs": "6.7.0", + "react": "16.7.0", + "react-dom": "16.7.0", + "react-helmet": "5.2.0", + "react-hot-loader": "4.6.3", + "react-loadable": "5.5.0", + "react-router-dom": "4.3.1", + "styled-components": "4.2.0", + "uid": "0.0.2", + "zone.js": "0.9.0" + }, + "devDependencies": { + "@babel/cli": "7.2.3", + "@babel/core": "7.2.2", + "@babel/plugin-proposal-class-properties": "7.2.3", + "@babel/plugin-proposal-decorators": "7.2.3", + "@babel/plugin-syntax-dynamic-import": "7.2.0", + "@babel/plugin-transform-runtime": "7.2.0", + "@babel/preset-env": "7.2.3", + "@babel/preset-react": "7.0.0", + "@types/helmet": "0.0.43", + "@types/node": "12.0.2", + "@types/qs": "6.5.3", + "@types/react": "16.8.15", + "@types/react-dom": "16.8.4", + "@types/react-loadable": "5.5.1", + "@types/react-router-dom": "4.3.2", + "@types/styled-components": "4.1.14", + "add-asset-html-webpack-plugin": "3.1.2", + "autoprefixer": "9.4.3", + "awesome-typescript-loader": "5.2.1", + "babel-eslint": "10.0.1", + "babel-loader": "8.0.4", + "babel-plugin-import": "1.11.0", + "chalk": "2.4.2", + "clean-webpack-plugin": "1.0.0", + "commander": "2.20.0", + "copy-webpack-plugin": "4.6.0", + "cross-env": "5.2.0", + "css-loader": "2.0.2", + "cssnano": "4.1.8", + "eslint": "5.10.0", + "eslint-config-airbnb": "17.1.0", + "eslint-config-prettier": "3.3.0", + "eslint-loader": "2.1.1", + "eslint-plugin-babel": "5.3.0", + "eslint-plugin-import": "2.14.0", + "eslint-plugin-jsx-a11y": "6.1.2", + "eslint-plugin-react": "7.11.1", + "extract-text-webpack-plugin": "4.0.0-beta.0", + "file-loader": "3.0.1", + "friendly-errors-webpack-plugin": "1.7.0", + "fs-extra": "7.0.1", + "glob-all": "3.1.0", + "happypack": "5.0.0-beta.4", + "http-server": "0.11.1", + "html-webpack-plugin": "3.2.0", + "invariant": "2.2.4", + "less": "3.9.0", + "less-loader": "4.1.0", + "mini-css-extract-plugin": "0.5.0", + "node-sass": "4.11.0", + "nodemon": "1.18.11", + "optimize-css-assets-webpack-plugin": "5.0.1", + "postcss-aspect-ratio-mini": "1.0.1", + "postcss-import": "12.0.1", + "postcss-loader": "3.0.0", + "postcss-nested": "4.1.2", + "postcss-px-to-viewport": "1.1.0", + "postcss-url": "8.0.0", + "postcss-viewport-units": "0.1.6", + "postcss-write-svg": "3.0.1", + "pre-commit": "1.2.2", + "precss": "4.0.0", + "purgecss-webpack-plugin": "1.4.0", + "purify-css": "1.2.5", + "purifycss-webpack": "0.7.0", + "sass-loader": "7.1.0", + "sass-resources-loader": "2.0.0", + "scss": "0.2.4", + "style-loader": "0.23.1", + "sugarss": "2.0.0", + "ts-import-plugin": "1.5.5", + "tslint": "5.16.0", + "tslint-config-prettier": "1.18.0", + "tslint-eslint-rules": "5.4.0", + "tslint-react": "4.0.0", + "typescript": "3.4.3", + "url-loader": "1.1.2", + "webpack": "4.28.1", + "webpack-cli": "3.1.2", + "webpack-dev-server": "3.1.11", + "webpack-merge": "4.1.5", + "webpack-parallel-uglify-plugin": "1.1.0" } } diff --git a/postcss.config.js b/postcss.config.js index 979ddd9..c1bfdd9 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,3 +1,33 @@ -module.exports = { - plugins: [require('autoprefixer')] // eslint-disable-line +// https://www.jianshu.com/p/477ae5cac982 +// https://mobilesite.github.io/2018/02/05/vm-mobile-layout/ + +// eslint-disable-next-line +function getPostcssConfig({ file, options, env }) { + return { + parser: file.extname === '.sss' ? 'sugarss' : false, // Handles `.css` && '.sss' files dynamically + exec: true, // css-in-js + plugins: { + // 'postcss-import': {}, // css-loader handles @import no need for this plugin in webpack + 'postcss-url': {}, + // 'postcss-cssnext': {}, // includes autoprefixer + autoprefixer: {}, + 'postcss-aspect-ratio-mini': {}, + 'postcss-viewport-units': {}, + 'postcss-nested': {}, + 'postcss-write-svg': { utf8: false }, + precss: {}, + 'postcss-px-to-viewport': { + viewportWidth: 750, + viewportHeight: 1334, + unitPrecision: 3, + viewportUnit: 'vw', + selectorBlackList: ['.ignore'], + minPixelValue: 1, + mediaQuery: false, + }, + cssnano: env === 'production' ? {} : false, + }, + } } + +module.exports = getPostcssConfig diff --git a/server.js b/server.js deleted file mode 100644 index ec471ab..0000000 --- a/server.js +++ /dev/null @@ -1,20 +0,0 @@ -const http = require('http') -const fs = require('fs') - -const server = http.createServer((req, res) => { - const basePath = './dist' - const filePath = `${basePath}${req.url === '/' ? '/index.html' : req.url}` - - fs.readFile(filePath, (err, data) => { - if (err) { - res.write('

404!

') - } else { - res.write(data) - } - res.end() - }) -}) - -server.listen(8080, () => - console.log('Server running at http://localhost:8080') -) diff --git a/src/App.hot.js b/src/App.hot.js deleted file mode 100644 index cf2ac45..0000000 --- a/src/App.hot.js +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react' -import { hot } from 'react-hot-loader' -import App from './App' - -// do not modify this file only if you know what you are doing -export default hot(module)(() => ) diff --git a/src/App.js b/src/App.js deleted file mode 100644 index c9c27ea..0000000 --- a/src/App.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react' -import Hello from './components/Hello/loadable' - -import addIcon from './assets/add.svg' - -import './index.less' - -const App = () => ( -
-
Hello! This is a div from App
- add-icon - -
-) - -export default App diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..a6fe914 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,22 @@ +import * as React from 'react' +import { hot } from 'react-hot-loader' +import { HashRouter as Router } from 'react-router-dom' +import { configure } from 'mobx' +import routes from 'routes' +import { provider } from './mobx/provider' +import './mobxDependence' + +import 'assets/css/global.scss' +import 'assets/css/font-awesome.min.css' + +configure({ enforceActions: 'observed' }) // strict + +@provider +class App extends React.Component { + render() { + return {routes} + } +} + +// do not modify next line only if you know what you are doing +export default hot(module)(() => ) diff --git a/src/assets/add.svg b/src/assets/add.svg deleted file mode 100644 index 368405e..0000000 --- a/src/assets/add.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - diff --git a/src/assets/css/font-awesome.css b/src/assets/css/font-awesome.css new file mode 100644 index 0000000..ee906a8 --- /dev/null +++ b/src/assets/css/font-awesome.css @@ -0,0 +1,2337 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url('../fonts/fontawesome-webfont.eot?v=4.7.0'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.fa { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.28571429em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: 0.14285714em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.85714286em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.fa-pull-left { + float: left; +} +.fa-pull-right { + float: right; +} +.fa.fa-pull-left { + margin-right: .3em; +} +.fa.fa-pull-right { + margin-left: .3em; +} +/* Deprecated as of 4.4.0 */ +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: .3em; +} +.fa.pull-right { + margin-left: .3em; +} +.fa-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +.fa-rotate-90 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; + -webkit-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; + -webkit-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; + -webkit-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; + -webkit-transform: scale(1, -1); + -ms-transform: scale(1, -1); + transform: scale(1, -1); +} +:root .fa-rotate-90, +:root .fa-rotate-180, +:root .fa-rotate-270, +:root .fa-flip-horizontal, +:root .fa-flip-vertical { + filter: none; +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.fa-glass:before { + content: "\f000"; +} +.fa-music:before { + content: "\f001"; +} +.fa-search:before { + content: "\f002"; +} +.fa-envelope-o:before { + content: "\f003"; +} +.fa-heart:before { + content: "\f004"; +} +.fa-star:before { + content: "\f005"; +} +.fa-star-o:before { + content: "\f006"; +} +.fa-user:before { + content: "\f007"; +} +.fa-film:before { + content: "\f008"; +} +.fa-th-large:before { + content: "\f009"; +} +.fa-th:before { + content: "\f00a"; +} +.fa-th-list:before { + content: "\f00b"; +} +.fa-check:before { + content: "\f00c"; +} +.fa-remove:before, +.fa-close:before, +.fa-times:before { + content: "\f00d"; +} +.fa-search-plus:before { + content: "\f00e"; +} +.fa-search-minus:before { + content: "\f010"; +} +.fa-power-off:before { + content: "\f011"; +} +.fa-signal:before { + content: "\f012"; +} +.fa-gear:before, +.fa-cog:before { + content: "\f013"; +} +.fa-trash-o:before { + content: "\f014"; +} +.fa-home:before { + content: "\f015"; +} +.fa-file-o:before { + content: "\f016"; +} +.fa-clock-o:before { + content: "\f017"; +} +.fa-road:before { + content: "\f018"; +} +.fa-download:before { + content: "\f019"; +} +.fa-arrow-circle-o-down:before { + content: "\f01a"; +} +.fa-arrow-circle-o-up:before { + content: "\f01b"; +} +.fa-inbox:before { + content: "\f01c"; +} +.fa-play-circle-o:before { + content: "\f01d"; +} +.fa-rotate-right:before, +.fa-repeat:before { + content: "\f01e"; +} +.fa-refresh:before { + content: "\f021"; +} +.fa-list-alt:before { + content: "\f022"; +} +.fa-lock:before { + content: "\f023"; +} +.fa-flag:before { + content: "\f024"; +} +.fa-headphones:before { + content: "\f025"; +} +.fa-volume-off:before { + content: "\f026"; +} +.fa-volume-down:before { + content: "\f027"; +} +.fa-volume-up:before { + content: "\f028"; +} +.fa-qrcode:before { + content: "\f029"; +} +.fa-barcode:before { + content: "\f02a"; +} +.fa-tag:before { + content: "\f02b"; +} +.fa-tags:before { + content: "\f02c"; +} +.fa-book:before { + content: "\f02d"; +} +.fa-bookmark:before { + content: "\f02e"; +} +.fa-print:before { + content: "\f02f"; +} +.fa-camera:before { + content: "\f030"; +} +.fa-font:before { + content: "\f031"; +} +.fa-bold:before { + content: "\f032"; +} +.fa-italic:before { + content: "\f033"; +} +.fa-text-height:before { + content: "\f034"; +} +.fa-text-width:before { + content: "\f035"; +} +.fa-align-left:before { + content: "\f036"; +} +.fa-align-center:before { + content: "\f037"; +} +.fa-align-right:before { + content: "\f038"; +} +.fa-align-justify:before { + content: "\f039"; +} +.fa-list:before { + content: "\f03a"; +} +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} +.fa-indent:before { + content: "\f03c"; +} +.fa-video-camera:before { + content: "\f03d"; +} +.fa-photo:before, +.fa-image:before, +.fa-picture-o:before { + content: "\f03e"; +} +.fa-pencil:before { + content: "\f040"; +} +.fa-map-marker:before { + content: "\f041"; +} +.fa-adjust:before { + content: "\f042"; +} +.fa-tint:before { + content: "\f043"; +} +.fa-edit:before, +.fa-pencil-square-o:before { + content: "\f044"; +} +.fa-share-square-o:before { + content: "\f045"; +} +.fa-check-square-o:before { + content: "\f046"; +} +.fa-arrows:before { + content: "\f047"; +} +.fa-step-backward:before { + content: "\f048"; +} +.fa-fast-backward:before { + content: "\f049"; +} +.fa-backward:before { + content: "\f04a"; +} +.fa-play:before { + content: "\f04b"; +} +.fa-pause:before { + content: "\f04c"; +} +.fa-stop:before { + content: "\f04d"; +} +.fa-forward:before { + content: "\f04e"; +} +.fa-fast-forward:before { + content: "\f050"; +} +.fa-step-forward:before { + content: "\f051"; +} +.fa-eject:before { + content: "\f052"; +} +.fa-chevron-left:before { + content: "\f053"; +} +.fa-chevron-right:before { + content: "\f054"; +} +.fa-plus-circle:before { + content: "\f055"; +} +.fa-minus-circle:before { + content: "\f056"; +} +.fa-times-circle:before { + content: "\f057"; +} +.fa-check-circle:before { + content: "\f058"; +} +.fa-question-circle:before { + content: "\f059"; +} +.fa-info-circle:before { + content: "\f05a"; +} +.fa-crosshairs:before { + content: "\f05b"; +} +.fa-times-circle-o:before { + content: "\f05c"; +} +.fa-check-circle-o:before { + content: "\f05d"; +} +.fa-ban:before { + content: "\f05e"; +} +.fa-arrow-left:before { + content: "\f060"; +} +.fa-arrow-right:before { + content: "\f061"; +} +.fa-arrow-up:before { + content: "\f062"; +} +.fa-arrow-down:before { + content: "\f063"; +} +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} +.fa-expand:before { + content: "\f065"; +} +.fa-compress:before { + content: "\f066"; +} +.fa-plus:before { + content: "\f067"; +} +.fa-minus:before { + content: "\f068"; +} +.fa-asterisk:before { + content: "\f069"; +} +.fa-exclamation-circle:before { + content: "\f06a"; +} +.fa-gift:before { + content: "\f06b"; +} +.fa-leaf:before { + content: "\f06c"; +} +.fa-fire:before { + content: "\f06d"; +} +.fa-eye:before { + content: "\f06e"; +} +.fa-eye-slash:before { + content: "\f070"; +} +.fa-warning:before, +.fa-exclamation-triangle:before { + content: "\f071"; +} +.fa-plane:before { + content: "\f072"; +} +.fa-calendar:before { + content: "\f073"; +} +.fa-random:before { + content: "\f074"; +} +.fa-comment:before { + content: "\f075"; +} +.fa-magnet:before { + content: "\f076"; +} +.fa-chevron-up:before { + content: "\f077"; +} +.fa-chevron-down:before { + content: "\f078"; +} +.fa-retweet:before { + content: "\f079"; +} +.fa-shopping-cart:before { + content: "\f07a"; +} +.fa-folder:before { + content: "\f07b"; +} +.fa-folder-open:before { + content: "\f07c"; +} +.fa-arrows-v:before { + content: "\f07d"; +} +.fa-arrows-h:before { + content: "\f07e"; +} +.fa-bar-chart-o:before, +.fa-bar-chart:before { + content: "\f080"; +} +.fa-twitter-square:before { + content: "\f081"; +} +.fa-facebook-square:before { + content: "\f082"; +} +.fa-camera-retro:before { + content: "\f083"; +} +.fa-key:before { + content: "\f084"; +} +.fa-gears:before, +.fa-cogs:before { + content: "\f085"; +} +.fa-comments:before { + content: "\f086"; +} +.fa-thumbs-o-up:before { + content: "\f087"; +} +.fa-thumbs-o-down:before { + content: "\f088"; +} +.fa-star-half:before { + content: "\f089"; +} +.fa-heart-o:before { + content: "\f08a"; +} +.fa-sign-out:before { + content: "\f08b"; +} +.fa-linkedin-square:before { + content: "\f08c"; +} +.fa-thumb-tack:before { + content: "\f08d"; +} +.fa-external-link:before { + content: "\f08e"; +} +.fa-sign-in:before { + content: "\f090"; +} +.fa-trophy:before { + content: "\f091"; +} +.fa-github-square:before { + content: "\f092"; +} +.fa-upload:before { + content: "\f093"; +} +.fa-lemon-o:before { + content: "\f094"; +} +.fa-phone:before { + content: "\f095"; +} +.fa-square-o:before { + content: "\f096"; +} +.fa-bookmark-o:before { + content: "\f097"; +} +.fa-phone-square:before { + content: "\f098"; +} +.fa-twitter:before { + content: "\f099"; +} +.fa-facebook-f:before, +.fa-facebook:before { + content: "\f09a"; +} +.fa-github:before { + content: "\f09b"; +} +.fa-unlock:before { + content: "\f09c"; +} +.fa-credit-card:before { + content: "\f09d"; +} +.fa-feed:before, +.fa-rss:before { + content: "\f09e"; +} +.fa-hdd-o:before { + content: "\f0a0"; +} +.fa-bullhorn:before { + content: "\f0a1"; +} +.fa-bell:before { + content: "\f0f3"; +} +.fa-certificate:before { + content: "\f0a3"; +} +.fa-hand-o-right:before { + content: "\f0a4"; +} +.fa-hand-o-left:before { + content: "\f0a5"; +} +.fa-hand-o-up:before { + content: "\f0a6"; +} +.fa-hand-o-down:before { + content: "\f0a7"; +} +.fa-arrow-circle-left:before { + content: "\f0a8"; +} +.fa-arrow-circle-right:before { + content: "\f0a9"; +} +.fa-arrow-circle-up:before { + content: "\f0aa"; +} +.fa-arrow-circle-down:before { + content: "\f0ab"; +} +.fa-globe:before { + content: "\f0ac"; +} +.fa-wrench:before { + content: "\f0ad"; +} +.fa-tasks:before { + content: "\f0ae"; +} +.fa-filter:before { + content: "\f0b0"; +} +.fa-briefcase:before { + content: "\f0b1"; +} +.fa-arrows-alt:before { + content: "\f0b2"; +} +.fa-group:before, +.fa-users:before { + content: "\f0c0"; +} +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} +.fa-cloud:before { + content: "\f0c2"; +} +.fa-flask:before { + content: "\f0c3"; +} +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} +.fa-copy:before, +.fa-files-o:before { + content: "\f0c5"; +} +.fa-paperclip:before { + content: "\f0c6"; +} +.fa-save:before, +.fa-floppy-o:before { + content: "\f0c7"; +} +.fa-square:before { + content: "\f0c8"; +} +.fa-navicon:before, +.fa-reorder:before, +.fa-bars:before { + content: "\f0c9"; +} +.fa-list-ul:before { + content: "\f0ca"; +} +.fa-list-ol:before { + content: "\f0cb"; +} +.fa-strikethrough:before { + content: "\f0cc"; +} +.fa-underline:before { + content: "\f0cd"; +} +.fa-table:before { + content: "\f0ce"; +} +.fa-magic:before { + content: "\f0d0"; +} +.fa-truck:before { + content: "\f0d1"; +} +.fa-pinterest:before { + content: "\f0d2"; +} +.fa-pinterest-square:before { + content: "\f0d3"; +} +.fa-google-plus-square:before { + content: "\f0d4"; +} +.fa-google-plus:before { + content: "\f0d5"; +} +.fa-money:before { + content: "\f0d6"; +} +.fa-caret-down:before { + content: "\f0d7"; +} +.fa-caret-up:before { + content: "\f0d8"; +} +.fa-caret-left:before { + content: "\f0d9"; +} +.fa-caret-right:before { + content: "\f0da"; +} +.fa-columns:before { + content: "\f0db"; +} +.fa-unsorted:before, +.fa-sort:before { + content: "\f0dc"; +} +.fa-sort-down:before, +.fa-sort-desc:before { + content: "\f0dd"; +} +.fa-sort-up:before, +.fa-sort-asc:before { + content: "\f0de"; +} +.fa-envelope:before { + content: "\f0e0"; +} +.fa-linkedin:before { + content: "\f0e1"; +} +.fa-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} +.fa-legal:before, +.fa-gavel:before { + content: "\f0e3"; +} +.fa-dashboard:before, +.fa-tachometer:before { + content: "\f0e4"; +} +.fa-comment-o:before { + content: "\f0e5"; +} +.fa-comments-o:before { + content: "\f0e6"; +} +.fa-flash:before, +.fa-bolt:before { + content: "\f0e7"; +} +.fa-sitemap:before { + content: "\f0e8"; +} +.fa-umbrella:before { + content: "\f0e9"; +} +.fa-paste:before, +.fa-clipboard:before { + content: "\f0ea"; +} +.fa-lightbulb-o:before { + content: "\f0eb"; +} +.fa-exchange:before { + content: "\f0ec"; +} +.fa-cloud-download:before { + content: "\f0ed"; +} +.fa-cloud-upload:before { + content: "\f0ee"; +} +.fa-user-md:before { + content: "\f0f0"; +} +.fa-stethoscope:before { + content: "\f0f1"; +} +.fa-suitcase:before { + content: "\f0f2"; +} +.fa-bell-o:before { + content: "\f0a2"; +} +.fa-coffee:before { + content: "\f0f4"; +} +.fa-cutlery:before { + content: "\f0f5"; +} +.fa-file-text-o:before { + content: "\f0f6"; +} +.fa-building-o:before { + content: "\f0f7"; +} +.fa-hospital-o:before { + content: "\f0f8"; +} +.fa-ambulance:before { + content: "\f0f9"; +} +.fa-medkit:before { + content: "\f0fa"; +} +.fa-fighter-jet:before { + content: "\f0fb"; +} +.fa-beer:before { + content: "\f0fc"; +} +.fa-h-square:before { + content: "\f0fd"; +} +.fa-plus-square:before { + content: "\f0fe"; +} +.fa-angle-double-left:before { + content: "\f100"; +} +.fa-angle-double-right:before { + content: "\f101"; +} +.fa-angle-double-up:before { + content: "\f102"; +} +.fa-angle-double-down:before { + content: "\f103"; +} +.fa-angle-left:before { + content: "\f104"; +} +.fa-angle-right:before { + content: "\f105"; +} +.fa-angle-up:before { + content: "\f106"; +} +.fa-angle-down:before { + content: "\f107"; +} +.fa-desktop:before { + content: "\f108"; +} +.fa-laptop:before { + content: "\f109"; +} +.fa-tablet:before { + content: "\f10a"; +} +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f10b"; +} +.fa-circle-o:before { + content: "\f10c"; +} +.fa-quote-left:before { + content: "\f10d"; +} +.fa-quote-right:before { + content: "\f10e"; +} +.fa-spinner:before { + content: "\f110"; +} +.fa-circle:before { + content: "\f111"; +} +.fa-mail-reply:before, +.fa-reply:before { + content: "\f112"; +} +.fa-github-alt:before { + content: "\f113"; +} +.fa-folder-o:before { + content: "\f114"; +} +.fa-folder-open-o:before { + content: "\f115"; +} +.fa-smile-o:before { + content: "\f118"; +} +.fa-frown-o:before { + content: "\f119"; +} +.fa-meh-o:before { + content: "\f11a"; +} +.fa-gamepad:before { + content: "\f11b"; +} +.fa-keyboard-o:before { + content: "\f11c"; +} +.fa-flag-o:before { + content: "\f11d"; +} +.fa-flag-checkered:before { + content: "\f11e"; +} +.fa-terminal:before { + content: "\f120"; +} +.fa-code:before { + content: "\f121"; +} +.fa-mail-reply-all:before, +.fa-reply-all:before { + content: "\f122"; +} +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: "\f123"; +} +.fa-location-arrow:before { + content: "\f124"; +} +.fa-crop:before { + content: "\f125"; +} +.fa-code-fork:before { + content: "\f126"; +} +.fa-unlink:before, +.fa-chain-broken:before { + content: "\f127"; +} +.fa-question:before { + content: "\f128"; +} +.fa-info:before { + content: "\f129"; +} +.fa-exclamation:before { + content: "\f12a"; +} +.fa-superscript:before { + content: "\f12b"; +} +.fa-subscript:before { + content: "\f12c"; +} +.fa-eraser:before { + content: "\f12d"; +} +.fa-puzzle-piece:before { + content: "\f12e"; +} +.fa-microphone:before { + content: "\f130"; +} +.fa-microphone-slash:before { + content: "\f131"; +} +.fa-shield:before { + content: "\f132"; +} +.fa-calendar-o:before { + content: "\f133"; +} +.fa-fire-extinguisher:before { + content: "\f134"; +} +.fa-rocket:before { + content: "\f135"; +} +.fa-maxcdn:before { + content: "\f136"; +} +.fa-chevron-circle-left:before { + content: "\f137"; +} +.fa-chevron-circle-right:before { + content: "\f138"; +} +.fa-chevron-circle-up:before { + content: "\f139"; +} +.fa-chevron-circle-down:before { + content: "\f13a"; +} +.fa-html5:before { + content: "\f13b"; +} +.fa-css3:before { + content: "\f13c"; +} +.fa-anchor:before { + content: "\f13d"; +} +.fa-unlock-alt:before { + content: "\f13e"; +} +.fa-bullseye:before { + content: "\f140"; +} +.fa-ellipsis-h:before { + content: "\f141"; +} +.fa-ellipsis-v:before { + content: "\f142"; +} +.fa-rss-square:before { + content: "\f143"; +} +.fa-play-circle:before { + content: "\f144"; +} +.fa-ticket:before { + content: "\f145"; +} +.fa-minus-square:before { + content: "\f146"; +} +.fa-minus-square-o:before { + content: "\f147"; +} +.fa-level-up:before { + content: "\f148"; +} +.fa-level-down:before { + content: "\f149"; +} +.fa-check-square:before { + content: "\f14a"; +} +.fa-pencil-square:before { + content: "\f14b"; +} +.fa-external-link-square:before { + content: "\f14c"; +} +.fa-share-square:before { + content: "\f14d"; +} +.fa-compass:before { + content: "\f14e"; +} +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: "\f150"; +} +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: "\f151"; +} +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: "\f152"; +} +.fa-euro:before, +.fa-eur:before { + content: "\f153"; +} +.fa-gbp:before { + content: "\f154"; +} +.fa-dollar:before, +.fa-usd:before { + content: "\f155"; +} +.fa-rupee:before, +.fa-inr:before { + content: "\f156"; +} +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: "\f157"; +} +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: "\f158"; +} +.fa-won:before, +.fa-krw:before { + content: "\f159"; +} +.fa-bitcoin:before, +.fa-btc:before { + content: "\f15a"; +} +.fa-file:before { + content: "\f15b"; +} +.fa-file-text:before { + content: "\f15c"; +} +.fa-sort-alpha-asc:before { + content: "\f15d"; +} +.fa-sort-alpha-desc:before { + content: "\f15e"; +} +.fa-sort-amount-asc:before { + content: "\f160"; +} +.fa-sort-amount-desc:before { + content: "\f161"; +} +.fa-sort-numeric-asc:before { + content: "\f162"; +} +.fa-sort-numeric-desc:before { + content: "\f163"; +} +.fa-thumbs-up:before { + content: "\f164"; +} +.fa-thumbs-down:before { + content: "\f165"; +} +.fa-youtube-square:before { + content: "\f166"; +} +.fa-youtube:before { + content: "\f167"; +} +.fa-xing:before { + content: "\f168"; +} +.fa-xing-square:before { + content: "\f169"; +} +.fa-youtube-play:before { + content: "\f16a"; +} +.fa-dropbox:before { + content: "\f16b"; +} +.fa-stack-overflow:before { + content: "\f16c"; +} +.fa-instagram:before { + content: "\f16d"; +} +.fa-flickr:before { + content: "\f16e"; +} +.fa-adn:before { + content: "\f170"; +} +.fa-bitbucket:before { + content: "\f171"; +} +.fa-bitbucket-square:before { + content: "\f172"; +} +.fa-tumblr:before { + content: "\f173"; +} +.fa-tumblr-square:before { + content: "\f174"; +} +.fa-long-arrow-down:before { + content: "\f175"; +} +.fa-long-arrow-up:before { + content: "\f176"; +} +.fa-long-arrow-left:before { + content: "\f177"; +} +.fa-long-arrow-right:before { + content: "\f178"; +} +.fa-apple:before { + content: "\f179"; +} +.fa-windows:before { + content: "\f17a"; +} +.fa-android:before { + content: "\f17b"; +} +.fa-linux:before { + content: "\f17c"; +} +.fa-dribbble:before { + content: "\f17d"; +} +.fa-skype:before { + content: "\f17e"; +} +.fa-foursquare:before { + content: "\f180"; +} +.fa-trello:before { + content: "\f181"; +} +.fa-female:before { + content: "\f182"; +} +.fa-male:before { + content: "\f183"; +} +.fa-gittip:before, +.fa-gratipay:before { + content: "\f184"; +} +.fa-sun-o:before { + content: "\f185"; +} +.fa-moon-o:before { + content: "\f186"; +} +.fa-archive:before { + content: "\f187"; +} +.fa-bug:before { + content: "\f188"; +} +.fa-vk:before { + content: "\f189"; +} +.fa-weibo:before { + content: "\f18a"; +} +.fa-renren:before { + content: "\f18b"; +} +.fa-pagelines:before { + content: "\f18c"; +} +.fa-stack-exchange:before { + content: "\f18d"; +} +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} +.fa-arrow-circle-o-left:before { + content: "\f190"; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: "\f191"; +} +.fa-dot-circle-o:before { + content: "\f192"; +} +.fa-wheelchair:before { + content: "\f193"; +} +.fa-vimeo-square:before { + content: "\f194"; +} +.fa-turkish-lira:before, +.fa-try:before { + content: "\f195"; +} +.fa-plus-square-o:before { + content: "\f196"; +} +.fa-space-shuttle:before { + content: "\f197"; +} +.fa-slack:before { + content: "\f198"; +} +.fa-envelope-square:before { + content: "\f199"; +} +.fa-wordpress:before { + content: "\f19a"; +} +.fa-openid:before { + content: "\f19b"; +} +.fa-institution:before, +.fa-bank:before, +.fa-university:before { + content: "\f19c"; +} +.fa-mortar-board:before, +.fa-graduation-cap:before { + content: "\f19d"; +} +.fa-yahoo:before { + content: "\f19e"; +} +.fa-google:before { + content: "\f1a0"; +} +.fa-reddit:before { + content: "\f1a1"; +} +.fa-reddit-square:before { + content: "\f1a2"; +} +.fa-stumbleupon-circle:before { + content: "\f1a3"; +} +.fa-stumbleupon:before { + content: "\f1a4"; +} +.fa-delicious:before { + content: "\f1a5"; +} +.fa-digg:before { + content: "\f1a6"; +} +.fa-pied-piper-pp:before { + content: "\f1a7"; +} +.fa-pied-piper-alt:before { + content: "\f1a8"; +} +.fa-drupal:before { + content: "\f1a9"; +} +.fa-joomla:before { + content: "\f1aa"; +} +.fa-language:before { + content: "\f1ab"; +} +.fa-fax:before { + content: "\f1ac"; +} +.fa-building:before { + content: "\f1ad"; +} +.fa-child:before { + content: "\f1ae"; +} +.fa-paw:before { + content: "\f1b0"; +} +.fa-spoon:before { + content: "\f1b1"; +} +.fa-cube:before { + content: "\f1b2"; +} +.fa-cubes:before { + content: "\f1b3"; +} +.fa-behance:before { + content: "\f1b4"; +} +.fa-behance-square:before { + content: "\f1b5"; +} +.fa-steam:before { + content: "\f1b6"; +} +.fa-steam-square:before { + content: "\f1b7"; +} +.fa-recycle:before { + content: "\f1b8"; +} +.fa-automobile:before, +.fa-car:before { + content: "\f1b9"; +} +.fa-cab:before, +.fa-taxi:before { + content: "\f1ba"; +} +.fa-tree:before { + content: "\f1bb"; +} +.fa-spotify:before { + content: "\f1bc"; +} +.fa-deviantart:before { + content: "\f1bd"; +} +.fa-soundcloud:before { + content: "\f1be"; +} +.fa-database:before { + content: "\f1c0"; +} +.fa-file-pdf-o:before { + content: "\f1c1"; +} +.fa-file-word-o:before { + content: "\f1c2"; +} +.fa-file-excel-o:before { + content: "\f1c3"; +} +.fa-file-powerpoint-o:before { + content: "\f1c4"; +} +.fa-file-photo-o:before, +.fa-file-picture-o:before, +.fa-file-image-o:before { + content: "\f1c5"; +} +.fa-file-zip-o:before, +.fa-file-archive-o:before { + content: "\f1c6"; +} +.fa-file-sound-o:before, +.fa-file-audio-o:before { + content: "\f1c7"; +} +.fa-file-movie-o:before, +.fa-file-video-o:before { + content: "\f1c8"; +} +.fa-file-code-o:before { + content: "\f1c9"; +} +.fa-vine:before { + content: "\f1ca"; +} +.fa-codepen:before { + content: "\f1cb"; +} +.fa-jsfiddle:before { + content: "\f1cc"; +} +.fa-life-bouy:before, +.fa-life-buoy:before, +.fa-life-saver:before, +.fa-support:before, +.fa-life-ring:before { + content: "\f1cd"; +} +.fa-circle-o-notch:before { + content: "\f1ce"; +} +.fa-ra:before, +.fa-resistance:before, +.fa-rebel:before { + content: "\f1d0"; +} +.fa-ge:before, +.fa-empire:before { + content: "\f1d1"; +} +.fa-git-square:before { + content: "\f1d2"; +} +.fa-git:before { + content: "\f1d3"; +} +.fa-y-combinator-square:before, +.fa-yc-square:before, +.fa-hacker-news:before { + content: "\f1d4"; +} +.fa-tencent-weibo:before { + content: "\f1d5"; +} +.fa-qq:before { + content: "\f1d6"; +} +.fa-wechat:before, +.fa-weixin:before { + content: "\f1d7"; +} +.fa-send:before, +.fa-paper-plane:before { + content: "\f1d8"; +} +.fa-send-o:before, +.fa-paper-plane-o:before { + content: "\f1d9"; +} +.fa-history:before { + content: "\f1da"; +} +.fa-circle-thin:before { + content: "\f1db"; +} +.fa-header:before { + content: "\f1dc"; +} +.fa-paragraph:before { + content: "\f1dd"; +} +.fa-sliders:before { + content: "\f1de"; +} +.fa-share-alt:before { + content: "\f1e0"; +} +.fa-share-alt-square:before { + content: "\f1e1"; +} +.fa-bomb:before { + content: "\f1e2"; +} +.fa-soccer-ball-o:before, +.fa-futbol-o:before { + content: "\f1e3"; +} +.fa-tty:before { + content: "\f1e4"; +} +.fa-binoculars:before { + content: "\f1e5"; +} +.fa-plug:before { + content: "\f1e6"; +} +.fa-slideshare:before { + content: "\f1e7"; +} +.fa-twitch:before { + content: "\f1e8"; +} +.fa-yelp:before { + content: "\f1e9"; +} +.fa-newspaper-o:before { + content: "\f1ea"; +} +.fa-wifi:before { + content: "\f1eb"; +} +.fa-calculator:before { + content: "\f1ec"; +} +.fa-paypal:before { + content: "\f1ed"; +} +.fa-google-wallet:before { + content: "\f1ee"; +} +.fa-cc-visa:before { + content: "\f1f0"; +} +.fa-cc-mastercard:before { + content: "\f1f1"; +} +.fa-cc-discover:before { + content: "\f1f2"; +} +.fa-cc-amex:before { + content: "\f1f3"; +} +.fa-cc-paypal:before { + content: "\f1f4"; +} +.fa-cc-stripe:before { + content: "\f1f5"; +} +.fa-bell-slash:before { + content: "\f1f6"; +} +.fa-bell-slash-o:before { + content: "\f1f7"; +} +.fa-trash:before { + content: "\f1f8"; +} +.fa-copyright:before { + content: "\f1f9"; +} +.fa-at:before { + content: "\f1fa"; +} +.fa-eyedropper:before { + content: "\f1fb"; +} +.fa-paint-brush:before { + content: "\f1fc"; +} +.fa-birthday-cake:before { + content: "\f1fd"; +} +.fa-area-chart:before { + content: "\f1fe"; +} +.fa-pie-chart:before { + content: "\f200"; +} +.fa-line-chart:before { + content: "\f201"; +} +.fa-lastfm:before { + content: "\f202"; +} +.fa-lastfm-square:before { + content: "\f203"; +} +.fa-toggle-off:before { + content: "\f204"; +} +.fa-toggle-on:before { + content: "\f205"; +} +.fa-bicycle:before { + content: "\f206"; +} +.fa-bus:before { + content: "\f207"; +} +.fa-ioxhost:before { + content: "\f208"; +} +.fa-angellist:before { + content: "\f209"; +} +.fa-cc:before { + content: "\f20a"; +} +.fa-shekel:before, +.fa-sheqel:before, +.fa-ils:before { + content: "\f20b"; +} +.fa-meanpath:before { + content: "\f20c"; +} +.fa-buysellads:before { + content: "\f20d"; +} +.fa-connectdevelop:before { + content: "\f20e"; +} +.fa-dashcube:before { + content: "\f210"; +} +.fa-forumbee:before { + content: "\f211"; +} +.fa-leanpub:before { + content: "\f212"; +} +.fa-sellsy:before { + content: "\f213"; +} +.fa-shirtsinbulk:before { + content: "\f214"; +} +.fa-simplybuilt:before { + content: "\f215"; +} +.fa-skyatlas:before { + content: "\f216"; +} +.fa-cart-plus:before { + content: "\f217"; +} +.fa-cart-arrow-down:before { + content: "\f218"; +} +.fa-diamond:before { + content: "\f219"; +} +.fa-ship:before { + content: "\f21a"; +} +.fa-user-secret:before { + content: "\f21b"; +} +.fa-motorcycle:before { + content: "\f21c"; +} +.fa-street-view:before { + content: "\f21d"; +} +.fa-heartbeat:before { + content: "\f21e"; +} +.fa-venus:before { + content: "\f221"; +} +.fa-mars:before { + content: "\f222"; +} +.fa-mercury:before { + content: "\f223"; +} +.fa-intersex:before, +.fa-transgender:before { + content: "\f224"; +} +.fa-transgender-alt:before { + content: "\f225"; +} +.fa-venus-double:before { + content: "\f226"; +} +.fa-mars-double:before { + content: "\f227"; +} +.fa-venus-mars:before { + content: "\f228"; +} +.fa-mars-stroke:before { + content: "\f229"; +} +.fa-mars-stroke-v:before { + content: "\f22a"; +} +.fa-mars-stroke-h:before { + content: "\f22b"; +} +.fa-neuter:before { + content: "\f22c"; +} +.fa-genderless:before { + content: "\f22d"; +} +.fa-facebook-official:before { + content: "\f230"; +} +.fa-pinterest-p:before { + content: "\f231"; +} +.fa-whatsapp:before { + content: "\f232"; +} +.fa-server:before { + content: "\f233"; +} +.fa-user-plus:before { + content: "\f234"; +} +.fa-user-times:before { + content: "\f235"; +} +.fa-hotel:before, +.fa-bed:before { + content: "\f236"; +} +.fa-viacoin:before { + content: "\f237"; +} +.fa-train:before { + content: "\f238"; +} +.fa-subway:before { + content: "\f239"; +} +.fa-medium:before { + content: "\f23a"; +} +.fa-yc:before, +.fa-y-combinator:before { + content: "\f23b"; +} +.fa-optin-monster:before { + content: "\f23c"; +} +.fa-opencart:before { + content: "\f23d"; +} +.fa-expeditedssl:before { + content: "\f23e"; +} +.fa-battery-4:before, +.fa-battery:before, +.fa-battery-full:before { + content: "\f240"; +} +.fa-battery-3:before, +.fa-battery-three-quarters:before { + content: "\f241"; +} +.fa-battery-2:before, +.fa-battery-half:before { + content: "\f242"; +} +.fa-battery-1:before, +.fa-battery-quarter:before { + content: "\f243"; +} +.fa-battery-0:before, +.fa-battery-empty:before { + content: "\f244"; +} +.fa-mouse-pointer:before { + content: "\f245"; +} +.fa-i-cursor:before { + content: "\f246"; +} +.fa-object-group:before { + content: "\f247"; +} +.fa-object-ungroup:before { + content: "\f248"; +} +.fa-sticky-note:before { + content: "\f249"; +} +.fa-sticky-note-o:before { + content: "\f24a"; +} +.fa-cc-jcb:before { + content: "\f24b"; +} +.fa-cc-diners-club:before { + content: "\f24c"; +} +.fa-clone:before { + content: "\f24d"; +} +.fa-balance-scale:before { + content: "\f24e"; +} +.fa-hourglass-o:before { + content: "\f250"; +} +.fa-hourglass-1:before, +.fa-hourglass-start:before { + content: "\f251"; +} +.fa-hourglass-2:before, +.fa-hourglass-half:before { + content: "\f252"; +} +.fa-hourglass-3:before, +.fa-hourglass-end:before { + content: "\f253"; +} +.fa-hourglass:before { + content: "\f254"; +} +.fa-hand-grab-o:before, +.fa-hand-rock-o:before { + content: "\f255"; +} +.fa-hand-stop-o:before, +.fa-hand-paper-o:before { + content: "\f256"; +} +.fa-hand-scissors-o:before { + content: "\f257"; +} +.fa-hand-lizard-o:before { + content: "\f258"; +} +.fa-hand-spock-o:before { + content: "\f259"; +} +.fa-hand-pointer-o:before { + content: "\f25a"; +} +.fa-hand-peace-o:before { + content: "\f25b"; +} +.fa-trademark:before { + content: "\f25c"; +} +.fa-registered:before { + content: "\f25d"; +} +.fa-creative-commons:before { + content: "\f25e"; +} +.fa-gg:before { + content: "\f260"; +} +.fa-gg-circle:before { + content: "\f261"; +} +.fa-tripadvisor:before { + content: "\f262"; +} +.fa-odnoklassniki:before { + content: "\f263"; +} +.fa-odnoklassniki-square:before { + content: "\f264"; +} +.fa-get-pocket:before { + content: "\f265"; +} +.fa-wikipedia-w:before { + content: "\f266"; +} +.fa-safari:before { + content: "\f267"; +} +.fa-chrome:before { + content: "\f268"; +} +.fa-firefox:before { + content: "\f269"; +} +.fa-opera:before { + content: "\f26a"; +} +.fa-internet-explorer:before { + content: "\f26b"; +} +.fa-tv:before, +.fa-television:before { + content: "\f26c"; +} +.fa-contao:before { + content: "\f26d"; +} +.fa-500px:before { + content: "\f26e"; +} +.fa-amazon:before { + content: "\f270"; +} +.fa-calendar-plus-o:before { + content: "\f271"; +} +.fa-calendar-minus-o:before { + content: "\f272"; +} +.fa-calendar-times-o:before { + content: "\f273"; +} +.fa-calendar-check-o:before { + content: "\f274"; +} +.fa-industry:before { + content: "\f275"; +} +.fa-map-pin:before { + content: "\f276"; +} +.fa-map-signs:before { + content: "\f277"; +} +.fa-map-o:before { + content: "\f278"; +} +.fa-map:before { + content: "\f279"; +} +.fa-commenting:before { + content: "\f27a"; +} +.fa-commenting-o:before { + content: "\f27b"; +} +.fa-houzz:before { + content: "\f27c"; +} +.fa-vimeo:before { + content: "\f27d"; +} +.fa-black-tie:before { + content: "\f27e"; +} +.fa-fonticons:before { + content: "\f280"; +} +.fa-reddit-alien:before { + content: "\f281"; +} +.fa-edge:before { + content: "\f282"; +} +.fa-credit-card-alt:before { + content: "\f283"; +} +.fa-codiepie:before { + content: "\f284"; +} +.fa-modx:before { + content: "\f285"; +} +.fa-fort-awesome:before { + content: "\f286"; +} +.fa-usb:before { + content: "\f287"; +} +.fa-product-hunt:before { + content: "\f288"; +} +.fa-mixcloud:before { + content: "\f289"; +} +.fa-scribd:before { + content: "\f28a"; +} +.fa-pause-circle:before { + content: "\f28b"; +} +.fa-pause-circle-o:before { + content: "\f28c"; +} +.fa-stop-circle:before { + content: "\f28d"; +} +.fa-stop-circle-o:before { + content: "\f28e"; +} +.fa-shopping-bag:before { + content: "\f290"; +} +.fa-shopping-basket:before { + content: "\f291"; +} +.fa-hashtag:before { + content: "\f292"; +} +.fa-bluetooth:before { + content: "\f293"; +} +.fa-bluetooth-b:before { + content: "\f294"; +} +.fa-percent:before { + content: "\f295"; +} +.fa-gitlab:before { + content: "\f296"; +} +.fa-wpbeginner:before { + content: "\f297"; +} +.fa-wpforms:before { + content: "\f298"; +} +.fa-envira:before { + content: "\f299"; +} +.fa-universal-access:before { + content: "\f29a"; +} +.fa-wheelchair-alt:before { + content: "\f29b"; +} +.fa-question-circle-o:before { + content: "\f29c"; +} +.fa-blind:before { + content: "\f29d"; +} +.fa-audio-description:before { + content: "\f29e"; +} +.fa-volume-control-phone:before { + content: "\f2a0"; +} +.fa-braille:before { + content: "\f2a1"; +} +.fa-assistive-listening-systems:before { + content: "\f2a2"; +} +.fa-asl-interpreting:before, +.fa-american-sign-language-interpreting:before { + content: "\f2a3"; +} +.fa-deafness:before, +.fa-hard-of-hearing:before, +.fa-deaf:before { + content: "\f2a4"; +} +.fa-glide:before { + content: "\f2a5"; +} +.fa-glide-g:before { + content: "\f2a6"; +} +.fa-signing:before, +.fa-sign-language:before { + content: "\f2a7"; +} +.fa-low-vision:before { + content: "\f2a8"; +} +.fa-viadeo:before { + content: "\f2a9"; +} +.fa-viadeo-square:before { + content: "\f2aa"; +} +.fa-snapchat:before { + content: "\f2ab"; +} +.fa-snapchat-ghost:before { + content: "\f2ac"; +} +.fa-snapchat-square:before { + content: "\f2ad"; +} +.fa-pied-piper:before { + content: "\f2ae"; +} +.fa-first-order:before { + content: "\f2b0"; +} +.fa-yoast:before { + content: "\f2b1"; +} +.fa-themeisle:before { + content: "\f2b2"; +} +.fa-google-plus-circle:before, +.fa-google-plus-official:before { + content: "\f2b3"; +} +.fa-fa:before, +.fa-font-awesome:before { + content: "\f2b4"; +} +.fa-handshake-o:before { + content: "\f2b5"; +} +.fa-envelope-open:before { + content: "\f2b6"; +} +.fa-envelope-open-o:before { + content: "\f2b7"; +} +.fa-linode:before { + content: "\f2b8"; +} +.fa-address-book:before { + content: "\f2b9"; +} +.fa-address-book-o:before { + content: "\f2ba"; +} +.fa-vcard:before, +.fa-address-card:before { + content: "\f2bb"; +} +.fa-vcard-o:before, +.fa-address-card-o:before { + content: "\f2bc"; +} +.fa-user-circle:before { + content: "\f2bd"; +} +.fa-user-circle-o:before { + content: "\f2be"; +} +.fa-user-o:before { + content: "\f2c0"; +} +.fa-id-badge:before { + content: "\f2c1"; +} +.fa-drivers-license:before, +.fa-id-card:before { + content: "\f2c2"; +} +.fa-drivers-license-o:before, +.fa-id-card-o:before { + content: "\f2c3"; +} +.fa-quora:before { + content: "\f2c4"; +} +.fa-free-code-camp:before { + content: "\f2c5"; +} +.fa-telegram:before { + content: "\f2c6"; +} +.fa-thermometer-4:before, +.fa-thermometer:before, +.fa-thermometer-full:before { + content: "\f2c7"; +} +.fa-thermometer-3:before, +.fa-thermometer-three-quarters:before { + content: "\f2c8"; +} +.fa-thermometer-2:before, +.fa-thermometer-half:before { + content: "\f2c9"; +} +.fa-thermometer-1:before, +.fa-thermometer-quarter:before { + content: "\f2ca"; +} +.fa-thermometer-0:before, +.fa-thermometer-empty:before { + content: "\f2cb"; +} +.fa-shower:before { + content: "\f2cc"; +} +.fa-bathtub:before, +.fa-s15:before, +.fa-bath:before { + content: "\f2cd"; +} +.fa-podcast:before { + content: "\f2ce"; +} +.fa-window-maximize:before { + content: "\f2d0"; +} +.fa-window-minimize:before { + content: "\f2d1"; +} +.fa-window-restore:before { + content: "\f2d2"; +} +.fa-times-rectangle:before, +.fa-window-close:before { + content: "\f2d3"; +} +.fa-times-rectangle-o:before, +.fa-window-close-o:before { + content: "\f2d4"; +} +.fa-bandcamp:before { + content: "\f2d5"; +} +.fa-grav:before { + content: "\f2d6"; +} +.fa-etsy:before { + content: "\f2d7"; +} +.fa-imdb:before { + content: "\f2d8"; +} +.fa-ravelry:before { + content: "\f2d9"; +} +.fa-eercast:before { + content: "\f2da"; +} +.fa-microchip:before { + content: "\f2db"; +} +.fa-snowflake-o:before { + content: "\f2dc"; +} +.fa-superpowers:before { + content: "\f2dd"; +} +.fa-wpexplorer:before { + content: "\f2de"; +} +.fa-meetup:before { + content: "\f2e0"; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; +} diff --git a/src/assets/css/font-awesome.min.css b/src/assets/css/font-awesome.min.css new file mode 100644 index 0000000..540440c --- /dev/null +++ b/src/assets/css/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/src/assets/css/global.scss b/src/assets/css/global.scss new file mode 100644 index 0000000..f90a11e --- /dev/null +++ b/src/assets/css/global.scss @@ -0,0 +1,3 @@ +.#{$globalPrefixCls}-hidden { + display: none !important; +} diff --git a/src/assets/css/global_vars.scss b/src/assets/css/global_vars.scss new file mode 100644 index 0000000..6aa755b --- /dev/null +++ b/src/assets/css/global_vars.scss @@ -0,0 +1,9 @@ +$globalPrefixCls: 'qa'; + +$blue: #2e61c8; + +$info: #2dbe8a; + +$warning: #ffb142; + +$error: #f43530; diff --git a/src/assets/fonts/FontAwesome.otf b/src/assets/fonts/FontAwesome.otf new file mode 100644 index 0000000..401ec0f Binary files /dev/null and b/src/assets/fonts/FontAwesome.otf differ diff --git a/src/assets/fonts/fontawesome-webfont.eot b/src/assets/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000..e9f60ca Binary files /dev/null and b/src/assets/fonts/fontawesome-webfont.eot differ diff --git a/src/assets/fonts/fontawesome-webfont.svg b/src/assets/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000..855c845 --- /dev/null +++ b/src/assets/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/fonts/fontawesome-webfont.ttf b/src/assets/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000..35acda2 Binary files /dev/null and b/src/assets/fonts/fontawesome-webfont.ttf differ diff --git a/src/assets/fonts/fontawesome-webfont.woff b/src/assets/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000..400014a Binary files /dev/null and b/src/assets/fonts/fontawesome-webfont.woff differ diff --git a/src/assets/fonts/fontawesome-webfont.woff2 b/src/assets/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000..4d13fc6 Binary files /dev/null and b/src/assets/fonts/fontawesome-webfont.woff2 differ diff --git a/src/assets/ruiwen.jpeg b/src/assets/images/favicon.jpg similarity index 100% rename from src/assets/ruiwen.jpeg rename to src/assets/images/favicon.jpg diff --git a/src/assets/images/ruiwen.gif b/src/assets/images/ruiwen.gif new file mode 100755 index 0000000..e5e9ad8 Binary files /dev/null and b/src/assets/images/ruiwen.gif differ diff --git a/src/assets/images/success.svg b/src/assets/images/success.svg new file mode 100755 index 0000000..1e8a895 --- /dev/null +++ b/src/assets/images/success.svg @@ -0,0 +1,18 @@ + + + + + + + diff --git a/src/assets/index.d.ts b/src/assets/index.d.ts new file mode 100644 index 0000000..658d1ac --- /dev/null +++ b/src/assets/index.d.ts @@ -0,0 +1,5 @@ +declare module '*.svg' +declare module '*.png' +declare module '*.jpg' +declare module '*.jpeg' +declare module '*.gif' diff --git a/src/common/index.ts b/src/common/index.ts new file mode 100644 index 0000000..82483f6 --- /dev/null +++ b/src/common/index.ts @@ -0,0 +1,7 @@ +const PREFIXCLS = 'rl' + +const DELAY_TIME = 2.5 + +const API_URL = 'http://omyleon.com:6260/v1' + +export { PREFIXCLS, DELAY_TIME, API_URL } diff --git a/src/components/Hello/styles/index.less b/src/components/ExampleCom/index.less similarity index 67% rename from src/components/Hello/styles/index.less rename to src/components/ExampleCom/index.less index efb7aa5..ab2c128 100644 --- a/src/components/Hello/styles/index.less +++ b/src/components/ExampleCom/index.less @@ -1,10 +1,12 @@ -@import "./theme"; +@color: #5ab4e3; + .h2 { color: blue; } .name { color: @color; + margin-top: 10px; } .test { @@ -15,8 +17,9 @@ .ruiwen { width: 300px; height: 300px; + margin-top: 20px; background-position: center; transform: translateX(100px); background-size: 300px 300px; - background-image: url(../../../assets/ruiwen.jpeg) + background-image: url(../../assets/images/ruiwen.gif) } diff --git a/src/components/ExampleCom/index.tsx b/src/components/ExampleCom/index.tsx new file mode 100644 index 0000000..5287b7c --- /dev/null +++ b/src/components/ExampleCom/index.tsx @@ -0,0 +1,32 @@ +import * as React from 'react' + +import './index.less' +import { Button } from 'antd-mobile' + +interface IProps { + name: string +} + +class Hello extends React.PureComponent { + state = { count: 1 } + + handleClick = () => { + const { count } = this.state + this.setState({ count: count + 1 }) + } + + render() { + const { name } = this.props + const { count } = this.state + return ( +
+
This is Example component.
+
{`my name is ${name}`}
+ +
this is ruiwen
+
+ ) + } +} + +export default Hello diff --git a/src/components/Hello/index.js b/src/components/Hello/index.js deleted file mode 100644 index 86dac61..0000000 --- a/src/components/Hello/index.js +++ /dev/null @@ -1,41 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' - -import './styles' - -class Hello extends PureComponent { - static propTypes = { - name: PropTypes.string.isRequired, - } - - state = { - count: 1, - } - - handleClick = () => { - const { count } = this.state - this.setState({ count: count + 1 }) - } - - render() { - const { name } = this.props - const { count } = this.state - return ( -
-

This is from Hello component.

-

this is h2

-
- my name is - {name} -
- -
this is ruiwen
-
- ) - } -} - -export default Hello diff --git a/src/components/Hello/loadable.js b/src/components/Hello/loadable.js deleted file mode 100644 index 9aefe10..0000000 --- a/src/components/Hello/loadable.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react' -import Loadable from 'react-loadable' - -export default Loadable({ - loader: () => import('./index'), - loading: () =>

loading...

, -}) diff --git a/src/components/Hello/styles/theme.less b/src/components/Hello/styles/theme.less deleted file mode 100644 index eb30f1c..0000000 --- a/src/components/Hello/styles/theme.less +++ /dev/null @@ -1 +0,0 @@ -@color: #4D926F; diff --git a/src/docs/index.md b/src/docs/index.md deleted file mode 100644 index 9695975..0000000 --- a/src/docs/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# This is a markdown file in docs file - -这是不需要处理,直接拷贝的文件,如果你没有,可以在 config/options 中进行设置 diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 5610cca..0000000 --- a/src/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react' -import { render } from 'react-dom' -import AppHot from './App.hot' - -const root = document.getElementById('root') - -function renderAppToContainer() { - render(, root) -} - -renderAppToContainer() diff --git a/src/index.less b/src/index.less deleted file mode 100644 index 79dbe6b..0000000 --- a/src/index.less +++ /dev/null @@ -1,21 +0,0 @@ -body { - margin: 0; - padding: 0 30px; -} - -h1 { - color: red; -} - -.div { - font-size: 45px; -} - -li { /* 不用的样式,打包会去掉 */ - list-style: none; -} - -.btn { - height: 60px; - line-height: 60px; -} diff --git a/src/index.tmpl.html b/src/index.tmpl.html index 655c174..2fc17af 100644 --- a/src/index.tmpl.html +++ b/src/index.tmpl.html @@ -1,13 +1,38 @@ - - - - <%= htmlWebpackPlugin.options.title %> - - - - -
- + + + + <%= htmlWebpackPlugin.options.title %> + + + + + + + +
+ diff --git a/src/index.tsx b/src/index.tsx new file mode 100644 index 0000000..eb9fb21 --- /dev/null +++ b/src/index.tsx @@ -0,0 +1,7 @@ +import * as React from 'react' +import { render } from 'react-dom' +import AppHot from './App' + +const root = document.getElementById('root') + +render(, root) diff --git a/src/interface.ts b/src/interface.ts new file mode 100644 index 0000000..172275e --- /dev/null +++ b/src/interface.ts @@ -0,0 +1,16 @@ +interface IReqOptions { + uri?: string + query?: object | null + data?: { [key: string]: any } +} + +type resType = 'success' | 'fail' | 'info' + +interface IResponse { + status: number + statusText: string + data: { type: resType; message: string; [key: string]: any } + lists?: any[] +} + +export { IReqOptions, resType, IResponse } diff --git a/src/mobx/action.js b/src/mobx/action.js new file mode 100644 index 0000000..97dec0f --- /dev/null +++ b/src/mobx/action.js @@ -0,0 +1,16 @@ +import { actionNameSymbol, appActionKeySymbol, actionTypeSymbol } from './meta'; +import { App } from './app'; + +const mAction = (config = {}) => target => { + target[actionNameSymbol] = config.name || target.name || null; + target[actionTypeSymbol] = config.type; + App[appActionKeySymbol] = App[appActionKeySymbol] || []; + App[appActionKeySymbol].push({ + target, + name: config.name, + page: config.page, + }); + return target; +}; + +export { mAction }; diff --git a/src/mobx/app.js b/src/mobx/app.js new file mode 100644 index 0000000..1756245 --- /dev/null +++ b/src/mobx/app.js @@ -0,0 +1,194 @@ +import invariant from 'invariant'; +import { + instanceType, + storeTypeSymbol, + storeInstanceSymbol, + getInstanceFuncSymbol, + singleInstanceSymbol, + appActionKeySymbol, + appStoreKeySymbol, +} from './meta'; +import { defineReadOnlyProperty, firstToLowercase } from './utils'; +import AsyncManager from './zone'; + +export class App { + rootStore = {}; + rootAction = {}; + + constructor() { + this.asyncManager = AsyncManager.getInstance(); + this.processStores(); + this.processActions(); + } + + processStores() { + let scannedStores = (App[appStoreKeySymbol] || []).reduce((ret, item) => { + ret[item.page] = ret[item.page] || {}; + ret[item.page][item.name] = item.target; + return ret; + }, {}); + + //扫描的文件 + Object.keys(scannedStores).forEach(pageKey => { + invariant( + !this.rootStore[pageKey], + `dumplicated page or component name for ${pageKey}` + ); + + defineReadOnlyProperty(this.rootStore, pageKey, {}); + + let pageStore = scannedStores[pageKey]; + this.processPageStore(pageStore, this.rootStore[pageKey]); + }); + + } + + processPageStore(pageStore, finalPageStore) { + Object.keys(pageStore).forEach(storeKey => { + this.processSingleStore(pageStore[storeKey], storeKey, finalPageStore); + }); + } + + processSingleStore(storeClassOrInstance, storeKey, finalPageStore) { + let asyncManager = this.asyncManager; + if (typeof storeClassOrInstance == 'function') { + if ( + storeClassOrInstance[storeTypeSymbol] === instanceType.singleton || + storeClassOrInstance[storeTypeSymbol] === undefined + ) { + Object.defineProperty(finalPageStore, firstToLowercase(storeKey), { + configurable: true, + enumerable: true, + get() { + storeClassOrInstance[singleInstanceSymbol] = + storeClassOrInstance[singleInstanceSymbol] || + new storeClassOrInstance(); + + asyncManager.wrapStore(storeClassOrInstance[singleInstanceSymbol]); + + return storeClassOrInstance[singleInstanceSymbol]; + }, + set() { + throw Error('can not set store again'); + }, + }); + } else { + this.processMultiInstance(storeClassOrInstance); + + Object.defineProperty(finalPageStore, firstToLowercase(storeKey), { + configurable: true, + enumerable: true, + get() { + return storeClassOrInstance[getInstanceFuncSymbol]; + }, + set() { + throw Error('can not set store again'); + }, + }); + } + } else { + asyncManager.wrapStore(storeClassOrInstance); + defineReadOnlyProperty( + finalPageStore, + firstToLowercase(storeKey), + storeClassOrInstance + ); + } + } + + processMultiInstance(storeClassOrInstance) { + let asyncManager = this.asyncManager; + + storeClassOrInstance[storeInstanceSymbol] = + storeClassOrInstance[storeInstanceSymbol] || {}; + + storeClassOrInstance[getInstanceFuncSymbol] = + storeClassOrInstance[getInstanceFuncSymbol] || + function(uniqueKey) { + storeClassOrInstance[storeInstanceSymbol][uniqueKey] = + storeClassOrInstance[storeInstanceSymbol][uniqueKey] || + new storeClassOrInstance(); + + asyncManager.wrapStore( + storeClassOrInstance[storeInstanceSymbol][uniqueKey] + ); + + return storeClassOrInstance[storeInstanceSymbol][uniqueKey]; + }; + } + + processActions() { + let scannedActions = (App[appActionKeySymbol] || []).reduce((ret, item) => { + ret[item.page] = ret[item.page] || {}; + ret[item.page][item.name] = item.target; + return ret; + }, {}); + + Object.keys(scannedActions).forEach(pageKey => { + defineReadOnlyProperty(this.rootAction, pageKey, {}); + + let pageAction = scannedActions[pageKey]; + let pageStore = this.rootStore[pageKey]; + this.processPageAction(pageAction, this.rootAction[pageKey], pageStore); + }); + } + + processPageAction(pageAction, finalPageAction, pageStore) { + Object.keys(pageAction).forEach(actionKey => { + this.processSingleAction( + pageAction[actionKey], + actionKey, + finalPageAction, + pageStore + ); + }); + } + + processSingleAction( + actionClassOrInstance, + actionKey, + finalPageAction, + pageStore + ) { + let asyncManager = this.asyncManager; + + if (typeof actionClassOrInstance == 'function') { + Object.defineProperty(finalPageAction, firstToLowercase(actionKey), { + configurable: true, + enumerable: true, + get() { + actionClassOrInstance[singleInstanceSymbol] = + actionClassOrInstance[singleInstanceSymbol] || + new actionClassOrInstance( + pageStore, + finalPageAction, + this.rootStore, + this.rootAction + ); + + asyncManager.wrapAction(actionClassOrInstance[singleInstanceSymbol]); + + return actionClassOrInstance[singleInstanceSymbol]; + }, + set() { + throw Error('can not set action again'); + }, + }); + } else { + asyncManager.wrapAction(actionClassOrInstance); + + defineReadOnlyProperty( + finalPageAction, + firstToLowercase(actionKey), + actionClassOrInstance + ); + } + } +} + +let app = null; + +export function createApp() { + app = app || new App(); + return app; +} diff --git a/src/mobx/index.js b/src/mobx/index.js new file mode 100644 index 0000000..9158559 --- /dev/null +++ b/src/mobx/index.js @@ -0,0 +1,4 @@ +export { mStore } from './store'; +export { mAction } from './action'; +export { instanceType } from './meta'; +export { provider } from './provider'; // 放最后,顺序不能乱,否则有循环依赖问题 diff --git a/src/mobx/meta.js b/src/mobx/meta.js new file mode 100644 index 0000000..690bd71 --- /dev/null +++ b/src/mobx/meta.js @@ -0,0 +1,22 @@ +export const storeNameSymbol = getSymbol('store-name'); +export const storeTypeSymbol = getSymbol('store-type'); +export const storeInstanceSymbol = getSymbol('store-instance'); //多实例缓存 +export const singleInstanceSymbol = getSymbol('single-instance'); //单实例缓存 +export const getInstanceFuncSymbol = getSymbol('get-instance-func'); //多实例根据key获取实例 +export const actionNameSymbol = getSymbol('action-name'); +export const actionTypeSymbol = getSymbol('action-type'); +export const appStoreKeySymbol = getSymbol('app-store-key'); +export const appActionKeySymbol = getSymbol('app-action-key'); + +export const asyncManagerSymbol = getSymbol('async-manager'); +export const storeWrappedSymbol = getSymbol('store-has-wrapped'); +export const actionWrappedSymbol = getSymbol('action-has-wrapped'); + +export const instanceType = { + singleton: getSymbol('singleton'), + multi: getSymbol('multi'), +}; + +function getSymbol(name) { + return typeof Symbol !== 'undefined' ? Symbol(name) : `__symbol-${name}__`; +} diff --git a/src/mobx/provider.js b/src/mobx/provider.js new file mode 100644 index 0000000..e60a3d9 --- /dev/null +++ b/src/mobx/provider.js @@ -0,0 +1,57 @@ +import React, { Component } from 'react'; +import { Provider } from 'mobx-react'; +import { createApp } from './app'; + +const provider = WrapComponentOrElement => { + let app = createApp(); + + if (React.isValidElement(WrapComponentOrElement)) { + let componentName = getDisplayName(WrapComponentOrElement.type); + + return ( + + {WrapComponentOrElement} + + ); + } else { + return class WrapperComponent extends Component { + static displayName = `Provider(${getDisplayName( + WrapComponentOrElement + )})`; + + constructor(props) { + super(props); + } + + componentWillReceiveProps(nextProps) {} + + render() { + const props = this.props; + return ( + + + {this.props.children} + + + ); + } + }; + } +}; + +function getDisplayName(WrappedComponent) { + return WrappedComponent.displayName || WrappedComponent.name || 'Component'; +} + +export { + provider, + getDisplayName, +} diff --git a/src/mobx/store.js b/src/mobx/store.js new file mode 100644 index 0000000..6040572 --- /dev/null +++ b/src/mobx/store.js @@ -0,0 +1,17 @@ +import { + storeNameSymbol, + appStoreKeySymbol, + instanceType, + storeTypeSymbol, +} from './meta'; +import { App } from './app'; + +const mStore = (config = { type: instanceType.singleton }) => target => { + target[storeNameSymbol] = config.name || target.name || null; + target[storeTypeSymbol] = config.type; + App[appStoreKeySymbol] = App[appStoreKeySymbol] || []; + App[appStoreKeySymbol].push({ target, name: config.name, page: config.page }); + return target; +}; + +export { mStore }; diff --git a/src/mobx/utils.js b/src/mobx/utils.js new file mode 100644 index 0000000..4da48f7 --- /dev/null +++ b/src/mobx/utils.js @@ -0,0 +1,42 @@ +export const defineReadOnlyProperty = ( + target, + name, + value, + message = 'property is readonly' +) => { + Object.defineProperty(target, name, { + configurable: true, + enumerable: true, + get() { + return value; + }, + set() { + throw Error(message); + }, + }); +}; + +export const defineHiddenProperty = (target, name, value) => { + Object.defineProperty(target, name, { + configurable: true, + enumerable: false, + writable: false, + value, + }); +}; + +export function firstToLowercase(str) { + return str.charAt(0).toLowerCase() + str.substr(1); +} + +export function isPromiseLike(p) { + if ( + p && + typeof p === 'object' && + typeof p.then === 'function' && + typeof p.catch === 'function' + ) { + return true; + } + return false; +} diff --git a/src/mobx/zone.js b/src/mobx/zone.js new file mode 100644 index 0000000..d8ee33e --- /dev/null +++ b/src/mobx/zone.js @@ -0,0 +1,110 @@ +import 'zone.js'; +import { + asyncManagerSymbol, + storeWrappedSymbol, + actionWrappedSymbol, +} from './meta'; +import { defineHiddenProperty } from './utils'; + +export default class AsyncManager { + static singleton = null; + + static getInstance() { + if (!this.singleton) { + new this(); + } + + return this.singleton; + } + + zone; + + constructor() { + if (AsyncManager.singleton !== null) return AsyncManager.singleton; + + this.init(); + AsyncManager.singleton = this; + } + + init() { + this.zone = Zone.root.fork({ + name: asyncManagerSymbol, + }); + } + + wrapStore(storeInstance) { + if (process.env.NODE_ENV !== 'production') { + if (this.storeHasWrapped(storeInstance)) { + return; + } + + let propKeys = this.getFunctionKeys(storeInstance); + propKeys.forEach(prop => { + if (typeof storeInstance[prop] === 'function') { + storeInstance[prop] = this.wrapStoreFunc( + storeInstance[prop], + storeInstance, + prop + ); + } + }); + defineHiddenProperty(storeInstance, storeWrappedSymbol, true); + } + } + + wrapStoreFunc = (fn, context, prop) => { + return (...args) => { + if (Zone.current !== this.zone) { + console.error( + `store ${context.constructor && + context.constructor.name} 的方法${prop}必须在action里调用` + ); + return; + } + return fn.apply(context, args); + }; + }; + + storeHasWrapped(storeInstance) { + return storeInstance && storeInstance[storeWrappedSymbol] === true; + } + + actionHasWrapped(actionInstance) { + return actionInstance && actionInstance[actionWrappedSymbol] === true; + } + + wrapAction(actionInstance) { + if (process.env.NODE_ENV !== 'production') { + if (this.actionHasWrapped(actionInstance)) { + return; + } + let propKeys = this.getFunctionKeys(actionInstance); + propKeys.forEach(prop => { + if (typeof actionInstance[prop] === 'function') { + actionInstance[prop] = this.wrapActionFunc(actionInstance, prop); + } + }); + + defineHiddenProperty(actionInstance, actionWrappedSymbol, true); + } + } + + wrapActionFunc(action, prop) { + let origin = action[prop]; + return (...args) => { + return this.zone.run(origin, action, args); + }; + } + + getFunctionKeys(obj) { + //获取实例和原型上的属性 + let objProto = Object.getPrototypeOf(obj) || obj.__proto__; + let propKeys = [ + ...Object.keys(obj), + ...Object.getOwnPropertyNames(objProto), + ]; + propKeys = Array.from(new Set(propKeys)); + propKeys = propKeys.filter(key => key !== 'constructor'); + return propKeys; + } +} diff --git a/src/mobxDependence.ts b/src/mobxDependence.ts new file mode 100644 index 0000000..7863fa0 --- /dev/null +++ b/src/mobxDependence.ts @@ -0,0 +1,2 @@ +import './pages/Example/stores/exampleStore' +import './pages/Example/actions/exampleAction' diff --git a/src/pages/404/index.scss b/src/pages/404/index.scss new file mode 100644 index 0000000..8557cba --- /dev/null +++ b/src/pages/404/index.scss @@ -0,0 +1,12 @@ +$prefixCls: 'page-404'; + +.#{$prefixCls} { + height: 100vh; + + h1 { + padding-top: 500px; + text-align: center; + margin: 0; + font-size: 45px; + } +} diff --git a/src/pages/404/index.tsx b/src/pages/404/index.tsx new file mode 100644 index 0000000..041d5e4 --- /dev/null +++ b/src/pages/404/index.tsx @@ -0,0 +1,11 @@ +import * as React from 'react' + +import './index.scss' + +const NoMatch = () => ( +
+

404! page not found...

+
+) + +export default NoMatch diff --git a/src/pages/Example/Loadable.tsx b/src/pages/Example/Loadable.tsx new file mode 100644 index 0000000..8098810 --- /dev/null +++ b/src/pages/Example/Loadable.tsx @@ -0,0 +1,23 @@ +import * as React from 'react' +import Loadable, { LoadingComponentProps } from 'react-loadable' + +class LoadingComponent extends React.PureComponent { + render() { + const { error, isLoading, pastDelay, timedOut } = this.props + return ( +
+ {error} + {isLoading} + {pastDelay} + {timedOut} +
+ ) + } +} + +export default Loadable({ + loader: () => import('./index'), + loading: LoadingComponent, + delay: 100, + timeout: 10000, +}) diff --git a/src/pages/Example/actions/exampleAction.ts b/src/pages/Example/actions/exampleAction.ts new file mode 100644 index 0000000..09f5e2e --- /dev/null +++ b/src/pages/Example/actions/exampleAction.ts @@ -0,0 +1,17 @@ +import { IRootAction, IRootStore } from 'typings' +import { mAction } from '../../../mobx/action' +import { getGoods } from '../apis' + +@mAction +export default class ExampleAction { + constructor(public stores: IRootStore['Example'], public actions: IRootAction['Example']) {} + + async loadGoods() { + const { exampleStore } = this.stores + + exampleStore + .setLoading(true) + .setCurGoods(await getGoods()) + .setLoading(false) + } +} diff --git a/src/pages/Example/apis.ts b/src/pages/Example/apis.ts new file mode 100644 index 0000000..ab8d10d --- /dev/null +++ b/src/pages/Example/apis.ts @@ -0,0 +1,13 @@ +export async function getGoods() { + await wait() + const random = Math.random().toFixed(3) + return { + id: random, + name: `goods-${random}`, + desc: `desc-${random}`, + } +} + +export function wait(delay = 400) { + return new Promise(r => setTimeout(r, delay)) +} diff --git a/src/pages/Example/index.scss b/src/pages/Example/index.scss new file mode 100644 index 0000000..ca70172 --- /dev/null +++ b/src/pages/Example/index.scss @@ -0,0 +1,37 @@ +$prefixCls: 'page-example'; + +.#{$prefixCls} { + h1, h2 { + text-align: center; + } + + ul { + padding: 0; + background: $info; + + li { + list-style: none; + height: 60px; + line-height: 60px; + text-align: center; + font-size: 30px; + } + } + + .am-button { + width: 60%; + height: 60px; + line-height: 60px; + margin: 0 auto; + + .icon-right { + margin-left: 10px; + vertical-align: -5px; + } + } +} + +.loading { + text-align: center; + margin-top: 50px; +} diff --git a/src/pages/Example/index.tsx b/src/pages/Example/index.tsx new file mode 100644 index 0000000..a24b565 --- /dev/null +++ b/src/pages/Example/index.tsx @@ -0,0 +1,69 @@ +import * as React from 'react' +import { inject, observer } from 'mobx-react' +import { Button } from 'antd-mobile' +import ExampleCom from 'components/ExampleCom' +import { IRootStore, IRootAction } from 'typings' + +import './index.scss' + +import successIcon from 'assets/images/success.svg' + +@inject(injector) +@observer +export default class Example extends React.Component { + static defaultProps = { + prefixCls: 'page-example', + } + + componentDidMount() { + this.handleLoadGoods() + } + + handleLoadGoods = () => { + const { action } = this.props + + action!.loadGoods() + } + + render() { + const { prefixCls, store } = this.props + const { + curGoods: { name, desc }, + loading, + } = store! + + return ( +
+

this is example page

+ + successIcon +

当前产品

+ {loading ? ( +

loading...

+ ) : ( +
    +
  • {name}
  • +
  • {desc}
  • +
+ )} +