├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── README.md ├── app ├── dist │ ├── 1-856466cc648a18903c62.chunk.js │ ├── 1-856466cc648a18903c62.chunk.js.map │ ├── 2-5eefedc12a6ccb7c4823.chunk.js │ ├── 2-5eefedc12a6ccb7c4823.chunk.js.map │ ├── css │ │ ├── app-921080b3e7a4930d6a9d.css │ │ └── app-921080b3e7a4930d6a9d.css.map │ ├── index.html │ └── js │ │ ├── app-921080b3e7a4930d6a9d.js │ │ ├── app-921080b3e7a4930d6a9d.js.map │ │ ├── lib-7f943a2a0e638403017e.js │ │ └── lib-7f943a2a0e638403017e.js.map └── src │ ├── README.md │ ├── actions │ ├── README.md │ ├── apis.js │ ├── auth.js │ ├── post.js │ └── posts.js │ ├── app.js │ ├── components │ ├── customEditor │ │ ├── base │ │ │ ├── index.js │ │ │ └── styles │ │ │ │ └── index.styl │ │ ├── index.js │ │ └── text │ │ │ ├── index.js │ │ │ └── styles │ │ │ └── index.styl │ ├── customPosts │ │ ├── base │ │ │ ├── index.js │ │ │ └── styles │ │ │ │ └── index.styl │ │ ├── image │ │ │ ├── index.js │ │ │ └── styles │ │ │ │ └── index.styl │ │ ├── index.js │ │ ├── music │ │ │ ├── index.js │ │ │ └── styles │ │ │ │ └── index.styl │ │ └── text │ │ │ ├── index.js │ │ │ └── styles │ │ │ └── index.styl │ ├── highlight │ │ └── index.js │ ├── me │ │ ├── index.js │ │ └── styles │ │ │ └── index.styl │ ├── modal │ │ ├── index.js │ │ └── styles │ │ │ └── index.styl │ ├── more │ │ ├── index.js │ │ └── styles │ │ │ └── index.styl │ ├── navbar │ │ ├── index.js │ │ ├── styles │ │ │ └── navbar.styl │ │ └── test │ │ │ └── index.js │ ├── post │ │ ├── index.js │ │ └── styles │ │ │ └── index.styl │ └── textarea │ │ ├── index.js │ │ └── styles │ │ └── index.styl │ ├── config │ └── client.js │ ├── constants │ ├── auth.js │ ├── post.js │ └── posts.js │ ├── containers │ ├── admin │ │ └── adminContainer │ │ │ └── index.js │ ├── indexContainer │ │ ├── index.js │ │ └── styles │ │ │ └── index.styl │ ├── loginContainer │ │ ├── index.js │ │ └── styles │ │ │ └── index.styl │ ├── postContainer │ │ ├── index.js │ │ └── styles │ │ │ └── index.styl │ └── rootContainer │ │ ├── index.js │ │ └── styles │ │ └── index.styl │ ├── index.template.html │ ├── middleware │ ├── createMiddle.js │ └── req.js │ ├── reducers │ ├── auth.js │ ├── index.js │ ├── post.js │ └── posts.js │ ├── routes.js │ ├── sockets │ └── index.js │ ├── styles │ └── app.styl │ └── utils.js ├── package.json ├── server ├── app.js ├── assets │ ├── favicon.ico │ ├── images │ │ ├── 03016_strossmayer_2880x1800.jpg │ │ ├── 03333_spinout_2880x1800.jpg │ │ ├── IMG_5053.jpg │ │ ├── bg.jpg │ │ └── me.png │ └── mp3 │ │ ├── Hillsong Young And Free - Wake.mp3 │ │ └── 金玟岐 - 腻味.mp3 ├── bin │ ├── _init.js │ ├── run.js │ ├── server.babel.js │ └── www.js ├── db │ ├── Post.js │ ├── User.js │ ├── connection.js │ ├── index.js │ └── schema │ │ ├── post.js │ │ └── user.js ├── routes │ ├── api.js │ └── index.js └── sockets │ └── index.js └── webpack ├── hot.js ├── webpack.dev.config.js └── webpack.prod.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0, 3 | "loose": "all", 4 | "optional": [ 5 | "bluebirdCoroutines", 6 | "runtime" 7 | ], 8 | "blacklist": [ 9 | "regenerator" 10 | ], 11 | "highlightCode": true, 12 | "env": { 13 | "development": { 14 | "plugins": [ 15 | "react-transform" 16 | ], 17 | "extra": { 18 | "react-transform": { 19 | "transforms": [ 20 | { 21 | "transform": "react-transform-catch-errors", 22 | "imports": [ 23 | "react", 24 | "redbox-react" 25 | ] 26 | }, 27 | { 28 | "transform": "react-transform-hmr", 29 | "imports": ["react"], 30 | "locals": ["module"] 31 | } 32 | ] 33 | } 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_style = space 3 | end_of_line = lf 4 | indent_size = 2 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | 8 | [*.md] 9 | max_line_length = 0 10 | trim_trailing_whitespace = false 11 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | webpack/* 2 | app/dist/* 3 | server/bin/www.js 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-airbnb", 3 | "env": { 4 | "browser": true, 5 | "node": true 6 | }, 7 | "ecmaFeatures": { 8 | "jsx": true, 9 | "modules": true 10 | }, 11 | "parser": "babel-eslint", 12 | "rules": { 13 | "react/jsx-uses-react": 2, 14 | "react/jsx-uses-vars": 2, 15 | "react/react-in-jsx-scope": 2, 16 | "react/prop-types": 0, 17 | "react/jsx-boolean-value": 0, 18 | "react/jsx-quotes": 0, 19 | "react/no-multi-comp": 0, 20 | "import/default": 0, 21 | "import/no-duplicates": 0, 22 | "import/named": 0, 23 | "import/namespace": 0, 24 | "import/no-unresolved": 0, 25 | "import/no-named-as-default": 2, 26 | "no-unused-vars": 1, 27 | "jsx-quotes": 2, 28 | "id-length": 0, 29 | "func-names": 0, 30 | "block-scoped-var": 0, 31 | "padded-blocks": 0, 32 | "comma-dangle": 0, 33 | "indent": [2, 2, { 34 | "SwitchCase": 1 35 | }], 36 | "no-console": 0, 37 | "no-alert": 0 38 | }, 39 | "plugins": [ 40 | "react", "import" 41 | ], 42 | "settings": { 43 | "import/parser": "babel-eslint", 44 | "import/resolve": { 45 | moduleDirectory: ["node_modules", "src"] 46 | } 47 | }, 48 | "globals": { 49 | "__DEVELOPMENT__": true, 50 | "__CLIENT__": true, 51 | "__SERVER__": true, 52 | "socket": true, 53 | "io": true 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | .tern-project 4 | *.log 5 | *.sublime-project 6 | *.sublime-workspace 7 | 8 | node_modules 9 | dump.rdb 10 | 11 | app/dist 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ddx 2 | 3 | 这是一个简单的日记web程序,记录,分享自己喜欢的文字,音乐,照片 4 | 总之还有很多问题,我会继续完善,也会尝试多增加点功能,主要是前端react,学习嘛,就是得折腾 5 | 6 | ## 主要使用到的技术 7 | - React.js 8 | - webpack 9 | - redux 10 | - react-router 11 | - Node.js 12 | - koa 13 | - Mongodb 14 | 15 | 还要感谢以下 16 | - css-modules 17 | - cssnext 18 | - postcss 19 | - babel 20 | - ..... 21 | (这个b装得可以) 22 | 23 | ## Demo 24 | [看这里](http://121.42.195.128/) 25 | 26 | ## 怎样启动? 27 | 1. 依赖mongodb,所以您需要先安装mongodb,并且启动,***建立一个数据库*** 28 | 2. 进入项目目录,执行```bash npm install // 也可以使用cnpm install 来安装 ``` 29 | 3. 😎进入下一步 30 | 31 | ### 开发模式 32 | - 服务端自动重启 33 | - 前端监控项目文件,有任何改动则会自动重启,无需浏览器自动F5。 34 | 35 | *** 36 | 37 | 服务端: 38 | ```bash 39 | npm run server-watch 40 | ``` 41 | 42 | 前端: 43 | ```bash 44 | npm run client-watch 45 | ``` 46 | 47 | ### 发布模式 48 | - 服务端使用pm2 or 其他等等启动 (我这里仅仅是很简单的启动而已) 49 | - 前端各种编译打包压缩代码。 50 | 51 | *** 52 | 53 | 服务端: 54 | ```bash 55 | npm run server-start 56 | ``` 57 | 前端: 58 | ```bash 59 | npm run client-build 60 | ``` 61 | 62 | ## 第一次运行 63 | 第一次数据库是没有东西的所有我们需要来点初始数据看看效果 64 | 新建两个命令行窗口,第一个窗口执行 65 | 如果你是想看 ***打包压缩*** 后的版本 66 | 先编译前端项目 67 | ```bash 68 | npm run client-build 69 | ``` 70 | 然后运行服务端 71 | ```base 72 | npm run server-start init 73 | ``` 74 | 这里init是执行一个js写点初始数据到数据库里,***以后不用加!!*** 75 | 打开浏览器localhost:3000 76 | ok 这就是你的第一次😀。 77 | 78 | 下面是你想进行开发了,自动重启啊什么的 79 | 把前面那些统统关掉 80 | ```bash 81 | npm run client-watch 82 | ``` 83 | 第二个窗口执行 84 | 如果不开发node端,可以用server-start 85 | ```bash 86 | npm run server-watch 87 | ``` 88 | 各方面细节还不是很完善,css-modules第一次使用,纯属乱用,导致现在写css比较难受。 89 | 本来html、css很渣,所有页面都是乱拼出来的。 90 | Chrome版本 48.0.2547.0 dev (64-bit) 91 | 92 | webpack打包后: 93 | - js有1.54MB 94 | - css有18.4KB 95 | 96 | gzip压缩后: 97 | - js有460.82KB 98 | - css有5.06KB 99 | 100 | ## TODOS 101 | - [x] 发表文章 102 | - [x] 浏览文章 103 | - [x] 评论文章 104 | - [x] 实时通知新评论,新文章 105 | - [] 上传图片 106 | - [] 上传音乐 107 | - [] 个人页面 108 | - [] 注册 109 | - [] ..... 110 | 111 | 最后,以上开发都在Mac上进行。 windows能try就try吧😂...... 112 | -------------------------------------------------------------------------------- /app/dist/2-5eefedc12a6ccb7c4823.chunk.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([2],{179:function(e,t){e.exports=function(e){return{aliases:["js"],keywords:{keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},contains:[{className:"pi",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE,{className:"subst",begin:"\\$\\{",end:"\\}"}]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"number",variants:[{begin:"\\b(0[bB][01]+)"},{begin:"\\b(0[oO][0-7]+)"},{begin:e.C_NUMBER_RE}],relevance:0},{begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.REGEXP_MODE,{begin:/\s*[);\]]/,relevance:0,subLanguage:"xml"}],relevance:0},{className:"function",beginKeywords:"function",end:/\{/,excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][0-9A-Za-z$_]*/}),{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]}],illegal:/\[|%/},{begin:/\$[(.]/},{begin:"\\."+e.IDENT_RE,relevance:0},{beginKeywords:"import",end:"[;$]",keywords:"import from as",contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends"},e.UNDERSCORE_TITLE_MODE]}],illegal:/#/}}},382:function(e,t,n){"use strict";var r=n(4)["default"];t.__esModule=!0;var s=n(484),i=r(s);n(450),i["default"].registerLanguage("markdown",n(486)),i["default"].registerLanguage("javascript",n(179)),i["default"].registerLanguage("js",n(179)),i["default"].registerLanguage("css",n(485)),t["default"]=i["default"],e.exports=t["default"]},450:451,484:function(e,t,n){!function(e){e(t)}(function(e){function t(e){return e.replace(/&/gm,"&").replace(//gm,">")}function n(e){return e.nodeName.toLowerCase()}function r(e,t){var n=e&&e.exec(t);return n&&0==n.index}function s(e){return/^(no-?highlight|plain|text)$/i.test(e)}function i(e){var t,n,r,i=e.className+" ";if(i+=e.parentNode?e.parentNode.className:"",n=/\blang(?:uage)?-([\w-]+)\b/i.exec(i))return x(n[1])?n[1]:"no-highlight";for(i=i.split(/\s+/),t=0,r=i.length;r>t;t++)if(x(i[t])||s(i[t]))return i[t]}function a(e,t){var n,r={};for(n in e)r[n]=e[n];if(t)for(n in t)r[n]=t[n];return r}function l(e){var t=[];return function r(e,s){for(var i=e.firstChild;i;i=i.nextSibling)3==i.nodeType?s+=i.nodeValue.length:1==i.nodeType&&(t.push({event:"start",offset:s,node:i}),s=r(i,s),n(i).match(/br|hr|img|input/)||t.push({event:"stop",offset:s,node:i}));return s}(e,0),t}function o(e,r,s){function i(){return e.length&&r.length?e[0].offset!=r[0].offset?e[0].offset"}function l(e){c+=""}function o(e){("start"==e.event?a:l)(e.node)}for(var u=0,c="",h=[];e.length||r.length;){var g=i();if(c+=t(s.substr(u,g[0].offset-u)),u=g[0].offset,g==e){h.reverse().forEach(l);do o(g.splice(0,1)[0]),g=i();while(g==e&&g.length&&g[0].offset==u);h.reverse().forEach(a)}else"start"==g[0].event?h.push(g[0].node):h.pop(),o(g.splice(0,1)[0])}return c+t(s.substr(u))}function u(e){function t(e){return e&&e.source||e}function n(n,r){return new RegExp(t(n),"m"+(e.case_insensitive?"i":"")+(r?"g":""))}function r(s,i){if(!s.compiled){if(s.compiled=!0,s.keywords=s.keywords||s.beginKeywords,s.keywords){var l={},o=function(t,n){e.case_insensitive&&(n=n.toLowerCase()),n.split(" ").forEach(function(e){var n=e.split("|");l[n[0]]=[t,n[1]?Number(n[1]):1]})};"string"==typeof s.keywords?o("keyword",s.keywords):Object.keys(s.keywords).forEach(function(e){o(e,s.keywords[e])}),s.keywords=l}s.lexemesRe=n(s.lexemes||/\b\w+\b/,!0),i&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")\\b"),s.begin||(s.begin=/\B|\b/),s.beginRe=n(s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(s.endRe=n(s.end)),s.terminator_end=t(s.end)||"",s.endsWithParent&&i.terminator_end&&(s.terminator_end+=(s.end?"|":"")+i.terminator_end)),s.illegal&&(s.illegalRe=n(s.illegal)),void 0===s.relevance&&(s.relevance=1),s.contains||(s.contains=[]);var u=[];s.contains.forEach(function(e){e.variants?e.variants.forEach(function(t){u.push(a(e,t))}):u.push("self"==e?s:e)}),s.contains=u,s.contains.forEach(function(e){r(e,s)}),s.starts&&r(s.starts,i);var c=s.contains.map(function(e){return e.beginKeywords?"\\.?("+e.begin+")\\.?":e.begin}).concat([s.terminator_end,s.illegal]).map(t).filter(Boolean);s.terminators=c.length?n(c.join("|"),!0):{exec:function(){return null}}}}r(e)}function c(e,n,s,i){function a(e,t){for(var n=0;n";return i+=e+'">',i+t+a}function d(){if(!N.keywords)return t(O);var e="",n=0;N.lexemesRe.lastIndex=0;for(var r=N.lexemesRe.exec(O);r;){e+=t(O.substr(n,r.index-n));var s=g(N,r);s?(M+=s[1],e+=p(s[0],t(r[0]))):e+=t(r[0]),n=N.lexemesRe.lastIndex,r=N.lexemesRe.exec(O)}return e+t(O.substr(n))}function f(){var e="string"==typeof N.subLanguage;if(e&&!v[N.subLanguage])return t(O);var n=e?c(N.subLanguage,O,!0,w[N.subLanguage]):h(O,N.subLanguage.length?N.subLanguage:void 0);return N.relevance>0&&(M+=n.relevance),e&&(w[N.subLanguage]=n.top),p(n.language,n.value,!1,!0)}function b(){return void 0!==N.subLanguage?f():d()}function m(e,n){var r=e.className?p(e.className,"",!0):"";e.returnBegin?(S+=r,O=""):e.excludeBegin?(S+=t(n)+r,O=""):(S+=r,O=n),N=Object.create(e,{parent:{value:N}})}function _(e,n){if(O+=e,void 0===n)return S+=b(),0;var r=a(n,N);if(r)return S+=b(),m(r,n),r.returnBegin?0:n.length;var s=l(N,n);if(s){var i=N;i.returnEnd||i.excludeEnd||(O+=n),S+=b();do N.className&&(S+=""),M+=N.relevance,N=N.parent;while(N!=s.parent);return i.excludeEnd&&(S+=t(n)),O="",s.starts&&m(s.starts,""),i.returnEnd?0:n.length}if(o(n,N))throw new Error('Illegal lexeme "'+n+'" for mode "'+(N.className||"")+'"');return O+=n,n.length||1}var E=x(e);if(!E)throw new Error('Unknown language: "'+e+'"');u(E);var y,N=i||E,w={},S="";for(y=N;y!=E;y=y.parent)y.className&&(S=p(y.className,"",!0)+S);var O="",M=0;try{for(var R,C,L=0;N.terminators.lastIndex=L,R=N.terminators.exec(n),R;)C=_(n.substr(L,R.index-L),R[0]),L=R.index+C;for(_(n.substr(L)),y=N;y.parent;y=y.parent)y.className&&(S+="");return{relevance:M,value:S,language:e,top:N}}catch(A){if(-1!=A.message.indexOf("Illegal"))return{relevance:0,value:t(n)};throw A}}function h(e,n){n=n||k.languages||Object.keys(v);var r={relevance:0,value:t(e)},s=r;return n.forEach(function(t){if(x(t)){var n=c(t,e,!1);n.language=t,n.relevance>s.relevance&&(s=n),n.relevance>r.relevance&&(s=r,r=n)}}),s.language&&(r.second_best=s),r}function g(e){return k.tabReplace&&(e=e.replace(/^((<[^>]+>|\t)+)/gm,function(e,t){return t.replace(/\t/g,k.tabReplace)})),k.useBR&&(e=e.replace(/\n/g,"
")),e}function p(e,t,n){var r=t?y[t]:n,s=[e.trim()];return e.match(/\bhljs\b/)||s.push("hljs"),-1===e.indexOf(r)&&s.push(r),s.join(" ").trim()}function d(e){var t=i(e);if(!s(t)){var n;k.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):n=e;var r=n.textContent,a=t?c(t,r,!0):h(r),u=l(n);if(u.length){var d=document.createElementNS("http://www.w3.org/1999/xhtml","div");d.innerHTML=a.value,a.value=o(u,l(d),r)}a.value=g(a.value),e.innerHTML=a.value,e.className=p(e.className,t,a.language),e.result={language:a.language,re:a.relevance},a.second_best&&(e.second_best={language:a.second_best.language,re:a.second_best.relevance})}}function f(e){k=a(k,e)}function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll("pre code");Array.prototype.forEach.call(e,d)}}function m(){addEventListener("DOMContentLoaded",b,!1),addEventListener("load",b,!1)}function _(t,n){var r=v[t]=n(e);r.aliases&&r.aliases.forEach(function(e){y[e]=t})}function E(){return Object.keys(v)}function x(e){return e=(e||"").toLowerCase(),v[e]||v[y[e]]}var k={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},v={},y={};return e.highlight=c,e.highlightAuto=h,e.fixMarkup=g,e.highlightBlock=d,e.configure=f,e.initHighlighting=b,e.initHighlightingOnLoad=m,e.registerLanguage=_,e.listLanguages=E,e.getLanguage=x,e.inherit=a,e.IDENT_RE="[a-zA-Z]\\w*",e.UNDERSCORE_IDENT_RE="[a-zA-Z_]\\w*",e.NUMBER_RE="\\b\\d+(\\.\\d+)?",e.C_NUMBER_RE="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BINARY_NUMBER_RE="\\b(0b[01]+)",e.RE_STARTERS_RE="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BACKSLASH_ESCAPE={begin:"\\\\[\\s\\S]",relevance:0},e.APOS_STRING_MODE={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},e.QUOTE_STRING_MODE={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},e.PHRASAL_WORDS_MODE={begin:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|like)\b/},e.COMMENT=function(t,n,r){var s=e.inherit({className:"comment",begin:t,end:n,contains:[]},r||{});return s.contains.push(e.PHRASAL_WORDS_MODE),s.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|XXX):",relevance:0}),s},e.C_LINE_COMMENT_MODE=e.COMMENT("//","$"),e.C_BLOCK_COMMENT_MODE=e.COMMENT("/\\*","\\*/"),e.HASH_COMMENT_MODE=e.COMMENT("#","$"),e.NUMBER_MODE={className:"number",begin:e.NUMBER_RE,relevance:0},e.C_NUMBER_MODE={className:"number",begin:e.C_NUMBER_RE,relevance:0},e.BINARY_NUMBER_MODE={className:"number",begin:e.BINARY_NUMBER_RE,relevance:0},e.CSS_NUMBER_MODE={className:"number",begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},e.REGEXP_MODE={className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,{begin:/\[/,end:/\]/,relevance:0,contains:[e.BACKSLASH_ESCAPE]}]},e.TITLE_MODE={className:"title",begin:e.IDENT_RE,relevance:0},e.UNDERSCORE_TITLE_MODE={className:"title",begin:e.UNDERSCORE_IDENT_RE,relevance:0},e})},485:function(e,t){e.exports=function(e){var t="[a-zA-Z-][a-zA-Z0-9_-]*",n={className:"function",begin:t+"\\(",returnBegin:!0,excludeEnd:!0,end:"\\("},r={className:"rule",begin:/[A-Z\_\.\-]+\s*:/,returnBegin:!0,end:";",endsWithParent:!0,contains:[{className:"attribute",begin:/\S/,end:":",excludeEnd:!0,starts:{className:"value",endsWithParent:!0,excludeEnd:!0,contains:[n,e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{className:"hexcolor",begin:"#[0-9A-Fa-f]+"},{className:"important",begin:"!important"}]}}]};return{case_insensitive:!0,illegal:/[=\/|'\$]/,contains:[e.C_BLOCK_COMMENT_MODE,{className:"id",begin:/\#[A-Za-z0-9_-]+/},{className:"class",begin:/\.[A-Za-z0-9_-]+/},{className:"attr_selector",begin:/\[/,end:/\]/,illegal:"$"},{className:"pseudo",begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"']+/},{className:"at_rule",begin:"@(font-face|page)",lexemes:"[a-z-]+",keywords:"font-face page"},{className:"at_rule",begin:"@",end:"[{;]",contains:[{className:"keyword",begin:/\S+/},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,contains:[n,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.CSS_NUMBER_MODE]}]},{className:"tag",begin:t,relevance:0},{className:"rules",begin:"{",end:"}",illegal:/\S/,contains:[e.C_BLOCK_COMMENT_MODE,r]}]}}},486:function(e,t){e.exports=function(e){return{aliases:["md","mkdown","mkd"],contains:[{className:"header",variants:[{begin:"^#{1,6}",end:"$"},{begin:"^.+?\\n[=-]{2,}$"}]},{begin:"<",end:">",subLanguage:"xml",relevance:0},{className:"bullet",begin:"^([*+-]|(\\d+\\.))\\s+"},{className:"strong",begin:"[*_]{2}.+?[*_]{2}"},{className:"emphasis",variants:[{begin:"\\*.+?\\*"},{begin:"_.+?_",relevance:0}]},{className:"blockquote",begin:"^>\\s+",end:"$"},{className:"code",variants:[{begin:"`.+?`"},{begin:"^( {4}| )",end:"$",relevance:0}]},{className:"horizontal_rule",begin:"^[-\\*]{3,}",end:"$"},{begin:"\\[.+?\\][\\(\\[].*?[\\)\\]]",returnBegin:!0,contains:[{className:"link_label",begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0,relevance:0},{className:"link_url",begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"link_reference",begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}],relevance:10},{begin:"^\\[.+\\]:",returnBegin:!0,contains:[{className:"link_reference",begin:"\\[",end:"\\]:",excludeBegin:!0,excludeEnd:!0,starts:{className:"link_url",end:"$"}}]}]}}},551:function(e,t,n){(function(t){(function(){function t(e){this.tokens=[],this.tokens.links={},this.options=e||c.defaults,this.rules=h.normal,this.options.gfm&&(this.options.tables?this.rules=h.tables:this.rules=h.gfm)}function n(e,t){if(this.options=t||c.defaults,this.links=e,this.rules=g.normal,this.renderer=this.options.renderer||new r,this.renderer.options=this.options,!this.links)throw new Error("Tokens array requires a `links` property.");this.options.gfm?this.options.breaks?this.rules=g.breaks:this.rules=g.gfm:this.options.pedantic&&(this.rules=g.pedantic)}function r(e){this.options=e||{}}function s(e){this.tokens=[],this.token=null,this.options=e||c.defaults,this.options.renderer=this.options.renderer||new r,this.renderer=this.options.renderer,this.renderer.options=this.options}function i(e,t){return e.replace(t?/&/g:/&(?!#?\w+;)/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function a(e){return e.replace(/&([#\w]+);/g,function(e,t){return t=t.toLowerCase(),"colon"===t?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}function l(e,t){return e=e.source,t=t||"",function n(r,s){return r?(s=s.source||s,s=s.replace(/(^|[^\[])\^/g,"$1"),e=e.replace(r,s),n):new RegExp(e,t)}}function o(){}function u(e){for(var t,n,r=1;rAn error occured:

"+i(g.message+"",!0)+"
";throw g}}var h={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:o,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:o,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:o,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};h.bullet=/(?:[*+-]|\d+\.)/,h.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,h.item=l(h.item,"gm")(/bull/g,h.bullet)(),h.list=l(h.list)(/bull/g,h.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+h.def.source+")")(),h.blockquote=l(h.blockquote)("def",h.def)(),h._tag="(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b",h.html=l(h.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,h._tag)(),h.paragraph=l(h.paragraph)("hr",h.hr)("heading",h.heading)("lheading",h.lheading)("blockquote",h.blockquote)("tag","<"+h._tag)("def",h.def)(),h.normal=u({},h),h.gfm=u({},h.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/}),h.gfm.paragraph=l(h.paragraph)("(?!","(?!"+h.gfm.fences.source.replace("\\1","\\2")+"|"+h.list.source.replace("\\1","\\3")+"|")(),h.tables=u({},h.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/}),t.rules=h,t.lex=function(e,n){var r=new t(n);return r.lex(e)},t.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},t.prototype.token=function(e,t,n){for(var r,s,i,a,l,o,u,c,g,e=e.replace(/^ +$/gm,"");e;)if((i=this.rules.newline.exec(e))&&(e=e.substring(i[0].length),i[0].length>1&&this.tokens.push({type:"space"})),i=this.rules.code.exec(e))e=e.substring(i[0].length),i=i[0].replace(/^ {4}/gm,""),this.tokens.push({type:"code",text:this.options.pedantic?i:i.replace(/\n+$/,"")});else if(i=this.rules.fences.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"code",lang:i[2],text:i[3]||""});else if(i=this.rules.heading.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"heading",depth:i[1].length,text:i[2]});else if(t&&(i=this.rules.nptable.exec(e))){for(e=e.substring(i[0].length),o={type:"table",header:i[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:i[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:i[3].replace(/\n$/,"").split("\n")},c=0;c ?/gm,""),this.token(i,t,!0),this.tokens.push({type:"blockquote_end"});else if(i=this.rules.list.exec(e)){for(e=e.substring(i[0].length),a=i[2],this.tokens.push({type:"list_start",ordered:a.length>1}),i=i[0].match(this.rules.item),r=!1,g=i.length,c=0;g>c;c++)o=i[c],u=o.length,o=o.replace(/^ *([*+-]|\d+\.) +/,""),~o.indexOf("\n ")&&(u-=o.length,o=this.options.pedantic?o.replace(/^ {1,4}/gm,""):o.replace(new RegExp("^ {1,"+u+"}","gm"),"")),this.options.smartLists&&c!==g-1&&(l=h.bullet.exec(i[c+1])[0],a===l||a.length>1&&l.length>1||(e=i.slice(c+1).join("\n")+e,c=g-1)),s=r||/\n\n(?!\s*$)/.test(o),c!==g-1&&(r="\n"===o.charAt(o.length-1),s||(s=r)),this.tokens.push({type:s?"loose_item_start":"list_item_start"}),this.token(o,!1,n),this.tokens.push({type:"list_item_end"});this.tokens.push({type:"list_end"})}else if(i=this.rules.html.exec(e))e=e.substring(i[0].length),this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:!this.options.sanitizer&&("pre"===i[1]||"script"===i[1]||"style"===i[1]),text:i[0]});else if(!n&&t&&(i=this.rules.def.exec(e)))e=e.substring(i[0].length),this.tokens.links[i[1].toLowerCase()]={href:i[2],title:i[3]};else if(t&&(i=this.rules.table.exec(e))){for(e=e.substring(i[0].length),o={type:"table",header:i[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:i[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:i[3].replace(/(?: *\| *)?\n$/,"").split("\n")},c=0;c])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:o,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:o,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/,g.link=l(g.link)("inside",g._inside)("href",g._href)(),g.reflink=l(g.reflink)("inside",g._inside)(),g.normal=u({},g),g.pedantic=u({},g.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/}),g.gfm=u({},g.normal,{escape:l(g.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:l(g.text)("]|","~]|")("|","|https?://|")()}),g.breaks=u({},g.gfm,{br:l(g.br)("{2,}","*")(),text:l(g.gfm.text)("{2,}","*")()}),n.rules=g,n.output=function(e,t,r){var s=new n(t,r);return s.output(e)},n.prototype.output=function(e){for(var t,n,r,s,a="";e;)if(s=this.rules.escape.exec(e))e=e.substring(s[0].length),a+=s[1];else if(s=this.rules.autolink.exec(e))e=e.substring(s[0].length),"@"===s[2]?(n=":"===s[1].charAt(6)?this.mangle(s[1].substring(7)):this.mangle(s[1]),r=this.mangle("mailto:")+n):(n=i(s[1]),r=n),a+=this.renderer.link(r,null,n);else if(this.inLink||!(s=this.rules.url.exec(e))){if(s=this.rules.tag.exec(e))!this.inLink&&/^/i.test(s[0])&&(this.inLink=!1),e=e.substring(s[0].length),a+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(s[0]):i(s[0]):s[0];else if(s=this.rules.link.exec(e))e=e.substring(s[0].length),this.inLink=!0,a+=this.outputLink(s,{href:s[2],title:s[3]}),this.inLink=!1;else if((s=this.rules.reflink.exec(e))||(s=this.rules.nolink.exec(e))){if(e=e.substring(s[0].length),t=(s[2]||s[1]).replace(/\s+/g," "),t=this.links[t.toLowerCase()],!t||!t.href){a+=s[0].charAt(0),e=s[0].substring(1)+e;continue}this.inLink=!0,a+=this.outputLink(s,t),this.inLink=!1}else if(s=this.rules.strong.exec(e))e=e.substring(s[0].length),a+=this.renderer.strong(this.output(s[2]||s[1]));else if(s=this.rules.em.exec(e))e=e.substring(s[0].length),a+=this.renderer.em(this.output(s[2]||s[1]));else if(s=this.rules.code.exec(e))e=e.substring(s[0].length),a+=this.renderer.codespan(i(s[2],!0));else if(s=this.rules.br.exec(e))e=e.substring(s[0].length),a+=this.renderer.br();else if(s=this.rules.del.exec(e))e=e.substring(s[0].length),a+=this.renderer.del(this.output(s[1]));else if(s=this.rules.text.exec(e))e=e.substring(s[0].length),a+=this.renderer.text(i(this.smartypants(s[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else e=e.substring(s[0].length),n=i(s[1]),r=n,a+=this.renderer.link(r,null,n);return a},n.prototype.outputLink=function(e,t){var n=i(t.href),r=t.title?i(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,i(e[1]))},n.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014\/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014\/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…"):e},n.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,s=0;r>s;s++)t=e.charCodeAt(s),Math.random()>.5&&(t="x"+t.toString(16)),n+="&#"+t+";";return n},r.prototype.code=function(e,t,n){if(this.options.highlight){var r=this.options.highlight(e,t);null!=r&&r!==e&&(n=!0,e=r)}return t?'
'+(n?e:i(e,!0))+"\n
\n":"
"+(n?e:i(e,!0))+"\n
"},r.prototype.blockquote=function(e){return"
\n"+e+"
\n"},r.prototype.html=function(e){return e},r.prototype.heading=function(e,t,n){return"'+e+"\n"},r.prototype.hr=function(){return this.options.xhtml?"
\n":"
\n"},r.prototype.list=function(e,t){var n=t?"ol":"ul";return"<"+n+">\n"+e+"\n"},r.prototype.listitem=function(e){return"
  • "+e+"
  • \n"},r.prototype.paragraph=function(e){return"

    "+e+"

    \n"},r.prototype.table=function(e,t){return"\n\n"+e+"\n\n"+t+"\n
    \n"},r.prototype.tablerow=function(e){return"\n"+e+"\n"},r.prototype.tablecell=function(e,t){var n=t.header?"th":"td",r=t.align?"<"+n+' style="text-align:'+t.align+'">':"<"+n+">";return r+e+"\n"},r.prototype.strong=function(e){return""+e+""},r.prototype.em=function(e){return""+e+""},r.prototype.codespan=function(e){return""+e+""},r.prototype.br=function(){return this.options.xhtml?"
    ":"
    "},r.prototype.del=function(e){return""+e+""},r.prototype.link=function(e,t,n){if(this.options.sanitize){try{var r=decodeURIComponent(a(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(s){return""}if(0===r.indexOf("javascript:")||0===r.indexOf("vbscript:"))return""}var i='
    "},r.prototype.image=function(e,t,n){var r=''+n+'":">"},r.prototype.text=function(e){return e},s.parse=function(e,t,n){var r=new s(t,n);return r.parse(e)},s.prototype.parse=function(e){this.inline=new n(e.links,this.options,this.renderer),this.tokens=e.reverse();for(var t="";this.next();)t+=this.tok();return t},s.prototype.next=function(){return this.token=this.tokens.pop()},s.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},s.prototype.parseText=function(){for(var e=this.token.text;"text"===this.peek().type;)e+="\n"+this.next().text;return this.inline.output(e)},s.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text);case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var e,t,n,r,s,i="",a="";for(n="",e=0;espan::selection,.cm-s-base16-light .CodeMirror-line>span>span::selection,.cm-s-base16-light div.CodeMirror-selected{background:#e0e0e0}.cm-s-base16-light .CodeMirror-line::-moz-selection,.cm-s-base16-light .CodeMirror-line>span::-moz-selection,.cm-s-base16-light .CodeMirror-line>span>span::-moz-selection{background:#e0e0e0}.cm-s-base16-light .CodeMirror-gutters{background:#f5f5f5;border-right:0}.cm-s-base16-light .CodeMirror-guttermarker{color:#ac4142}.cm-s-base16-light .CodeMirror-guttermarker-subtle,.cm-s-base16-light .CodeMirror-linenumber{color:#b0b0b0}.cm-s-base16-light .CodeMirror-cursor{border-left:1px solid #505050}.cm-s-base16-light span.cm-comment{color:#8f5536}.cm-s-base16-light span.cm-atom,.cm-s-base16-light span.cm-number{color:#aa759f}.cm-s-base16-light span.cm-attribute,.cm-s-base16-light span.cm-property{color:#90a959}.cm-s-base16-light span.cm-keyword{color:#ac4142}.cm-s-base16-light span.cm-string{color:#f4bf75}.cm-s-base16-light span.cm-variable{color:#90a959}.cm-s-base16-light span.cm-variable-2{color:#6a9fb5}.cm-s-base16-light span.cm-def{color:#d28445}.cm-s-base16-light span.cm-bracket{color:#202020}.cm-s-base16-light span.cm-tag{color:#ac4142}.cm-s-base16-light span.cm-link{color:#aa759f}.cm-s-base16-light span.cm-error{background:#ac4142;color:#505050}.cm-s-base16-light .CodeMirror-activeline-background{background:#dddcdc}.cm-s-base16-light .CodeMirror-matchingbracket{text-decoration:underline;color:#fff!important}.CodeMirror{font-family:monospace;height:300px;color:#000}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-ruler{border-left:1px solid #ccc;position:absolute}.cm-s-default .cm-header{color:blue}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta,.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-invalidchar,.cm-s-default .cm-error{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:none;position:relative}.CodeMirror-sizer{position:relative;border-right:30px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;margin-bottom:-30px;*zoom:1;*display:inline}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:none!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre{border-radius:0;border-width:0;background:transparent;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}.CodeMirror-code{outline:none}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}.CodeMirror-focused div.CodeMirror-cursors,div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background:#ffa;background:rgba(255,255,0,.4)}.CodeMirror span{*vertical-align:text-bottom}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:none}.CodeMirror{height:400px;padding:5px}.index__newPost___UGDJu{padding:5px}.index__newPost___UGDJu button{margin-left:5px}.index__box___sRfME{padding:13px;padding-left:20px}.index__posts___1fCCL{background:#fff;border-radius:3px}.index__panel___2Nuv2{width:100%;height:46px;line-height:46px}.index__header___r7cTO{font-size:13px;color:#343434}.index__header___r7cTO>div{padding-left:10px}.index__time___37rwE{padding-left:5px;border-bottom:1px solid #d0cfcf}.index__actions___3sQJl{float:right;padding-right:20px}.index__text___1iFXw{color:#000!important}.index__actions___3sQJl{font-size:12px}.index__out___yUXHd{color:#444;font-family:Georgia Neue,Hiragino Sans GB,Microsoft Yahei,WenQuanYi Micro Hei,serif;font-size:16px;line-height:1.5em}.index__out___yUXHd a{color:#0645ad;text-decoration:none}.index__out___yUXHd a:visited{color:#0b0080}.index__out___yUXHd a:hover{color:#06e}.index__out___yUXHd a:active{color:#faa700}.index__out___yUXHd a:focus{outline:thin dotted}.index__out___yUXHd a:active,.index__out___yUXHd a:hover{outline:0}.index__out___yUXHd p{margin:1em 0}.index__out___yUXHd img{max-width:100%}.index__out___yUXHd h1,.index__out___yUXHd h2,.index__out___yUXHd h3,.index__out___yUXHd h4,.index__out___yUXHd h5,.index__out___yUXHd h6{font-weight:400;color:#111;line-height:1em}.index__out___yUXHd h4,.index__out___yUXHd h5,.index__out___yUXHd h6{font-weight:700}.index__out___yUXHd h1{font-size:2.5em}.index__out___yUXHd h2{font-size:2em;border-bottom:1px solid silver;padding-bottom:5px}.index__out___yUXHd h3{font-size:1.5em}.index__out___yUXHd h4{font-size:1.2em}.index__out___yUXHd h5{font-size:1em}.index__out___yUXHd h6{font-size:.9em}.index__out___yUXHd blockquote{color:#666;margin:0;padding-left:3em;border-left:.5em solid #eee}.index__out___yUXHd hr{display:block;height:2px;border:0;border-top:1px solid #aaa;border-bottom:1px solid #eee;margin:1em 0;padding:0}.index__out___yUXHd code,.index__out___yUXHd pre{color:#000;font-family:Consolas,Liberation Mono,Menlo,Courier,monospace;font-size:.94em;border-radius:3px;background-color:#f8f8f8}.index__out___yUXHd pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word;padding:5px}.index__out___yUXHd pre code{border:0!important;background:transparent!important;line-height:1.3em}.index__out___yUXHd code{padding:0 3px;display:block}.index__out___yUXHd sub,.index__out___yUXHd sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}.index__out___yUXHd sup{top:-.5em}.index__out___yUXHd sub{bottom:-.25em}.index__out___yUXHd ol,.index__out___yUXHd ul{margin:1em 0;padding:0 0 0 2em}.index__out___yUXHd li p:last-child{margin:0}.index__out___yUXHd dd{margin:0 0 0 2em}.index__out___yUXHd img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle}.index__out___yUXHd table{border-collapse:collapse;border-spacing:0}.index__out___yUXHd td,.index__out___yUXHd th{vertical-align:top;padding:4px 10px;border:1px solid #bbb}.index__out___yUXHd tr:nth-child(even) td,.index__out___yUXHd tr:nth-child(even) th{background:#eee}.hljs{display:block;overflow-x:auto;padding:.5em;background:#002b36;color:#839496;-webkit-text-size-adjust:none}.diff .hljs-header,.hljs-comment,.hljs-doctype,.hljs-pi,.lisp .hljs-string{color:#586e75}.css .hljs-tag,.hljs-addition,.hljs-keyword,.hljs-request,.hljs-status,.hljs-winutils,.method,.nginx .hljs-title{color:#859900}.hljs-command,.hljs-doctag,.hljs-hexcolor,.hljs-link_url,.hljs-number,.hljs-regexp,.hljs-rule .hljs-value,.hljs-string,.hljs-tag .hljs-value,.tex .hljs-formula{color:#2aa198}.css .hljs-function,.hljs-built_in,.hljs-chunk,.hljs-decorator,.hljs-id,.hljs-identifier,.hljs-localvars,.hljs-name,.hljs-title,.vhdl .hljs-literal{color:#268bd2}.hljs-attribute,.hljs-class .hljs-title,.hljs-constant,.hljs-link_reference,.hljs-parent,.hljs-type,.hljs-variable,.lisp .hljs-body,.smalltalk .hljs-number{color:#b58900}.css .hljs-pseudo,.diff .hljs-change,.hljs-attr_selector,.hljs-cdata,.hljs-header,.hljs-pragma,.hljs-preprocessor,.hljs-preprocessor .hljs-keyword,.hljs-shebang,.hljs-special,.hljs-subst,.hljs-symbol,.hljs-symbol .hljs-string{color:#cb4b16}.hljs-deletion,.hljs-important{color:#dc322f}.hljs-link_label{color:#6c71c4}.tex .hljs-formula{background:#073642}.index__close___2U2gZ{height:50px;border-bottom:1px solid #96919e}.index__content___2JJNO{padding:10px}.navbar__navbar___1ZvrZ{color:#fff;height:70px;text-align:center;padding-left:200px;line-height:70px;border-bottom:1px solid #e1dbdb}.navbar__logo___2clf8{font-size:26px;font-family:cursive}.navbar__logo___2clf8>a{color:#fff;text-decoration:none}.navbar__left___3SBQ6{float:right;text-align:right;width:200px;font-size:14px}.navbar__left___3SBQ6>ul{list-style:none;margin:0;padding:0}.navbar__left___3SBQ6>ul>li{display:inline-block;float:left;text-align:center;height:100%;width:70px;text-decoration:none;color:#fff;border-bottom:1px solid transparent;box-sizing:border-box;transition:all .2s;cursor:pointer}.navbar__left___3SBQ6>ul>li>a{color:#fff}.navbar__left___3SBQ6>ul>li:hover{color:#b2b3b2;color:#bbb;border-bottom:1px solid #696464}.navbar__login___1sbIl{transition:all .2s}.navbar__create___2er15{display:block}.navbar__show___11gWe{visibility:hidden}.navbar__types___3Ub9Q{margin-left:135px}.navbar__type___1cxjL{position:relative;width:100px;height:100px;float:left;cursor:pointer;margin-right:30px;background:#02af84;border-radius:50%;text-align:center;color:#fff;line-height:100px}.navbar__text___f4Qkb{background:#f98888}.navbar__music___3lOy1{background:coral}.navbar__image___2IQOz{background:#02af84}.index__menu___2S5DL{font-size:22px;margin:50px 0;text-align:center;position:relative}.index__menus___3e4Na{transition:all .5s;position:absolute;top:-40px;left:188px}.index__menus___3e4Na>div>span{color:#fff;display:inline-block;width:80px;position:relative;font-size:17px;cursor:pointer;border-bottom:1px solid transparent}.index__menus___3e4Na>div>span:hover{color:#e6e6e6;border-bottom:1px solid #e6e6e6;transition:all .5s}.index__selectd___2RtAt{display:inline-block;border-radius:3px;background:#4dd0a5;height:39px;width:86px;color:#fff;line-height:37px;font-size:19px}.index__header___2gN8S{text-align:center;margin:20px 0}.index__me___eYYD5{width:114px;border-radius:50%}.index__name___1-Qqg{color:#fff;font-size:42px;margin-top:10px;margin-bottom:10px;font-family:cursive}.index__img___3BMI6{padding:13px;padding-left:20px}.index__cover___30U5N img{max-height:700px;max-width:100%;background-size:cover}.index__text___a5S8t{padding:13px;padding-left:20px}.index__musicBox___1QDyg{background:#fff}.index__music___3P_0Q{padding:13px 0 0 20px}.index__progress___mjSCT{background:#48aeea}.index__progressBar___3hUW3{height:70px;background:#51d5a1}.index__button___2zeqC{position:absolute;top:10px;left:10px}.index__play___pJNVu{float:left;border-radius:50%;border:0;height:50px;width:50px;color:#fff;background:#ff7070;box-shadow:0 1px 2px #706969}.index__text___2JWWj{color:#fff;position:relative;top:15px;left:18px;float:left;width:600px;padding-left:5px}.index__time___2aG4B{float:right}.index__post___9sg2n{margin-bottom:20px;margin-top:20px}.index__loginForm___3nvNY{width:100%;color:#fff;position:relative;margin-top:100px}.index__ctrl___HStLB{width:300px;margin:0 auto}.index__input___gBsPF{margin-top:15px}.index__input___gBsPF input[type=password],.index__input___gBsPF input[type=text]{padding:5px;width:290px;margin-top:3px;color:#444;height:29px;border-radius:2px;border:0}.index__loginBtn___IRjmd{margin-top:10px}.index__views___3F4M_{height:60px;font-size:13px;line-height:55px;color:#444}.index__views___3F4M_>ul{list-style:none;height:100%;padding:0;margin:0}.index__views___3F4M_>ul>li{display:inline-block;width:33.333333%;height:100%;transition:all .4s;border-bottom:1px solid transparent;text-align:center}.index__views___3F4M_>ul>li:hover{border-bottom:1px solid #adaaaa}.index__commentBox___2_-kZ{padding:10px;line-height:2}.index__commentBox___2_-kZ .comments{height:30px;margin:5px 0}.index__commentAction___3hSaK{height:45px;border-bottom:1px solid #d0d0d0}.index__commentPost___1G9hQ{float:right}.index__comment___3UwQV{background:#83c783;border-bottom:2px solid #527152}.index__commentArea___30Qtv{max-width:100%}.index__addCommentBox___27Nex{padding:10px;width:500px;height:130px} 2 | /*# sourceMappingURL=app-921080b3e7a4930d6a9d.css.map*/ -------------------------------------------------------------------------------- /app/dist/css/app-921080b3e7a4930d6a9d.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/app-921080b3e7a4930d6a9d.css","sourceRoot":""} -------------------------------------------------------------------------------- /app/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ddx 6 | 7 | 8 | 387 | 388 | 389 | 390 | 391 | 392 |
    393 |
    394 |
    395 |
    396 |
    397 |
    398 |
    399 |
    400 |
    401 |
    402 |
    403 |
    404 |
    405 |
    406 |
    407 |
    408 |
    409 |
    410 |
    411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | -------------------------------------------------------------------------------- /app/src/README.md: -------------------------------------------------------------------------------- 1 | # 前端开发注意事项 2 | 3 | 判断当前是否登录: 4 | redux@connect取得auth 5 | 使用this.props.auth.logind->boolean 6 | -------------------------------------------------------------------------------- /app/src/actions/README.md: -------------------------------------------------------------------------------- 1 | 自己写得中间件很low,写起来很麻烦还很复杂,建议用redux-thunk来控制吧 2 | -------------------------------------------------------------------------------- /app/src/actions/apis.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kee on 15/10/21. 3 | */ 4 | import axios from 'axios'; 5 | const host = __DEVELOPMENT__ ? '//localhost:3000/api' : '/api'; 6 | 7 | export default function apis({ url, method, ...others }) { 8 | return axios({ 9 | url: host + url, 10 | method: method, 11 | ...others 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /app/src/actions/auth.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kee on 15/9/28. 3 | */ 4 | import { 5 | AUTH_INIT, 6 | AUTH_INIT_SUCCESS, 7 | AUTH_INIT_FAIL, 8 | AUTH_LOGIN, 9 | AUTH_LOGIN_SUCCESS, 10 | AUTH_LOGIN_FAIL, 11 | } from '../constants/auth'; 12 | import ajax from './apis'; 13 | import tokenDecode from 'jwt-decode'; 14 | 15 | /** 16 | * @param {String} token 17 | * */ 18 | function decodeUser(token) { 19 | return tokenDecode(token); 20 | } 21 | 22 | export function init(callback) { 23 | return { 24 | types: [AUTH_INIT, AUTH_INIT_SUCCESS, AUTH_INIT_FAIL], 25 | promise: ()=>{ 26 | const token = localStorage.getItem('jwt'); 27 | if (!token) { 28 | return Promise.resolve({ 29 | data: { 30 | error: 'no login' 31 | } 32 | }); 33 | } 34 | return ajax({ 35 | url: '/valid', 36 | method: 'GET', 37 | headers: { 38 | 'x-access-token': 'Bearer ' + token 39 | } 40 | }); 41 | }, 42 | after: ()=>{ 43 | if (typeof callback === 'function') { 44 | callback(); 45 | } 46 | }, 47 | onData: result=>{ 48 | const { token, error, msg } = result.data; 49 | try { 50 | if (token) { 51 | return { 52 | msg, 53 | user: decodeUser(token).user 54 | }; 55 | } 56 | return { 57 | error 58 | }; 59 | } catch (e) { 60 | console.warn('token decode error'); 61 | return Promise.reject({ 62 | data: { 63 | error: 'token decode error' // 有服务器端返回的token,但解析出错,也就是有问题的token 64 | } 65 | }); 66 | } 67 | }, 68 | onError: error=>{ 69 | const err = error.data.error || '初始化失败 ——网络好像出现了问题'; 70 | // 验证不通过,没必要将错误显示到页面上 71 | return err; 72 | } 73 | }; 74 | } 75 | 76 | export function login(data, callback) { 77 | return { 78 | types: [AUTH_LOGIN, AUTH_LOGIN_SUCCESS, AUTH_LOGIN_FAIL], 79 | promise: ()=>{ 80 | return ajax({ 81 | url: '/login', 82 | method: 'POST', 83 | data: data 84 | }); 85 | }, 86 | after: ()=>{ 87 | if (typeof callback === 'function') { 88 | callback(); 89 | } 90 | }, 91 | onData: result=>{ 92 | const { token, msg } = result.data; 93 | const { user } = decodeUser(token); 94 | try { 95 | localStorage.setItem('jwt', token); 96 | return { 97 | msg, 98 | user: user 99 | }; 100 | } catch (e) { 101 | console.warn('token decode error'); 102 | return Promise.reject({ 103 | data: { 104 | error: '登陆失败, 请重新尝试' // token decode error 105 | } 106 | }); 107 | } 108 | }, 109 | onError: error=>{ 110 | const err = error.data.error || '登陆失败,请重新尝试 ——网络好像出现了问题'; 111 | return err; 112 | } 113 | }; 114 | } 115 | 116 | export function isLogin() { 117 | return (dispatch, getState)=> { 118 | const { auth } = getState(); 119 | if (auth.logind) { 120 | return true; 121 | } 122 | return false; 123 | }; 124 | } 125 | -------------------------------------------------------------------------------- /app/src/actions/post.js: -------------------------------------------------------------------------------- 1 | import { 2 | POST_INFO_LOAD, 3 | POST_INFO_LOAD_SUCCESS, 4 | POST_INFO_LOAD_FAIL, 5 | POST_COMMENT_CREATE_LOAD, 6 | POST_COMMENT_CREATE_SUCCESS, 7 | POST_COMMENT_CREATE_FAIL 8 | } from 'constants/post'; 9 | import ajax from './apis'; 10 | 11 | export function loadInfo(_id, callback) { 12 | return { 13 | types: [POST_INFO_LOAD, POST_INFO_LOAD_SUCCESS, POST_INFO_LOAD_FAIL], 14 | promise: ()=> ajax({ 15 | url: `/posts/${_id}`, 16 | method: 'GET' 17 | }), 18 | after: ()=>{ 19 | if (typeof callback === 'function') { 20 | callback(); 21 | } 22 | }, 23 | onData: result=>{ 24 | return result.data; 25 | }, 26 | onError: error=>{ 27 | const err = error.data.error || '文章信息加载失败 ——网络好像出现了问题'; 28 | return err; 29 | } 30 | }; 31 | } 32 | export function onNewComment(comment) { 33 | return { 34 | type: POST_COMMENT_CREATE_SUCCESS, 35 | result: comment 36 | }; 37 | } 38 | export function createComment(comment, callback) { 39 | return { 40 | types: [POST_COMMENT_CREATE_LOAD, POST_COMMENT_CREATE_SUCCESS, POST_COMMENT_CREATE_FAIL], 41 | promise: ()=>{ 42 | return ajax({ 43 | url: `/comments/${comment.post_id}`, 44 | method: 'POST', 45 | data: comment 46 | }); 47 | }, 48 | before: ()=>{ 49 | if (!comment.from) { 50 | return Promise.reject({ 51 | data: { 52 | error: '填写不完整,请重试' 53 | } 54 | }); 55 | } 56 | }, 57 | after: ()=>{ 58 | if (typeof callback === 'function') { 59 | callback(); 60 | } 61 | }, 62 | onData: ()=>{ 63 | // 返回提交的comment 64 | return comment; 65 | }, 66 | onError: error=>{ 67 | const err = error.data.error || '发表评论失败 ——网络好像出现了问题'; 68 | return err; 69 | } 70 | }; 71 | } 72 | -------------------------------------------------------------------------------- /app/src/actions/posts.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kee on 15/9/28. 3 | */ 4 | import { 5 | POSTS_LOAD, 6 | POSTS_LOAD_SUCCESS, 7 | POSTS_LOAD_FAIL, 8 | POSTS_CREATE, 9 | POSTS_CREATE_SUCCESS, 10 | POSTS_CREATE_FAIL 11 | } from '../constants/posts'; 12 | import ajax from './apis'; 13 | 14 | export function load(showType, callback) { 15 | return { 16 | types: [POSTS_LOAD, POSTS_LOAD_SUCCESS, POSTS_LOAD_FAIL], 17 | promise: ()=> { 18 | return ajax({ 19 | url: '/posts', 20 | method: 'GET', 21 | params: { 22 | showType: showType 23 | } 24 | }); 25 | }, 26 | after: ()=>{ 27 | if (typeof callback === 'function') { 28 | callback(); 29 | } 30 | }, 31 | onData: result=>{ 32 | const data = result.data; 33 | return data; 34 | }, 35 | onError: error=>{ 36 | const err = error.data.error || '加载文章失败 ——网络好像出现了问题'; 37 | return err; 38 | } 39 | }; 40 | } 41 | export function onNewPost(post) { 42 | return { 43 | type: POSTS_CREATE_SUCCESS, 44 | result: post 45 | }; 46 | } 47 | export function createPost(post, callback) { 48 | return { 49 | types: [POSTS_CREATE, POSTS_CREATE_SUCCESS, POSTS_CREATE_FAIL], 50 | promise: ()=> { 51 | return ajax({ 52 | url: `/posts`, 53 | method: 'POST', 54 | data: post 55 | }); 56 | }, 57 | after: (result)=>{ 58 | if (typeof callback === 'function') { 59 | callback(result); 60 | } 61 | }, 62 | onData: result=>{ 63 | return result.data; 64 | }, 65 | onError: error=>{ 66 | const err = error.data.error || '创建文章失败 ——网络好像出现了问题'; 67 | return err; 68 | } 69 | }; 70 | } 71 | -------------------------------------------------------------------------------- /app/src/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kee on 15/9/22. 3 | */ 4 | import 'normalize.css'; 5 | import 'styles/app.styl'; 6 | import React from 'react'; 7 | import { render } from 'react-dom'; 8 | import { createStore, combineReducers, applyMiddleware, compose, bindActionCreators } from 'redux'; 9 | import { Provider } from 'react-redux'; 10 | import { Router } from 'react-router'; 11 | import { createHistory } from 'history'; 12 | import * as authActions from './actions/auth'; 13 | import * as reducers from './reducers/index'; 14 | import createMiddle from './middleware/createMiddle'; 15 | import createRoutes from './routes'; 16 | 17 | const history = createHistory(); 18 | // const location = history.createLocation(window.location.pathname); 19 | const routes = createRoutes(); 20 | const middle = createMiddle(); 21 | 22 | const DEVTOOLS = false; 23 | let finalCreateStore; 24 | let reduxTools = null; 25 | 26 | if (DEVTOOLS) { 27 | const { devTools, persistState } = require('redux-devtools'); 28 | finalCreateStore = compose( 29 | applyMiddleware(...middle), 30 | devTools(), 31 | persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/)) 32 | )(createStore); 33 | } else { 34 | finalCreateStore = applyMiddleware(...middle)(createStore); 35 | } 36 | 37 | const reducer = combineReducers(reducers); 38 | const store = finalCreateStore(reducer); 39 | 40 | if (DEVTOOLS) { 41 | const { DevTools, DebugPanel, LogMonitor } = require('redux-devtools/lib/react'); 42 | // redux 调试工具 43 | reduxTools = ( 44 | 45 | 46 | 47 | ); 48 | } 49 | 50 | const init = bindActionCreators(authActions, store.dispatch).init; 51 | 52 | const provider = ( 53 | 54 |
    55 | 56 | {reduxTools} 57 |
    58 |
    59 | ); 60 | 61 | render(provider, document.getElementById('app')); 62 | 63 | // ajax验证用是否登录 64 | init(); 65 | -------------------------------------------------------------------------------- /app/src/components/customEditor/base/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kee on 15/11/06. 3 | */ 4 | import React, { Component, PropTypes as Types } from 'react'; 5 | import styles from './styles/index.styl'; 6 | 7 | export default class Defaults extends Component { 8 | static PropTypes = { 9 | onClose: Types.func.isRequired, 10 | header: Types.any 11 | } 12 | render() { 13 | return ( 14 |
    15 |
    16 | {this.props.header} 17 | 18 |
    19 |
    20 | {this.props.children} 21 |
    22 |
    23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/components/customEditor/base/styles/index.styl: -------------------------------------------------------------------------------- 1 | .header 2 | height:40px; 3 | padding: 10px 12px 5px 10px; 4 | border-top-left-radius: 3px; 5 | border-top-right-radius: 3px; 6 | background: #2A9AD8; 7 | color:white; 8 | 9 | .editorArea 10 | margin:0; 11 | 12 | .text 13 | line-height: 35px; 14 | -------------------------------------------------------------------------------- /app/src/components/customEditor/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kee on 15/10/29. 3 | */ 4 | import { getTypeComponent } from '../../utils'; 5 | import text from './text'; 6 | 7 | const components = { 8 | text 9 | }; 10 | 11 | export default getTypeComponent(components); 12 | -------------------------------------------------------------------------------- /app/src/components/customEditor/text/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kee on 15/9/28. 3 | */ 4 | import React, { Component, PropTypes as Types } from 'react'; 5 | import { connect } from 'react-redux'; 6 | import { bindActionCreators } from 'redux'; 7 | import Defaults from '../base'; 8 | import TextArea from '../../textarea'; 9 | import * as postsActions from '../../../actions/posts'; 10 | import * as authActions from '../../../actions/auth'; 11 | import styles from './styles/index.styl'; 12 | import { Markdown } from '../../customPosts/base'; 13 | 14 | @connect(state=>({ 15 | posts: state.posts, 16 | auth: state.auth, 17 | user: state.auth.user, 18 | config: state.auth.config 19 | }), dispatch=>({ 20 | postsActions: bindActionCreators(postsActions, dispatch), 21 | authActions: bindActionCreators(authActions, dispatch) 22 | })) 23 | class TextEditor extends Component { 24 | static propTypes = { 25 | posts: Types.object.isRequired, 26 | auth: Types.object.isRequired, 27 | user: Types.object, 28 | config: Types.object.isRequired 29 | } 30 | state = { 31 | isPreview: false, 32 | content: '' 33 | } 34 | onCloseEditor(e) { 35 | // TODO https://github.com/rackt/react-modal/pull/91 36 | if (this.state.content.trim().length > 0) { 37 | if (window.confirm('您有正在编辑的内容确定要关闭吗?')) { 38 | this.props.onClose(); 39 | return true; 40 | } 41 | // e.preventDefault() 42 | return false; 43 | } 44 | this.props.onClose(); 45 | } 46 | _preview() { 47 | this.setState({ 48 | isPreview: !this.state.isPreview 49 | }); 50 | } 51 | _post() { 52 | if (!this.props.authActions.isLogin()) { 53 | return alert('请先登录'); 54 | } 55 | const newPost = { 56 | content: this.state.content, 57 | type: 'text', 58 | author: { 59 | name: this.props.user.name, 60 | email: this.props.user.email 61 | }, 62 | create_time: Date.now() 63 | }; 64 | this.props.postsActions.createPost(newPost, (post)=>{ 65 | socket.emit('create:post', post); 66 | alert('创建成功'); 67 | }); 68 | } 69 | update(e) { 70 | this.setState({ 71 | content: e.getValue() 72 | }); 73 | } 74 | renderHeader() { 75 | return ( 76 | 77 | 创建你的新文章 78 | 79 | ); 80 | } 81 | render() { 82 | return ( 83 | 84 |
    85 | {this.state.isPreview ? ( 86 |
    87 | 88 |
    89 | ) : ( 90 |