├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .postcssrc.js
├── README.md
├── build
├── build.js
├── check-versions.js
├── dev-client.js
├── dev-server.js
├── utils.js
├── vue-loader.conf.js
├── webpack.base.conf.js
├── webpack.dev.conf.js
└── webpack.prod.conf.js
├── config
├── dev.env.js
├── index.js
└── prod.env.js
├── index.html
├── package.json
├── src
├── assets
│ └── css
│ │ ├── common.css
│ │ ├── markdown.css
│ │ └── reset.css
├── components
│ ├── backtotop.vue
│ ├── collect.vue
│ ├── header.vue
│ ├── loading.vue
│ ├── menu.vue
│ └── reply.vue
├── filters.js
├── libs
│ ├── alert.js
│ └── inertia.js
├── main.js
├── routers.js
├── views
│ ├── about.vue
│ ├── add.vue
│ ├── detail.vue
│ ├── list.vue
│ ├── login.vue
│ ├── message.vue
│ ├── start.vue
│ └── user.vue
└── vuex
│ └── state.js
└── static
└── .gitkeep
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["latest", {
4 | "es2015": { "modules": false }
5 | }],
6 | "stage-2"
7 | ],
8 | "plugins": ["transform-runtime"],
9 | "comments": false,
10 | "env": {
11 | "test": {
12 | "presets": ["latest", "stage-2"],
13 | "plugins": [ "istanbul" ]
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | build/*.js
2 | config/*.js
3 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // http://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | root: true,
5 | parser: 'babel-eslint',
6 | parserOptions: {
7 | sourceType: 'module'
8 | },
9 | env: {
10 | browser: true,
11 | },
12 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
13 | extends: 'standard',
14 | // required to lint *.vue files
15 | plugins: [
16 | 'html'
17 | ],
18 | // add your custom rules here
19 | 'rules': {
20 | // allow paren-less arrow functions
21 | 'arrow-parens': 0,
22 | // allow async-await
23 | 'generator-star-spacing': 0,
24 | // allow debugger during development
25 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
26 |
27 | "indent": ["error", 4, { "SwitchCase": 1 }],
28 |
29 | "eol-last": 0
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 | npm-debug.log
5 | yarn-error.log
6 |
--------------------------------------------------------------------------------
/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | "plugins": {
5 | // to edit target browsers: use "browserlist" field in package.json
6 | "autoprefixer": {}
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cnode
2 |
3 | > A Vue.js project
4 |
5 | ## Build Setup
6 |
7 | ``` bash
8 | # 下载项目
9 | git clone https://github.com/wocaatm/vue-cnode.git
10 |
11 | # 安装依赖
12 | npm install
13 |
14 | # 开发环境启动
15 | npm run dev
16 |
17 | # 生产环境打包
18 | npm run build
19 |
20 | # 本人qq 1844209986 欢迎一起学习
21 |
--------------------------------------------------------------------------------
/build/build.js:
--------------------------------------------------------------------------------
1 | require('./check-versions')()
2 |
3 | process.env.NODE_ENV = 'production'
4 |
5 | var ora = require('ora')
6 | var rm = require('rimraf')
7 | var path = require('path')
8 | var chalk = require('chalk')
9 | var webpack = require('webpack')
10 | var config = require('../config')
11 | var webpackConfig = require('./webpack.prod.conf')
12 |
13 | var spinner = ora('building for production...')
14 | spinner.start()
15 |
16 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
17 | if (err) throw err
18 | webpack(webpackConfig, function (err, stats) {
19 | spinner.stop()
20 | if (err) throw err
21 | process.stdout.write(stats.toString({
22 | colors: true,
23 | modules: false,
24 | children: false,
25 | chunks: false,
26 | chunkModules: false
27 | }) + '\n\n')
28 |
29 | console.log(chalk.cyan(' Build complete.\n'))
30 | console.log(chalk.yellow(
31 | ' Tip: built files are meant to be served over an HTTP server.\n' +
32 | ' Opening index.html over file:// won\'t work.\n'
33 | ))
34 | })
35 | })
36 |
--------------------------------------------------------------------------------
/build/check-versions.js:
--------------------------------------------------------------------------------
1 | var chalk = require('chalk')
2 | var semver = require('semver')
3 | var packageConfig = require('../package.json')
4 |
5 | function exec (cmd) {
6 | return require('child_process').execSync(cmd).toString().trim()
7 | }
8 |
9 | var versionRequirements = [
10 | {
11 | name: 'node',
12 | currentVersion: semver.clean(process.version),
13 | versionRequirement: packageConfig.engines.node
14 | },
15 | {
16 | name: 'npm',
17 | currentVersion: exec('npm --version'),
18 | versionRequirement: packageConfig.engines.npm
19 | }
20 | ]
21 |
22 | module.exports = function () {
23 | var warnings = []
24 | for (var i = 0; i < versionRequirements.length; i++) {
25 | var mod = versionRequirements[i]
26 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
27 | warnings.push(mod.name + ': ' +
28 | chalk.red(mod.currentVersion) + ' should be ' +
29 | chalk.green(mod.versionRequirement)
30 | )
31 | }
32 | }
33 |
34 | if (warnings.length) {
35 | console.log('')
36 | console.log(chalk.yellow('To use this template, you must update following to modules:'))
37 | console.log()
38 | for (var i = 0; i < warnings.length; i++) {
39 | var warning = warnings[i]
40 | console.log(' ' + warning)
41 | }
42 | console.log()
43 | process.exit(1)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/build/dev-client.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | require('eventsource-polyfill')
3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
4 |
5 | hotClient.subscribe(function (event) {
6 | if (event.action === 'reload') {
7 | window.location.reload()
8 | }
9 | })
10 |
--------------------------------------------------------------------------------
/build/dev-server.js:
--------------------------------------------------------------------------------
1 | require('./check-versions')()
2 |
3 | var config = require('../config')
4 | if (!process.env.NODE_ENV) {
5 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
6 | }
7 |
8 | var opn = require('opn')
9 | var path = require('path')
10 | var express = require('express')
11 | var webpack = require('webpack')
12 | var proxyMiddleware = require('http-proxy-middleware')
13 | var webpackConfig = require('./webpack.dev.conf')
14 |
15 | // default port where dev server listens for incoming traffic
16 | var port = process.env.PORT || config.dev.port
17 | // automatically open browser, if not set will be false
18 | var autoOpenBrowser = !!config.dev.autoOpenBrowser
19 | // Define HTTP proxies to your custom API backend
20 | // https://github.com/chimurai/http-proxy-middleware
21 | var proxyTable = config.dev.proxyTable
22 |
23 | var app = express()
24 | var compiler = webpack(webpackConfig)
25 |
26 | var devMiddleware = require('webpack-dev-middleware')(compiler, {
27 | publicPath: webpackConfig.output.publicPath,
28 | quiet: true
29 | })
30 |
31 | var hotMiddleware = require('webpack-hot-middleware')(compiler, {
32 | log: () => {}
33 | })
34 | // force page reload when html-webpack-plugin template changes
35 | compiler.plugin('compilation', function (compilation) {
36 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
37 | hotMiddleware.publish({ action: 'reload' })
38 | cb()
39 | })
40 | })
41 |
42 | // proxy api requests
43 | Object.keys(proxyTable).forEach(function (context) {
44 | var options = proxyTable[context]
45 | if (typeof options === 'string') {
46 | options = { target: options }
47 | }
48 | app.use(proxyMiddleware(options.filter || context, options))
49 | })
50 |
51 | // handle fallback for HTML5 history API
52 | app.use(require('connect-history-api-fallback')())
53 |
54 | // serve webpack bundle output
55 | app.use(devMiddleware)
56 |
57 | // enable hot-reload and state-preserving
58 | // compilation error display
59 | app.use(hotMiddleware)
60 |
61 | // serve pure static assets
62 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
63 | app.use(staticPath, express.static('./static'))
64 |
65 | var uri = 'http://localhost:' + port
66 |
67 | devMiddleware.waitUntilValid(function () {
68 | console.log('> Listening at ' + uri + '\n')
69 | })
70 |
71 | module.exports = app.listen(port, function (err) {
72 | if (err) {
73 | console.log(err)
74 | return
75 | }
76 |
77 | // when env is testing, don't need open it
78 | if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
79 | opn(uri)
80 | }
81 | })
82 |
--------------------------------------------------------------------------------
/build/utils.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var config = require('../config')
3 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
4 |
5 | exports.assetsPath = function (_path) {
6 | var assetsSubDirectory = process.env.NODE_ENV === 'production'
7 | ? config.build.assetsSubDirectory
8 | : config.dev.assetsSubDirectory
9 | return path.posix.join(assetsSubDirectory, _path)
10 | }
11 |
12 | exports.cssLoaders = function (options) {
13 | options = options || {}
14 |
15 | var cssLoader = {
16 | loader: 'css-loader',
17 | options: {
18 | minimize: process.env.NODE_ENV === 'production',
19 | sourceMap: options.sourceMap
20 | }
21 | }
22 |
23 | // generate loader string to be used with extract text plugin
24 | function generateLoaders (loader, loaderOptions) {
25 | var loaders = [cssLoader]
26 | if (loader) {
27 | loaders.push({
28 | loader: loader + '-loader',
29 | options: Object.assign({}, loaderOptions, {
30 | sourceMap: options.sourceMap
31 | })
32 | })
33 | }
34 |
35 | // Extract CSS when that option is specified
36 | // (which is the case during production build)
37 | if (options.extract) {
38 | return ExtractTextPlugin.extract({
39 | use: loaders,
40 | fallback: 'vue-style-loader'
41 | })
42 | } else {
43 | return ['vue-style-loader'].concat(loaders)
44 | }
45 | }
46 |
47 | // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html
48 | return {
49 | css: generateLoaders(),
50 | postcss: generateLoaders(),
51 | less: generateLoaders('less'),
52 | sass: generateLoaders('sass', { indentedSyntax: true }),
53 | scss: generateLoaders('sass'),
54 | stylus: generateLoaders('stylus'),
55 | styl: generateLoaders('stylus')
56 | }
57 | }
58 |
59 | // Generate loaders for standalone style files (outside of .vue)
60 | exports.styleLoaders = function (options) {
61 | var output = []
62 | var loaders = exports.cssLoaders(options)
63 | for (var extension in loaders) {
64 | var loader = loaders[extension]
65 | output.push({
66 | test: new RegExp('\\.' + extension + '$'),
67 | use: loader
68 | })
69 | }
70 | return output
71 | }
72 |
--------------------------------------------------------------------------------
/build/vue-loader.conf.js:
--------------------------------------------------------------------------------
1 | var utils = require('./utils')
2 | var config = require('../config')
3 | var isProduction = process.env.NODE_ENV === 'production'
4 |
5 | module.exports = {
6 | loaders: utils.cssLoaders({
7 | sourceMap: isProduction
8 | ? config.build.productionSourceMap
9 | : config.dev.cssSourceMap,
10 | extract: isProduction
11 | })
12 | }
13 |
--------------------------------------------------------------------------------
/build/webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var utils = require('./utils')
3 | var config = require('../config')
4 | var vueLoaderConfig = require('./vue-loader.conf')
5 |
6 | function resolve (dir) {
7 | return path.join(__dirname, '..', dir)
8 | }
9 |
10 | module.exports = {
11 | entry: {
12 | app: './src/main.js'
13 | },
14 | output: {
15 | path: config.build.assetsRoot,
16 | filename: '[name].js',
17 | publicPath: process.env.NODE_ENV === 'production'
18 | ? config.build.assetsPublicPath
19 | : config.dev.assetsPublicPath
20 | },
21 | resolve: {
22 | extensions: ['.js', '.vue', '.json'],
23 | alias: {
24 | 'vue$': 'vue/dist/vue.esm.js',
25 | '@': resolve('src'),
26 | }
27 | },
28 | module: {
29 | rules: [
30 | {
31 | test: /\.(js|vue)$/,
32 | loader: 'eslint-loader',
33 | enforce: "pre",
34 | include: [resolve('src'), resolve('test')],
35 | options: {
36 | formatter: require('eslint-friendly-formatter')
37 | }
38 | },
39 | {
40 | test: /\.vue$/,
41 | loader: 'vue-loader',
42 | options: vueLoaderConfig
43 | },
44 | {
45 | test: /\.js$/,
46 | loader: 'babel-loader',
47 | include: [resolve('src'), resolve('test')]
48 | },
49 | {
50 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
51 | loader: 'url-loader',
52 | query: {
53 | limit: 10000,
54 | name: utils.assetsPath('img/[name].[hash:7].[ext]')
55 | }
56 | },
57 | {
58 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
59 | loader: 'url-loader',
60 | query: {
61 | limit: 10000,
62 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
63 | }
64 | }
65 | ]
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/build/webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | var utils = require('./utils')
2 | var webpack = require('webpack')
3 | var config = require('../config')
4 | var merge = require('webpack-merge')
5 | var baseWebpackConfig = require('./webpack.base.conf')
6 | var HtmlWebpackPlugin = require('html-webpack-plugin')
7 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
8 |
9 | // add hot-reload related code to entry chunks
10 | Object.keys(baseWebpackConfig.entry).forEach(function (name) {
11 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
12 | })
13 |
14 | module.exports = merge(baseWebpackConfig, {
15 | module: {
16 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
17 | },
18 | // cheap-module-eval-source-map is faster for development
19 | devtool: '#cheap-module-eval-source-map',
20 | plugins: [
21 | new webpack.DefinePlugin({
22 | 'process.env': config.dev.env
23 | }),
24 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
25 | new webpack.HotModuleReplacementPlugin(),
26 | new webpack.NoEmitOnErrorsPlugin(),
27 | // https://github.com/ampedandwired/html-webpack-plugin
28 | new HtmlWebpackPlugin({
29 | filename: 'index.html',
30 | template: 'index.html',
31 | inject: true
32 | }),
33 | new FriendlyErrorsPlugin()
34 | ]
35 | })
36 |
--------------------------------------------------------------------------------
/build/webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var utils = require('./utils')
3 | var webpack = require('webpack')
4 | var config = require('../config')
5 | var merge = require('webpack-merge')
6 | var baseWebpackConfig = require('./webpack.base.conf')
7 | var CopyWebpackPlugin = require('copy-webpack-plugin')
8 | var HtmlWebpackPlugin = require('html-webpack-plugin')
9 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
10 | var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
11 |
12 | var env = config.build.env
13 |
14 | var webpackConfig = merge(baseWebpackConfig, {
15 | module: {
16 | rules: utils.styleLoaders({
17 | sourceMap: config.build.productionSourceMap,
18 | extract: true
19 | })
20 | },
21 | devtool: config.build.productionSourceMap ? '#source-map' : false,
22 | output: {
23 | path: config.build.assetsRoot,
24 | filename: utils.assetsPath('js/[name].[chunkhash].js'),
25 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
26 | },
27 | plugins: [
28 | // http://vuejs.github.io/vue-loader/en/workflow/production.html
29 | new webpack.DefinePlugin({
30 | 'process.env': env
31 | }),
32 | new webpack.optimize.UglifyJsPlugin({
33 | compress: {
34 | warnings: false
35 | },
36 | sourceMap: true
37 | }),
38 | // extract css into its own file
39 | new ExtractTextPlugin({
40 | filename: utils.assetsPath('css/[name].[contenthash].css')
41 | }),
42 | // Compress extracted CSS. We are using this plugin so that possible
43 | // duplicated CSS from different components can be deduped.
44 | new OptimizeCSSPlugin(),
45 | // generate dist index.html with correct asset hash for caching.
46 | // you can customize output by editing /index.html
47 | // see https://github.com/ampedandwired/html-webpack-plugin
48 | new HtmlWebpackPlugin({
49 | filename: config.build.index,
50 | template: 'index.html',
51 | inject: true,
52 | minify: {
53 | removeComments: true,
54 | collapseWhitespace: true,
55 | removeAttributeQuotes: true
56 | // more options:
57 | // https://github.com/kangax/html-minifier#options-quick-reference
58 | },
59 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin
60 | chunksSortMode: 'dependency'
61 | }),
62 | // split vendor js into its own file
63 | new webpack.optimize.CommonsChunkPlugin({
64 | name: 'vendor',
65 | minChunks: function (module, count) {
66 | // any required modules inside node_modules are extracted to vendor
67 | return (
68 | module.resource &&
69 | /\.js$/.test(module.resource) &&
70 | module.resource.indexOf(
71 | path.join(__dirname, '../node_modules')
72 | ) === 0
73 | )
74 | }
75 | }),
76 | // extract webpack runtime and module manifest to its own file in order to
77 | // prevent vendor hash from being updated whenever app bundle is updated
78 | new webpack.optimize.CommonsChunkPlugin({
79 | name: 'manifest',
80 | chunks: ['vendor']
81 | }),
82 | // copy custom static assets
83 | new CopyWebpackPlugin([
84 | {
85 | from: path.resolve(__dirname, '../static'),
86 | to: config.build.assetsSubDirectory,
87 | ignore: ['.*']
88 | }
89 | ])
90 | ]
91 | })
92 |
93 | if (config.build.productionGzip) {
94 | var CompressionWebpackPlugin = require('compression-webpack-plugin')
95 |
96 | webpackConfig.plugins.push(
97 | new CompressionWebpackPlugin({
98 | asset: '[path].gz[query]',
99 | algorithm: 'gzip',
100 | test: new RegExp(
101 | '\\.(' +
102 | config.build.productionGzipExtensions.join('|') +
103 | ')$'
104 | ),
105 | threshold: 10240,
106 | minRatio: 0.8
107 | })
108 | )
109 | }
110 |
111 | if (config.build.bundleAnalyzerReport) {
112 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
113 | webpackConfig.plugins.push(new BundleAnalyzerPlugin())
114 | }
115 |
116 | module.exports = webpackConfig
117 |
--------------------------------------------------------------------------------
/config/dev.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var prodEnv = require('./prod.env')
3 |
4 | module.exports = merge(prodEnv, {
5 | NODE_ENV: '"development"'
6 | })
7 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | // see http://vuejs-templates.github.io/webpack for documentation.
2 | var path = require('path')
3 |
4 | module.exports = {
5 | build: {
6 | env: require('./prod.env'),
7 | index: path.resolve(__dirname, '../dist/index.html'),
8 | assetsRoot: path.resolve(__dirname, '../dist'),
9 | assetsSubDirectory: 'static',
10 | assetsPublicPath: '/',
11 | productionSourceMap: true,
12 | // Gzip off by default as many popular static hosts such as
13 | // Surge or Netlify already gzip all static assets for you.
14 | // Before setting to `true`, make sure to:
15 | // npm install --save-dev compression-webpack-plugin
16 | productionGzip: false,
17 | productionGzipExtensions: ['js', 'css'],
18 | // Run the build command with an extra argument to
19 | // View the bundle analyzer report after build finishes:
20 | // `npm run build --report`
21 | // Set to `true` or `false` to always turn it on or off
22 | bundleAnalyzerReport: process.env.npm_config_report
23 | },
24 | dev: {
25 | env: require('./dev.env'),
26 | port: 8080,
27 | autoOpenBrowser: true,
28 | assetsSubDirectory: 'static',
29 | assetsPublicPath: '/',
30 | proxyTable: {},
31 | // CSS Sourcemaps off by default because relative paths are "buggy"
32 | // with this option, according to the CSS-Loader README
33 | // (https://github.com/webpack/css-loader#sourcemaps)
34 | // In our experience, they generally work as expected,
35 | // just be aware of this issue when enabling this option.
36 | cssSourceMap: false
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/config/prod.env.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | NODE_ENV: '"production"'
3 | }
4 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | cnode.js社区
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cnode",
3 | "version": "1.0.0",
4 | "description": "A Vue.js project",
5 | "author": "lc",
6 | "private": true,
7 | "scripts": {
8 | "dev": "node build/dev-server.js",
9 | "build": "node build/build.js",
10 | "lint": "eslint --ext .js,.vue src"
11 | },
12 | "dependencies": {
13 | "font-awesome": "^4.7.0",
14 | "hammerjs": "^2.0.8",
15 | "moment": "^2.18.0",
16 | "timeago": "^1.5.4",
17 | "vue": "^2.2.1",
18 | "vue-resource": "^1.2.1",
19 | "vue-router": "^2.3.0",
20 | "vuex": "^2.2.1"
21 | },
22 | "devDependencies": {
23 | "autoprefixer": "^6.7.2",
24 | "babel-core": "^6.22.1",
25 | "babel-eslint": "^7.1.1",
26 | "babel-loader": "^6.2.10",
27 | "babel-plugin-transform-runtime": "^6.22.0",
28 | "babel-preset-latest": "^6.22.0",
29 | "babel-preset-stage-2": "^6.22.0",
30 | "babel-register": "^6.22.0",
31 | "chalk": "^1.1.3",
32 | "connect-history-api-fallback": "^1.3.0",
33 | "copy-webpack-plugin": "^4.0.1",
34 | "css-loader": "^0.26.1",
35 | "eslint": "^3.14.1",
36 | "eslint-config-standard": "^6.2.1",
37 | "eslint-friendly-formatter": "^2.0.7",
38 | "eslint-loader": "^1.6.1",
39 | "eslint-plugin-html": "^2.0.0",
40 | "eslint-plugin-promise": "^3.4.0",
41 | "eslint-plugin-standard": "^2.0.1",
42 | "eventsource-polyfill": "^0.9.6",
43 | "express": "^4.14.1",
44 | "extract-text-webpack-plugin": "^2.0.0",
45 | "file-loader": "^0.10.0",
46 | "friendly-errors-webpack-plugin": "^1.1.3",
47 | "function-bind": "^1.1.0",
48 | "html-webpack-plugin": "^2.28.0",
49 | "http-proxy-middleware": "^0.17.3",
50 | "mint-ui": "^2.1.1",
51 | "opn": "^4.0.2",
52 | "optimize-css-assets-webpack-plugin": "^1.3.0",
53 | "ora": "^1.1.0",
54 | "rimraf": "^2.6.0",
55 | "semver": "^5.3.0",
56 | "stylus": "^0.54.5",
57 | "stylus-loader": "^2.5.0",
58 | "url-loader": "^0.5.7",
59 | "vue-loader": "^11.0.0",
60 | "vue-style-loader": "^2.0.0",
61 | "vue-template-compiler": "^2.2.1",
62 | "webpack": "^2.2.1",
63 | "webpack-bundle-analyzer": "^2.2.1",
64 | "webpack-dev-middleware": "^1.10.0",
65 | "webpack-hot-middleware": "^2.16.1",
66 | "webpack-merge": "^2.6.1"
67 | },
68 | "engines": {
69 | "node": ">= 4.0.0",
70 | "npm": ">= 3.0.0"
71 | },
72 | "browserlist": [
73 | "> 1%",
74 | "last 2 versions",
75 | "not ie <= 8"
76 | ]
77 | }
78 |
--------------------------------------------------------------------------------
/src/assets/css/common.css:
--------------------------------------------------------------------------------
1 | .alert-container{
2 | position:fixed;
3 | left:50%;
4 | top:50%;
5 | transform:translate(-50%,-50%);
6 | max-width:60%;
7 | padding:15px;
8 | border-radius: 8px;
9 | background:rgba(0,0,0,.7);
10 | color:#fff;
11 | font-size:14px;
12 | z-index:10;
13 | }
14 |
15 | .fl{
16 | float:left;
17 | }
18 | .fr{
19 | float:right;
20 | }
21 | .clearfix:after{
22 | content:'';
23 | display: table;
24 | clear:both;
25 | }
--------------------------------------------------------------------------------
/src/assets/css/markdown.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: octicons-anchor;
3 | src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAYcAA0AAAAACjQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABMAAAABwAAAAca8vGTk9TLzIAAAFMAAAARAAAAFZG1VHVY21hcAAAAZAAAAA+AAABQgAP9AdjdnQgAAAB0AAAAAQAAAAEACICiGdhc3AAAAHUAAAACAAAAAj//wADZ2x5ZgAAAdwAAADRAAABEKyikaNoZWFkAAACsAAAAC0AAAA2AtXoA2hoZWEAAALgAAAAHAAAACQHngNFaG10eAAAAvwAAAAQAAAAEAwAACJsb2NhAAADDAAAAAoAAAAKALIAVG1heHAAAAMYAAAAHwAAACABEAB2bmFtZQAAAzgAAALBAAAFu3I9x/Nwb3N0AAAF/AAAAB0AAAAvaoFvbwAAAAEAAAAAzBdyYwAAAADP2IQvAAAAAM/bz7t4nGNgZGFgnMDAysDB1Ml0hoGBoR9CM75mMGLkYGBgYmBlZsAKAtJcUxgcPsR8iGF2+O/AEMPsznAYKMwIkgMA5REMOXicY2BgYGaAYBkGRgYQsAHyGMF8FgYFIM0ChED+h5j//yEk/3KoSgZGNgYYk4GRCUgwMaACRoZhDwCs7QgGAAAAIgKIAAAAAf//AAJ4nHWMMQrCQBBF/0zWrCCIKUQsTDCL2EXMohYGSSmorScInsRGL2DOYJe0Ntp7BK+gJ1BxF1stZvjz/v8DRghQzEc4kIgKwiAppcA9LtzKLSkdNhKFY3HF4lK69ExKslx7Xa+vPRVS43G98vG1DnkDMIBUgFN0MDXflU8tbaZOUkXUH0+U27RoRpOIyCKjbMCVejwypzJJG4jIwb43rfl6wbwanocrJm9XFYfskuVC5K/TPyczNU7b84CXcbxks1Un6H6tLH9vf2LRnn8Ax7A5WQAAAHicY2BkYGAA4teL1+yI57f5ysDNwgAC529f0kOmWRiYVgEpDgYmEA8AUzEKsQAAAHicY2BkYGB2+O/AEMPCAAJAkpEBFbAAADgKAe0EAAAiAAAAAAQAAAAEAAAAAAAAKgAqACoAiAAAeJxjYGRgYGBhsGFgYgABEMkFhAwM/xn0QAIAD6YBhwB4nI1Ty07cMBS9QwKlQapQW3VXySvEqDCZGbGaHULiIQ1FKgjWMxknMfLEke2A+IJu+wntrt/QbVf9gG75jK577Lg8K1qQPCfnnnt8fX1NRC/pmjrk/zprC+8D7tBy9DHgBXoWfQ44Av8t4Bj4Z8CLtBL9CniJluPXASf0Lm4CXqFX8Q84dOLnMB17N4c7tBo1AS/Qi+hTwBH4rwHHwN8DXqQ30XXAS7QaLwSc0Gn8NuAVWou/gFmnjLrEaEh9GmDdDGgL3B4JsrRPDU2hTOiMSuJUIdKQQayiAth69r6akSSFqIJuA19TrzCIaY8sIoxyrNIrL//pw7A2iMygkX5vDj+G+kuoLdX4GlGK/8Lnlz6/h9MpmoO9rafrz7ILXEHHaAx95s9lsI7AHNMBWEZHULnfAXwG9/ZqdzLI08iuwRloXE8kfhXYAvE23+23DU3t626rbs8/8adv+9DWknsHp3E17oCf+Z48rvEQNZ78paYM38qfk3v/u3l3u3GXN2Dmvmvpf1Srwk3pB/VSsp512bA/GG5i2WJ7wu430yQ5K3nFGiOqgtmSB5pJVSizwaacmUZzZhXLlZTq8qGGFY2YcSkqbth6aW1tRmlaCFs2016m5qn36SbJrqosG4uMV4aP2PHBmB3tjtmgN2izkGQyLWprekbIntJFing32a5rKWCN/SdSoga45EJykyQ7asZvHQ8PTm6cslIpwyeyjbVltNikc2HTR7YKh9LBl9DADC0U/jLcBZDKrMhUBfQBvXRzLtFtjU9eNHKin0x5InTqb8lNpfKv1s1xHzTXRqgKzek/mb7nB8RZTCDhGEX3kK/8Q75AmUM/eLkfA+0Hi908Kx4eNsMgudg5GLdRD7a84npi+YxNr5i5KIbW5izXas7cHXIMAau1OueZhfj+cOcP3P8MNIWLyYOBuxL6DRylJ4cAAAB4nGNgYoAALjDJyIAOWMCiTIxMLDmZedkABtIBygAAAA==) format('woff');
4 | }
5 |
6 | .markdown-body {
7 | -webkit-text-size-adjust: 100%;
8 | text-size-adjust: 100%;
9 | color: #333;
10 | font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
11 | font-size: 16px;
12 | line-height: 1.6;
13 | word-wrap: break-word;
14 | }
15 |
16 | .markdown-body a {
17 | background-color: transparent;
18 | }
19 |
20 | .markdown-body a:active,
21 | .markdown-body a:hover {
22 | outline: 0;
23 | }
24 |
25 | .markdown-body strong {
26 | font-weight: bold;
27 | }
28 |
29 | .markdown-body h1 {
30 | font-size: 2em;
31 | margin: 0.67em 0;
32 | }
33 |
34 | .markdown-body img {
35 | border: 0;
36 | }
37 |
38 | .markdown-body hr {
39 | box-sizing: content-box;
40 | height: 0;
41 | }
42 |
43 | .markdown-body pre {
44 | overflow: auto;
45 | }
46 |
47 | .markdown-body code,
48 | .markdown-body kbd,
49 | .markdown-body pre {
50 | font-family: monospace, monospace;
51 | font-size: 1em;
52 | }
53 |
54 | .markdown-body input {
55 | color: inherit;
56 | font: inherit;
57 | margin: 0;
58 | }
59 |
60 | .markdown-body html input[disabled] {
61 | cursor: default;
62 | }
63 |
64 | .markdown-body input {
65 | line-height: normal;
66 | }
67 |
68 | .markdown-body input[type="checkbox"] {
69 | box-sizing: border-box;
70 | padding: 0;
71 | }
72 |
73 | .markdown-body table {
74 | border-collapse: collapse;
75 | border-spacing: 0;
76 | }
77 |
78 | .markdown-body td,
79 | .markdown-body th {
80 | padding: 0;
81 | }
82 |
83 | .markdown-body * {
84 | box-sizing: border-box;
85 | }
86 |
87 | .markdown-body input {
88 | font: 13px/1.4 Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
89 | }
90 |
91 | .markdown-body a {
92 | color: #4078c0;
93 | text-decoration: none;
94 | }
95 |
96 | .markdown-body a:hover,
97 | .markdown-body a:active {
98 | text-decoration: underline;
99 | }
100 |
101 | .markdown-body hr {
102 | height: 0;
103 | margin: 15px 0;
104 | overflow: hidden;
105 | background: transparent;
106 | border: 0;
107 | border-bottom: 1px solid #ddd;
108 | }
109 |
110 | .markdown-body hr:before {
111 | display: table;
112 | content: "";
113 | }
114 |
115 | .markdown-body hr:after {
116 | display: table;
117 | clear: both;
118 | content: "";
119 | }
120 |
121 | .markdown-body h1,
122 | .markdown-body h2,
123 | .markdown-body h3,
124 | .markdown-body h4,
125 | .markdown-body h5,
126 | .markdown-body h6 {
127 | margin-top: 15px;
128 | margin-bottom: 15px;
129 | line-height: 1.1;
130 | }
131 |
132 | .markdown-body h1 {
133 | font-size: 30px;
134 | }
135 |
136 | .markdown-body h2 {
137 | font-size: 21px;
138 | }
139 |
140 | .markdown-body h3 {
141 | font-size: 16px;
142 | }
143 |
144 | .markdown-body h4 {
145 | font-size: 14px;
146 | }
147 |
148 | .markdown-body h5 {
149 | font-size: 12px;
150 | }
151 |
152 | .markdown-body h6 {
153 | font-size: 11px;
154 | }
155 |
156 | .markdown-body blockquote {
157 | margin: 0;
158 | }
159 |
160 | .markdown-body ul,
161 | .markdown-body ol {
162 | padding: 0;
163 | margin-top: 0;
164 | margin-bottom: 0;
165 | }
166 |
167 | .markdown-body ol ol,
168 | .markdown-body ul ol {
169 | list-style-type: lower-roman;
170 | }
171 |
172 | .markdown-body ul ul ol,
173 | .markdown-body ul ol ol,
174 | .markdown-body ol ul ol,
175 | .markdown-body ol ol ol {
176 | list-style-type: lower-alpha;
177 | }
178 |
179 | .markdown-body dd {
180 | margin-left: 0;
181 | }
182 |
183 | .markdown-body code {
184 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
185 | font-size: 12px;
186 | }
187 |
188 | .markdown-body pre {
189 | margin-top: 0;
190 | margin-bottom: 0;
191 | font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
192 | }
193 |
194 | .markdown-body .select::-ms-expand {
195 | opacity: 0;
196 | }
197 |
198 | .markdown-body .octicon {
199 | font: normal normal normal 16px/1 octicons-anchor;
200 | display: inline-block;
201 | text-decoration: none;
202 | text-rendering: auto;
203 | -webkit-font-smoothing: antialiased;
204 | -moz-osx-font-smoothing: grayscale;
205 | user-select: none;
206 | }
207 |
208 | .markdown-body .octicon-link:before {
209 | content: '\f05c';
210 | }
211 |
212 | .markdown-body>*:first-child {
213 | margin-top: 0 !important;
214 | }
215 |
216 | .markdown-body>*:last-child {
217 | margin-bottom: 0 !important;
218 | }
219 |
220 | .markdown-body a:not([href]) {
221 | color: inherit;
222 | text-decoration: none;
223 | }
224 |
225 | .markdown-body .anchor {
226 | display: inline-block;
227 | padding-right: 2px;
228 | margin-left: -18px;
229 | }
230 |
231 | .markdown-body .anchor:focus {
232 | outline: none;
233 | }
234 |
235 | .markdown-body h1,
236 | .markdown-body h2,
237 | .markdown-body h3,
238 | .markdown-body h4,
239 | .markdown-body h5,
240 | .markdown-body h6 {
241 | margin-top: 1em;
242 | margin-bottom: 16px;
243 | font-weight: bold;
244 | line-height: 1.4;
245 | }
246 |
247 | .markdown-body h1 .octicon-link,
248 | .markdown-body h2 .octicon-link,
249 | .markdown-body h3 .octicon-link,
250 | .markdown-body h4 .octicon-link,
251 | .markdown-body h5 .octicon-link,
252 | .markdown-body h6 .octicon-link {
253 | color: #000;
254 | vertical-align: middle;
255 | visibility: hidden;
256 | }
257 |
258 | .markdown-body h1:hover .anchor,
259 | .markdown-body h2:hover .anchor,
260 | .markdown-body h3:hover .anchor,
261 | .markdown-body h4:hover .anchor,
262 | .markdown-body h5:hover .anchor,
263 | .markdown-body h6:hover .anchor {
264 | text-decoration: none;
265 | }
266 |
267 | .markdown-body h1:hover .anchor .octicon-link,
268 | .markdown-body h2:hover .anchor .octicon-link,
269 | .markdown-body h3:hover .anchor .octicon-link,
270 | .markdown-body h4:hover .anchor .octicon-link,
271 | .markdown-body h5:hover .anchor .octicon-link,
272 | .markdown-body h6:hover .anchor .octicon-link {
273 | visibility: visible;
274 | }
275 |
276 | .markdown-body h1 {
277 | padding-bottom: 0.3em;
278 | font-size: 2.25em;
279 | line-height: 1.2;
280 | border-bottom: 1px solid #eee;
281 | }
282 |
283 | .markdown-body h1 .anchor {
284 | line-height: 1;
285 | }
286 |
287 | .markdown-body h2 {
288 | padding-bottom: 0.3em;
289 | font-size: 1.75em;
290 | line-height: 1.225;
291 | border-bottom: 1px solid #eee;
292 | }
293 |
294 | .markdown-body h2 .anchor {
295 | line-height: 1;
296 | }
297 |
298 | .markdown-body h3 {
299 | font-size: 1.5em;
300 | line-height: 1.43;
301 | }
302 |
303 | .markdown-body h3 .anchor {
304 | line-height: 1.2;
305 | }
306 |
307 | .markdown-body h4 {
308 | font-size: 1.25em;
309 | }
310 |
311 | .markdown-body h4 .anchor {
312 | line-height: 1.2;
313 | }
314 |
315 | .markdown-body h5 {
316 | font-size: 1em;
317 | }
318 |
319 | .markdown-body h5 .anchor {
320 | line-height: 1.1;
321 | }
322 |
323 | .markdown-body h6 {
324 | font-size: 1em;
325 | color: #777;
326 | }
327 |
328 | .markdown-body h6 .anchor {
329 | line-height: 1.1;
330 | }
331 |
332 | .markdown-body p,
333 | .markdown-body blockquote,
334 | .markdown-body ul,
335 | .markdown-body ol,
336 | .markdown-body dl,
337 | .markdown-body table,
338 | .markdown-body pre {
339 | margin-top: 0;
340 | margin-bottom: 16px;
341 | }
342 |
343 | .markdown-body hr {
344 | height: 4px;
345 | padding: 0;
346 | margin: 16px 0;
347 | background-color: #e7e7e7;
348 | border: 0 none;
349 | }
350 |
351 | .markdown-body ul,
352 | .markdown-body ol {
353 | padding-left: 2em;
354 | }
355 |
356 | .markdown-body ul ul,
357 | .markdown-body ul ol,
358 | .markdown-body ol ol,
359 | .markdown-body ol ul {
360 | margin-top: 0;
361 | margin-bottom: 0;
362 | }
363 |
364 | .markdown-body li>p {
365 | margin-top: 16px;
366 | }
367 |
368 | .markdown-body dl {
369 | padding: 0;
370 | }
371 |
372 | .markdown-body dl dt {
373 | padding: 0;
374 | margin-top: 16px;
375 | font-size: 1em;
376 | font-style: italic;
377 | font-weight: bold;
378 | }
379 |
380 | .markdown-body dl dd {
381 | padding: 0 16px;
382 | margin-bottom: 16px;
383 | }
384 |
385 | .markdown-body blockquote {
386 | padding: 0 15px;
387 | color: #777;
388 | border-left: 4px solid #ddd;
389 | }
390 |
391 | .markdown-body blockquote>:first-child {
392 | margin-top: 0;
393 | }
394 |
395 | .markdown-body blockquote>:last-child {
396 | margin-bottom: 0;
397 | }
398 |
399 | .markdown-body table {
400 | display: block;
401 | width: 100%;
402 | overflow: auto;
403 | word-break: normal;
404 | word-break: keep-all;
405 | }
406 |
407 | .markdown-body table th {
408 | font-weight: bold;
409 | }
410 |
411 | .markdown-body table th,
412 | .markdown-body table td {
413 | padding: 6px 13px;
414 | border: 1px solid #ddd;
415 | }
416 |
417 | .markdown-body table tr {
418 | background-color: #fff;
419 | border-top: 1px solid #ccc;
420 | }
421 |
422 | .markdown-body table tr:nth-child(2n) {
423 | background-color: #f8f8f8;
424 | }
425 |
426 | .markdown-body img {
427 | max-width: 100%;
428 | box-sizing: content-box;
429 | background-color: #fff;
430 | }
431 |
432 | .markdown-body code {
433 | padding: 0;
434 | padding-top: 0.2em;
435 | padding-bottom: 0.2em;
436 | margin: 0;
437 | font-size: 85%;
438 | background-color: rgba(0,0,0,0.04);
439 | border-radius: 3px;
440 | }
441 |
442 | .markdown-body code:before,
443 | .markdown-body code:after {
444 | letter-spacing: -0.2em;
445 | content: "\00a0";
446 | }
447 |
448 | .markdown-body pre>code {
449 | padding: 0;
450 | margin: 0;
451 | font-size: 100%;
452 | word-break: normal;
453 | white-space: pre;
454 | background: transparent;
455 | border: 0;
456 | }
457 |
458 | .markdown-body .highlight {
459 | margin-bottom: 16px;
460 | }
461 |
462 | .markdown-body .highlight pre,
463 | .markdown-body pre {
464 | padding: 16px;
465 | overflow: auto;
466 | font-size: 85%;
467 | line-height: 1.45;
468 | background-color: #f7f7f7;
469 | border-radius: 3px;
470 | }
471 |
472 | .markdown-body .highlight pre {
473 | margin-bottom: 0;
474 | word-break: normal;
475 | }
476 |
477 | .markdown-body pre {
478 | word-wrap: normal;
479 | }
480 |
481 | .markdown-body pre code {
482 | display: inline;
483 | max-width: initial;
484 | padding: 0;
485 | margin: 0;
486 | overflow: initial;
487 | line-height: inherit;
488 | word-wrap: normal;
489 | background-color: transparent;
490 | border: 0;
491 | }
492 |
493 | .markdown-body pre code:before,
494 | .markdown-body pre code:after {
495 | content: normal;
496 | }
497 |
498 | .markdown-body kbd {
499 | display: inline-block;
500 | padding: 3px 5px;
501 | font-size: 11px;
502 | line-height: 10px;
503 | color: #555;
504 | vertical-align: middle;
505 | background-color: #fcfcfc;
506 | border: solid 1px #ccc;
507 | border-bottom-color: #bbb;
508 | border-radius: 3px;
509 | box-shadow: inset 0 -1px 0 #bbb;
510 | }
511 |
512 | .markdown-body .pl-c {
513 | color: #969896;
514 | }
515 |
516 | .markdown-body .pl-c1,
517 | .markdown-body .pl-s .pl-v {
518 | color: #0086b3;
519 | }
520 |
521 | .markdown-body .pl-e,
522 | .markdown-body .pl-en {
523 | color: #795da3;
524 | }
525 |
526 | .markdown-body .pl-s .pl-s1,
527 | .markdown-body .pl-smi {
528 | color: #333;
529 | }
530 |
531 | .markdown-body .pl-ent {
532 | color: #63a35c;
533 | }
534 |
535 | .markdown-body .pl-k {
536 | color: #a71d5d;
537 | }
538 |
539 | .markdown-body .pl-pds,
540 | .markdown-body .pl-s,
541 | .markdown-body .pl-s .pl-pse .pl-s1,
542 | .markdown-body .pl-sr,
543 | .markdown-body .pl-sr .pl-cce,
544 | .markdown-body .pl-sr .pl-sra,
545 | .markdown-body .pl-sr .pl-sre {
546 | color: #183691;
547 | }
548 |
549 | .markdown-body .pl-v {
550 | color: #ed6a43;
551 | }
552 |
553 | .markdown-body .pl-id {
554 | color: #b52a1d;
555 | }
556 |
557 | .markdown-body .pl-ii {
558 | background-color: #b52a1d;
559 | color: #f8f8f8;
560 | }
561 |
562 | .markdown-body .pl-sr .pl-cce {
563 | color: #63a35c;
564 | font-weight: bold;
565 | }
566 |
567 | .markdown-body .pl-ml {
568 | color: #693a17;
569 | }
570 |
571 | .markdown-body .pl-mh,
572 | .markdown-body .pl-mh .pl-en,
573 | .markdown-body .pl-ms {
574 | color: #1d3e81;
575 | font-weight: bold;
576 | }
577 |
578 | .markdown-body .pl-mq {
579 | color: #008080;
580 | }
581 |
582 | .markdown-body .pl-mi {
583 | color: #333;
584 | font-style: italic;
585 | }
586 |
587 | .markdown-body .pl-mb {
588 | color: #333;
589 | font-weight: bold;
590 | }
591 |
592 | .markdown-body .pl-md {
593 | background-color: #ffecec;
594 | color: #bd2c00;
595 | }
596 |
597 | .markdown-body .pl-mi1 {
598 | background-color: #eaffea;
599 | color: #55a532;
600 | }
601 |
602 | .markdown-body .pl-mdr {
603 | color: #795da3;
604 | font-weight: bold;
605 | }
606 |
607 | .markdown-body .pl-mo {
608 | color: #1d3e81;
609 | }
610 |
611 | .markdown-body kbd {
612 | display: inline-block;
613 | padding: 3px 5px;
614 | font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
615 | line-height: 10px;
616 | color: #555;
617 | vertical-align: middle;
618 | background-color: #fcfcfc;
619 | border: solid 1px #ccc;
620 | border-bottom-color: #bbb;
621 | border-radius: 3px;
622 | box-shadow: inset 0 -1px 0 #bbb;
623 | }
624 |
625 | .markdown-body:before {
626 | display: table;
627 | content: "";
628 | }
629 |
630 | .markdown-body:after {
631 | display: table;
632 | clear: both;
633 | content: "";
634 | }
635 |
636 | .markdown-body .task-list-item {
637 | list-style-type: none;
638 | }
639 |
640 | .markdown-body .task-list-item+.task-list-item {
641 | margin-top: 3px;
642 | }
643 |
644 | .markdown-body .task-list-item input {
645 | margin: 0 0.35em 0.25em -1.6em;
646 | vertical-align: middle;
647 | }
648 |
649 | .markdown-body :checked+.radio-label {
650 | z-index: 1;
651 | position: relative;
652 | border-color: #4078c0;
653 | }
654 |
--------------------------------------------------------------------------------
/src/assets/css/reset.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | border: 0;
3 | font-family: "微软雅黑", "Helvetica", Arial, sans-serif;
4 | line-height: 1.5;
5 | margin: 0;
6 | padding: 0;
7 | }
8 |
9 | div, span, object, iframe, img, table, caption, thead, tbody,
10 | tfoot, tr, tr, td, article, aside, canvas, details, figure, hgroup, menu,
11 | nav, footer, header, section, summary, mark, audio, video {
12 | border: 0;
13 | margin: 0;
14 | padding: 0;
15 | }
16 |
17 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, address, cit, code,
18 | del, dfn, em, ins, q, samp, small, strong, sub, sup, b, i, hr, dl, dt, dd,
19 | ol, ul, li, fieldset, legend, label {
20 | border: 0;
21 | font-size: 100%;
22 | vertical-align: baseline;
23 | margin: 0;
24 | padding: 0;
25 | }
26 |
27 | article, aside, canvas, figure, figure img, figcaption, hgroup,
28 | footer, header, nav, section, audio, video {
29 | display: block;
30 | }
31 |
32 | table {
33 | border-collapse: separate;
34 | border-spacing: 0;
35 | caption, th, td {
36 | text-align: left;
37 | vertical-align: middle;
38 | }
39 | }
40 | li{
41 | list-style: none;
42 | }
43 | a{
44 | text-decoration: none;
45 | }
46 |
47 | a:active{
48 | tap-highlight-color:rgba(0, 0, 0, 0);
49 | }
50 |
51 | a img {
52 | border: 0;
53 | }
54 |
55 | :focus {
56 | outline: 0;
57 | }
58 |
59 | textarea{
60 | resize: none;
61 | appearance: none;
62 | }
63 | input{
64 | appearance: none;
65 | border: none;
66 | }
67 | select {
68 | appearance: none;
69 | background-color: #fff;
70 | }
71 |
72 | tap-highlight-color:rgba(0, 0, 0, 0);
--------------------------------------------------------------------------------
/src/components/backtotop.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
21 |
22 |
--------------------------------------------------------------------------------
/src/components/collect.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 用户收藏
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
![]()
15 |
16 |
17 |
{{collect.title}}
18 |
19 |
{{collect.author.loginname}}
20 |
21 |
22 |
最新回复 {{collect.create_at | getTime}}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
33 |
34 |
35 |
36 |
37 |
38 |
95 |
96 |
--------------------------------------------------------------------------------
/src/components/header.vue:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
23 |
64 |
65 |
--------------------------------------------------------------------------------
/src/components/loading.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/src/components/menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
53 |
54 |
--------------------------------------------------------------------------------
/src/components/reply.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
18 |
19 |
84 |
85 |
--------------------------------------------------------------------------------
/src/filters.js:
--------------------------------------------------------------------------------
1 | exports.getTabInfo = (tab, top, good, isClassName) => {
2 | let str = ''
3 | let className = ''
4 | if (top) {
5 | str = '置顶'
6 | className = 'top'
7 | } else if (good) {
8 | str = '精华'
9 | className = 'good'
10 | } else {
11 | switch (tab) {
12 | case 'share':
13 | str = '分享'
14 | className = 'share'
15 | break
16 | case 'ask':
17 | str = '问答'
18 | className = 'ask'
19 | break
20 | case 'job':
21 | str = '招聘'
22 | className = 'job'
23 | break
24 | default:
25 | str = '暂无'
26 | className = 'no-type'
27 | break
28 | }
29 | }
30 | return isClassName ? className : str
31 | }
32 |
33 | exports.getTime = (value) => {
34 | let index = value.indexOf('T')
35 | return value.substr(0, index)
36 | }
--------------------------------------------------------------------------------
/src/libs/alert.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | export default {
4 | install () {
5 | let time = null
6 | Vue.prototype.$alert = (msg, showTime = 2000) => {
7 | let exist = document.getElementsByClassName('alert-container')
8 | if (exist.length) {
9 | document.body.removeChild(exist[0])
10 | }
11 | let container = document.createElement('div')
12 | container.classList.add('alert-container')
13 | container.innerHTML = msg
14 | document.body.appendChild(container)
15 | clearTimeout(time)
16 | time = window.setTimeout(() => {
17 | document.body.removeChild(container)
18 | }, showTime)
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/src/libs/inertia.js:
--------------------------------------------------------------------------------
1 | var Inertia = function (ele, options) {
2 | var defaults = {
3 | edge: true
4 | }
5 | var params = {}
6 | options = options || {}
7 | for (var key in defaults) {
8 | if (typeof options[key] !== 'undefined') {
9 | params[key] = options[key]
10 | } else {
11 | params[key] = defaults[key]
12 | }
13 | }
14 | var data = {
15 | distanceX: 0,
16 | distanceY: 0
17 | }
18 | var checkbox = ele.querySelectorAll("input[type='checkbox']")[0]
19 | var win = window
20 | var winWidth = win.innerWidth
21 | var winHeight = win.innerHeight
22 | if (!ele) {
23 | return
24 | }
25 | var fnTranslate = function (x, y) {
26 | x = Math.round(1000 * x) / 1000
27 | y = Math.round(1000 * y) / 1000
28 | ele.style.webkitTransform = 'translate(' + [x + 'px', y + 'px'].join(',') + ')'
29 | ele.style.transform = 'translate3d(' + [x + 'px', y + 'px', 0].join(',') + ')'
30 | }
31 | var strStoreDistance = ''
32 | if (ele.id && win.localStorage && (strStoreDistance = localStorage['Inertia_' + ele.id])) {
33 | var arrStoreDistance = strStoreDistance.split(',')
34 | ele.distanceX = +arrStoreDistance[0]
35 | ele.distanceY = +arrStoreDistance[1]
36 | fnTranslate(ele.distanceX, ele.distanceY)
37 | }
38 | ele.style.visibility = 'visible'
39 | var initBound = ele.getBoundingClientRect()
40 | if (initBound.left < -0.5 * initBound.width ||
41 | initBound.top < -0.5 * initBound.height ||
42 | initBound.right > winWidth + 0.5 * initBound.width ||
43 | initBound.bottom > winHeight + 0.5 * initBound.height
44 | ) {
45 | ele.distanceX = 0
46 | ele.distanceY = 0
47 | fnTranslate(0, 0)
48 | }
49 | ele.addEventListener('touchstart', function (event) {
50 | var events = event.touches[0] || event
51 | data.posX = events.pageX
52 | data.posY = events.pageY
53 | data.touching = true
54 | data.flag = !checkbox.checked
55 | if (ele.distanceX) {
56 | data.distanceX = ele.distanceX
57 | }
58 | if (ele.distanceY) {
59 | data.distanceY = ele.distanceY
60 | }
61 | data.bound = ele.getBoundingClientRect()
62 | data.timerready = true
63 | })
64 | var easeOutBounce = function (t, b, c, d) {
65 | if ((t /= d) < (1 / 2.75)) {
66 | return c * (7.5625 * t * t) + b
67 | } else if (t < (2 / 2.75)) {
68 | return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b
69 | } else if (t < (2.5 / 2.75)) {
70 | return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b
71 | } else {
72 | return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b
73 | }
74 | }
75 | document.addEventListener('touchmove', function (event) {
76 | if (data.touching !== true || !data.flag) {
77 | return
78 | }
79 | if (data.timerready === true) {
80 | data.timerstart = +new Date()
81 | data.timerready = false
82 | }
83 | checkbox.classList.add('no-move')
84 | event.preventDefault()
85 | var events = event.touches[0] || event
86 | data.nowX = events.pageX
87 | data.nowY = events.pageY
88 | var distanceX = data.nowX - data.posX
89 | var distanceY = data.nowY - data.posY
90 | var absLeft = data.bound.left + distanceX
91 | var absTop = data.bound.top + distanceY
92 | var absRight = absLeft + data.bound.width
93 | var absBottom = absTop + data.bound.height
94 | if (absLeft < 0) {
95 | distanceX = distanceX - absLeft
96 | }
97 | if (absTop < 0) {
98 | distanceY = distanceY - absTop
99 | }
100 | if (absRight > winWidth) {
101 | distanceX = distanceX - (absRight - winWidth)
102 | }
103 | if (absBottom > winHeight) {
104 | distanceY = distanceY - (absBottom - winHeight)
105 | }
106 | var x = data.distanceX + distanceX
107 | var y = data.distanceY + distanceY
108 | fnTranslate(x, y)
109 | ele.distanceX = x
110 | ele.distanceY = y
111 | })
112 |
113 | document.addEventListener('touchend', function () {
114 | if (data.touching === false) {
115 | return
116 | }
117 | data.touching = false
118 | data.timerend = +new Date()
119 | if (!data.nowX || !data.nowY) {
120 | return
121 | }
122 | var distanceX = data.nowX - data.posX
123 | var distanceY = data.nowY - data.posY
124 | if (Math.abs(distanceX) < 5 && Math.abs(distanceY) < 5) {
125 | return
126 | }
127 | var distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY)
128 | var time = data.timerend - data.timerstart
129 | var speed = distance / time * 16.666
130 | var rate = Math.min(10, speed)
131 | data.inertiaing = true
132 | var reverseX = 1
133 | var reverseY = 1
134 | var step = function () {
135 | if (data.touching === true) {
136 | data.inertiaing = false
137 | return
138 | }
139 | speed = speed - speed / rate
140 | var moveX = reverseX * speed * distanceX / distance
141 | var moveY = reverseY * speed * distanceY / distance
142 | var bound = ele.getBoundingClientRect()
143 | if (moveX < 0 && bound.left + moveX < 0) {
144 | moveX = 0 - bound.left
145 | reverseX = reverseX * -1
146 | } else if (moveX > 0 && bound.right + moveX > winWidth) {
147 | moveX = winWidth - bound.right
148 | reverseX = reverseX * -1
149 | }
150 | if (moveY < 0 && bound.top + moveY < 0) {
151 | moveY = -1 * bound.top
152 | reverseY = -1 * reverseY
153 | } else if (moveY > 0 && bound.bottom + moveY > winHeight) {
154 | moveY = winHeight - bound.bottom
155 | reverseY = -1 * reverseY
156 | }
157 | var x = ele.distanceX + moveX
158 | var y = ele.distanceY + moveY
159 | fnTranslate(x, y)
160 | ele.distanceX = x
161 | ele.distanceY = y
162 | if (speed < 0.1) {
163 | speed = 0
164 | if (params.edge === false) {
165 | data.inertiaing = false
166 | checkbox.classList.remove('no-move')
167 | if (win.localStorage) {
168 | localStorage['Inertia_' + ele.id] = [x, y].join()
169 | }
170 | } else {
171 | edge()
172 | }
173 | } else {
174 | requestAnimationFrame(step)
175 | }
176 | }
177 | var edge = function () {
178 | var start = 0
179 | var during = 25
180 | var init = ele.distanceX
181 | var y = ele.distanceY
182 | var change = 0
183 | var bound = ele.getBoundingClientRect()
184 | if (bound.left + bound.width / 2 < winWidth / 2) {
185 | change = -1 * bound.left
186 | ele.classList.remove('edge-right')
187 | ele.classList.add('edge-left')
188 | } else {
189 | change = winWidth - bound.right
190 | ele.classList.remove('edge-left')
191 | ele.classList.add('edge-right')
192 | }
193 | var run = function () {
194 | if (data.touching === true) {
195 | data.inertiaing = false
196 | return
197 | }
198 | start++
199 | var x = easeOutBounce(start, init, change, during)
200 | fnTranslate(x, y)
201 | if (start < during) {
202 | requestAnimationFrame(run)
203 | } else {
204 | ele.distanceX = x
205 | ele.distanceY = y
206 | data.inertiaing = false
207 | checkbox.classList.remove('no-move')
208 | if (win.localStorage) {
209 | localStorage['Inertia_' + ele.id] = [x, y].join()
210 | }
211 | }
212 | }
213 | run()
214 | }
215 | step()
216 | })
217 | }
218 |
219 | export default Inertia
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue'
4 | import VueResource from 'vue-resource'
5 | import 'font-awesome/css/font-awesome.min.css'
6 | import './assets/css/common.css'
7 | import './assets/css/reset.css'
8 | import './assets/css/markdown.css'
9 | import Alert from './libs/alert'
10 | import router from './routers'
11 | import store from './vuex/state'
12 | import filters from './filters'
13 |
14 | Vue.use(VueResource)
15 | Vue.use(Alert)
16 |
17 | Object.keys(filters).forEach(k => {
18 | Vue.filter(k, filters[k])
19 | })
20 |
21 | if (window.localStorage.user) {
22 | store.commit('login', JSON.parse(window.localStorage.user))
23 | }
24 |
25 | router.beforeEach((to, from, next) => {
26 | if (to.matched.some(record => record.meta.requiresAuth)) {
27 | if (store.state.userInfo.userId) {
28 | next()
29 | } else {
30 | next({
31 | path: '/login',
32 | query: { redirect: to.fullPath }
33 | })
34 | }
35 | } else {
36 | next()
37 | }
38 | })
39 |
40 | /* eslint-disable no-new */
41 | new Vue({
42 | router,
43 | store
44 | }).$mount('#app')
45 |
--------------------------------------------------------------------------------
/src/routers.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueRouter from 'vue-router'
3 | import List from './views/list'
4 | import Login from './views/login'
5 | import Detail from './views/detail'
6 | import About from './views/about'
7 | import Add from './views/add'
8 | import User from './views/user'
9 | import Message from './views/message'
10 | import Start from './views/start'
11 |
12 | Vue.use(VueRouter)
13 |
14 | const routers = new VueRouter({
15 | mode: 'history',
16 | routes: [
17 | {name: 'start', path: '/', component: Start},
18 | {name: 'list', path: '/list', component: List},
19 | {name: 'login', path: '/login', component: Login},
20 | {name: 'detail', path: '/detail/:id', component: Detail},
21 | {name: 'about', path: '/about', component: About},
22 | {name: 'add', path: '/add', component: Add, meta: {requiresAuth: true}},
23 | {
24 | name: 'user',
25 | path: '/user/:username',
26 | component: User,
27 | meta: {requiresAuth: true}
28 | },
29 | {name: 'message', path: '/message/:accesstoken', component: Message, meta: {requiresAuth: true}}
30 | ]
31 | })
32 |
33 | export default routers
--------------------------------------------------------------------------------
/src/views/about.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
关于此webapp的相关介绍
6 |
7 | - 1:利用Cnode-API来获取webapp的数据
8 | - 2:代码已经提交到github上,很感谢能给个star
9 | - 3:webapp利用了vue的相关技术构建
10 | - 4:对Css3的一些常用使用场景进行了实现,例如:背景渐变,折角实现,还有悬浮菜单
11 | - 5:需要优化的东西:继续增加css或js的动画效果,对常见的tab切换改为手势操作
12 | - 6:本人QQ:1844209986,一起学习
13 |
14 |
15 |
16 |
17 |
18 |
19 |
29 |
30 |
--------------------------------------------------------------------------------
/src/views/add.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
20 |
{{opration}}
21 |
22 |
23 |
24 |
25 |
118 |
119 |
--------------------------------------------------------------------------------
/src/views/detail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
{{topic.title}}
7 |
8 |
9 |
10 |
11 |
12 |
{{topic.author.loginname}}
13 |
{{topic.tab | getTabInfo(topic.top, topic.good, false)}}
14 |
{{topic.create_at | getTime}}
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
43 |
44 |
评论一发
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
188 |
189 |
--------------------------------------------------------------------------------
/src/views/list.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | -
7 |
8 |
9 | {{item.tab | getTabInfo(item.top, item.good, false)}}
10 | {{item.title}}
11 |
12 |
13 |
![]()
14 |
15 |
16 | {{item.author.loginname}}
17 | {{item.create_at | getTime}}
18 |
19 |
20 | {{item.reply_count}}
21 | {{item.visit_count}}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
146 |
147 |
--------------------------------------------------------------------------------
/src/views/login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
66 |
67 |
--------------------------------------------------------------------------------
/src/views/message.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 未读消息
6 | 已读消息
7 |
8 |
9 |
10 |
11 | 标记为已读
12 |
13 |
14 | -
15 |
16 |
17 | {{message.topic.title}}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
{{message.author.loginname}}评论中@了你:
27 |
{{message.author.loginname}}参与了主题的评论:
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | 暂无数据
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 | {{message.topic.title}}
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
{{message.author.loginname}}评论中@了你:
54 |
{{message.author.loginname}}参与了主题的评论:
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | 暂无数据
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
119 |
120 |
--------------------------------------------------------------------------------
/src/views/start.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
18 |
19 |
34 |
35 |
--------------------------------------------------------------------------------
/src/views/user.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
![]()
7 |
8 |
积分: {{userInfo.score}}
9 |
10 |
11 | 用户名: {{userInfo.loginname}}
12 | 创建日期: {{ userInfo.create_at | getTime }}
13 |
14 |
15 |
16 |
17 | 发布的主题
18 | 参与的主题
19 |
20 |
21 |
22 |
23 |
24 | -
25 |
26 |
27 |
28 |
![]()
29 |
30 |
31 |
{{topic.title}}
32 |
33 | {{topic.author.loginname}}
34 |
35 |
36 |
37 |
38 |
39 | 最新回复 {{topic.last_reply_at | getTime}}
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | 暂无数据
49 |
50 |
51 |
52 |
53 | -
54 |
55 |
56 |
57 |
![]()
58 |
59 |
60 |
{{reply.title}}
61 |
62 | {{reply.author.loginname}}
63 | 最新回复:{{reply.last_reply_at | getTime}}
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | 暂无数据
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
155 |
156 |
--------------------------------------------------------------------------------
/src/vuex/state.js:
--------------------------------------------------------------------------------
1 | import Vuex from 'vuex'
2 | import Vue from 'vue'
3 |
4 | Vue.use(Vuex)
5 |
6 | const infoStore = new Vuex.Store({
7 | state: {
8 | userInfo: {}
9 | },
10 | mutations: {
11 | login (state, userinfo) {
12 | state.userInfo = userinfo
13 | }
14 | }
15 | })
16 |
17 | export default infoStore
--------------------------------------------------------------------------------
/static/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wocaatm/vue-cnode/5a6900fdb705d09345607ee0ba77aed1825b7f1c/static/.gitkeep
--------------------------------------------------------------------------------