├── public
├── img
│ ├── bg.jpg
│ ├── TK2.png
│ ├── bug.png
│ ├── talk.png
│ ├── about.png
│ ├── bug (1).png
│ ├── post n.png
│ ├── write.png
│ ├── about (1).png
│ ├── icon post.png
│ ├── talk (1).png
│ └── write (1).png
├── favicon.ico
├── src
│ ├── store
│ │ └── store.js
│ ├── component
│ │ ├── pleaseWait.js
│ │ ├── posts
│ │ │ ├── write.js
│ │ │ ├── post.js
│ │ │ ├── posts.js
│ │ │ ├── comment.js
│ │ │ ├── inputArea.js
│ │ │ └── article.js
│ │ ├── talk
│ │ │ └── talk.js
│ │ ├── nav.js
│ │ ├── sign
│ │ │ └── signInput.js
│ │ └── about
│ │ │ └── about.js
│ ├── reducer
│ │ ├── getMessages.js
│ │ ├── loginState.js
│ │ ├── index.js
│ │ └── getData.js
│ ├── route
│ │ ├── talk.js
│ │ ├── post.js
│ │ ├── about.js
│ │ ├── posts.js
│ │ ├── write.js
│ │ ├── update.js
│ │ ├── signInput.js
│ │ └── root.js
│ ├── js
│ │ ├── ajaxReturn.js
│ │ └── getCookie.js
│ ├── index.js
│ └── action
│ │ └── index.js
├── index.html
├── css
│ ├── index.css
│ └── about.css
└── build
│ ├── About.6577d.chunk.js
│ ├── Nav.f69a4.chunk.js
│ └── SignInput.d5958.chunk.js
├── config.js
├── routes
├── index.js
├── comments.js
├── sign.js
└── posts.js
├── models
├── users.js
├── messages.js
├── comments.js
└── posts.js
├── webpack.config.js
├── mongo
└── mongo.js
├── package.json
├── README.md
└── server.js
/public/img/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangkai123456/blog/HEAD/public/img/bg.jpg
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangkai123456/blog/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/img/TK2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangkai123456/blog/HEAD/public/img/TK2.png
--------------------------------------------------------------------------------
/public/img/bug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangkai123456/blog/HEAD/public/img/bug.png
--------------------------------------------------------------------------------
/public/img/talk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangkai123456/blog/HEAD/public/img/talk.png
--------------------------------------------------------------------------------
/public/img/about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangkai123456/blog/HEAD/public/img/about.png
--------------------------------------------------------------------------------
/public/img/bug (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangkai123456/blog/HEAD/public/img/bug (1).png
--------------------------------------------------------------------------------
/public/img/post n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangkai123456/blog/HEAD/public/img/post n.png
--------------------------------------------------------------------------------
/public/img/write.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangkai123456/blog/HEAD/public/img/write.png
--------------------------------------------------------------------------------
/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | url: "http://localhost/",
3 | talkURL: "http://localhost:3001/"
4 | }
--------------------------------------------------------------------------------
/public/img/about (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangkai123456/blog/HEAD/public/img/about (1).png
--------------------------------------------------------------------------------
/public/img/icon post.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangkai123456/blog/HEAD/public/img/icon post.png
--------------------------------------------------------------------------------
/public/img/talk (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangkai123456/blog/HEAD/public/img/talk (1).png
--------------------------------------------------------------------------------
/public/img/write (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangkai123456/blog/HEAD/public/img/write (1).png
--------------------------------------------------------------------------------
/public/src/store/store.js:
--------------------------------------------------------------------------------
1 | import {createStore} from 'redux'
2 | import reducer from "../reducer/index.js"
3 |
4 | export const store=createStore(reducer)
--------------------------------------------------------------------------------
/routes/index.js:
--------------------------------------------------------------------------------
1 | module.exports=function(app){
2 | app.use("/sign",require("./sign.js"))
3 | app.use("/posts",require("./posts.js"))
4 | app.use("/comments",require("./comments.js"))
5 | }
--------------------------------------------------------------------------------
/public/src/component/pleaseWait.js:
--------------------------------------------------------------------------------
1 | import React,{PropTypes} from 'react'
2 |
3 | export default class PlaseWait extends React.Component{
4 | render(){
5 | return (
6 |
敬请期待
7 | )
8 | }
9 | }
--------------------------------------------------------------------------------
/public/src/reducer/getMessages.js:
--------------------------------------------------------------------------------
1 | import {GET_MESSAGES} from '../action/index.js'
2 |
3 | export default function getMessages(state=[],action){
4 | switch (action.type){
5 | case GET_MESSAGES:
6 | return action.data;
7 | default:
8 | return state
9 | }
10 | }
--------------------------------------------------------------------------------
/public/src/reducer/loginState.js:
--------------------------------------------------------------------------------
1 | import {CHANGE_LOGIN_STATE} from '../action/index.js'
2 |
3 | export default function loginState(state=0,action){
4 | switch (action.type){
5 | case CHANGE_LOGIN_STATE:
6 | return action.userType;
7 | default:
8 | return state
9 | }
10 | }
--------------------------------------------------------------------------------
/models/users.js:
--------------------------------------------------------------------------------
1 | var User=require("../mongo/mongo.js").User
2 | /*为用户模型添加方法*/
3 | module.exports={
4 | create:function(user){
5 | return User.create(user).exec()
6 | },
7 | getUserByName:function(name){
8 | return User
9 | .findOne({name:name})
10 | .addCreatedAt()
11 | .exec()
12 | }
13 | }
--------------------------------------------------------------------------------
/public/src/route/talk.js:
--------------------------------------------------------------------------------
1 | // import Talk from '../component/talk/talk.js'
2 |
3 | const talk = {
4 | path: '/talk',
5 | getComponent(nextState, cb) {
6 | require.ensure([], (require) => {
7 | cb(null, require('../component/talk/talk.js').default)
8 | }, 'Talk')
9 | }
10 | }
11 |
12 | module.exports = talk
--------------------------------------------------------------------------------
/public/src/route/post.js:
--------------------------------------------------------------------------------
1 | // import Post from '../component/posts/post.js'
2 |
3 | const post = {
4 | path: '/post/:id',
5 | getComponent(nextState, cb) {
6 | require.ensure([], (require) => {
7 | cb(null, require('../component/posts/post.js').default)
8 | }, 'Post')
9 | }
10 | }
11 |
12 | module.exports = post
--------------------------------------------------------------------------------
/public/src/reducer/index.js:
--------------------------------------------------------------------------------
1 | import {combineReducers} from 'redux'
2 | import loginState from './loginState.js'
3 | import getData from './getData.js'
4 | import getMessages from './getMessages.js'
5 |
6 | const rootReducer=combineReducers({
7 | loginState,
8 | getData,
9 | getMessages,
10 | })
11 |
12 | export default rootReducer
--------------------------------------------------------------------------------
/public/src/route/about.js:
--------------------------------------------------------------------------------
1 | // import About from '../component/about/about.js'
2 |
3 | const about = {
4 | path: '/about',
5 | getComponent(nextState, cb) {
6 | require.ensure([], (require) => {
7 | cb(null, require('../component/about/about.js').default)
8 | }, 'About')
9 | }
10 | }
11 |
12 | module.exports = about
--------------------------------------------------------------------------------
/public/src/route/posts.js:
--------------------------------------------------------------------------------
1 | // import Posts from '../component/posts/posts.js'
2 |
3 | const posts = {
4 | path: '/main',
5 | getComponent(nextState, cb) {
6 | require.ensure([], (require) => {
7 | cb(null, require('../component/posts/posts.js').default)
8 | }, 'Posts')
9 | }
10 | }
11 |
12 | module.exports = posts
--------------------------------------------------------------------------------
/public/src/route/write.js:
--------------------------------------------------------------------------------
1 | // import Write from '../component/posts/write.js'
2 |
3 | const write = {
4 | path: '/write',
5 | getComponent(nextState, cb) {
6 | require.ensure([], (require) => {
7 | cb(null, require('../component/posts/write.js').default)
8 | }, 'Write')
9 | }
10 | }
11 |
12 | module.exports = write
--------------------------------------------------------------------------------
/public/src/route/update.js:
--------------------------------------------------------------------------------
1 | // import Write from '../component/posts/write.js'
2 |
3 | const update = {
4 | path: '/updatePost/:id',
5 | getComponent(nextState, cb) {
6 | require.ensure([], (require) => {
7 | cb(null, require('../component/posts/write.js').default)
8 | }, 'Update')
9 | }
10 | }
11 |
12 | module.exports = update
--------------------------------------------------------------------------------
/public/src/js/ajaxReturn.js:
--------------------------------------------------------------------------------
1 | import Alert from 'react-s-alert'
2 | /*ajax请求成功之后的弹窗操作*/
3 | export default function(res){
4 | if(res.state===300){
5 | Alert.warning(res.info,{
6 | effect:"slide",
7 | timeout:2000
8 | })
9 | }else if(res.state===400){
10 | Alert.error(res.info,{
11 | effect:"slide",
12 | timeout:2000
13 | })
14 | }
15 | }
--------------------------------------------------------------------------------
/public/src/route/signInput.js:
--------------------------------------------------------------------------------
1 | // import SignInput from '../component/sign/signInput.js'
2 |
3 | const signInput = {
4 | path: '/sign/:type',
5 | getComponent(nextState, cb) {
6 | require.ensure([], (require) => {
7 | cb(null, require('../component/sign/signInput.js').default)
8 | }, 'SignInput')
9 | }
10 | }
11 |
12 | module.exports = signInput
--------------------------------------------------------------------------------
/public/src/reducer/getData.js:
--------------------------------------------------------------------------------
1 | import {GET_DATA,GET_DATA_SUCCESS,GET_DATA_ERROR} from '../action/index.js'
2 |
3 | export default function getData(state=[],action){
4 | var newState=state;
5 | switch (action.type){
6 | case GET_DATA:
7 | return newState;
8 | case GET_DATA_SUCCESS:
9 | return action.data;
10 | case GET_DATA_ERROR:
11 | return action.error
12 | default :
13 | return state
14 | }
15 | }
--------------------------------------------------------------------------------
/public/src/js/getCookie.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 从cookie字符串的键值对中获取指定的值
3 | * @param {string} cookies 源字符串
4 | * @param {string} key 键
5 | * @return {string} value 值
6 | */
7 | function getCookie(cookies,key){
8 | var value="";
9 | if(cookies){
10 | if(cookies.match(key)){
11 | value=cookies.split(key+"=")[1].trim();
12 | /*如果key后面还有其他键,则用;分割*/
13 | if(value.match(";")){
14 | value=value.split(";")[0].trim();
15 | }
16 | }
17 | }
18 | return value
19 | }
20 |
21 | module.exports=getCookie
--------------------------------------------------------------------------------
/models/messages.js:
--------------------------------------------------------------------------------
1 | var Message=require("../mongo/mongo.js").Message
2 |
3 | Message.plugin("sliceTo50",{
4 | afterFind:function(messages){
5 | var len=messages.length;
6 | return messages.slice(len-30,len)
7 | }
8 | })
9 |
10 | module.exports={
11 | create:function(message){
12 | return Message
13 | .create(message)
14 | .exec()
15 | },
16 | getPartMessages:function(){
17 | return Message
18 | .find()
19 | .addCreatedAt()
20 | .sliceTo50()
21 | .exec()
22 | },
23 | getAllMessages:function(){
24 | return Message
25 | .find()
26 | .addCreatedAt()
27 | .exec()
28 | }
29 | }
--------------------------------------------------------------------------------
/public/src/component/posts/write.js:
--------------------------------------------------------------------------------
1 | import React,{PropTypes} from 'react'
2 | import InputArea from './inputArea.js'
3 | import {connect} from 'react-redux'
4 | import * as actions from '../../action/index.js'
5 |
6 | class Write extends React.Component{
7 | constructor(props) {
8 | super(props);
9 | }
10 | componentDidMount() {
11 | if(this.props.params.id){
12 | this.props.getData("posts/getRawPost/"+this.props.params.id)
13 | }
14 | }
15 | render(){
16 | return (
17 |
18 |
{this.props.params.id?"修改":"发表"}
19 |
20 |
21 | )
22 | }
23 | }
24 |
25 | Write.PropTyoes={
26 | data:PropTypes.array.isRequired,
27 | getData:PropTypes.func.isRequired
28 | }
29 |
30 | export default connect(
31 | (state)=>({data:state.getData}),
32 | actions
33 | )(Write)
--------------------------------------------------------------------------------
/models/comments.js:
--------------------------------------------------------------------------------
1 | var Comment=require("../mongo/mongo.js").Comment
2 |
3 | module.exports={
4 | create:function(comment){
5 | return Comment
6 | .create(comment)
7 | .exec()
8 | },
9 | /*通过用户名和评论id删除评论*/
10 | delCommentByIdAndName:function (commentId,name){
11 | return Comment
12 | .remove({name:name,_id:commentId})
13 | .exec()
14 | },
15 | /*通过评论id删除评论*/
16 | delCommentById:function(commentId){
17 | return Comment
18 | .remove({_id:commentId})
19 | .exec()
20 | },
21 | /*通过文章id删除所有评论*/
22 | delCommentsByPostId:function(postId){
23 | return Comment
24 | .remove({postId:postId})
25 | .exec()
26 | },
27 | /*通过文章id获取所有评论*/
28 | getComments:function(postId){
29 | return Comment
30 | .find({postId:postId})
31 | .sort({_id:-1})
32 | .addCreatedAt()
33 | .exec()
34 | },
35 | /*获取评论数*/
36 | getCommentsCount:function(postId){
37 | return Comment
38 | .count({postId:postId})
39 | .exec()
40 | }
41 | }
--------------------------------------------------------------------------------
/public/src/route/root.js:
--------------------------------------------------------------------------------
1 | // import Posts from './posts.js'
2 | // import Post from './post.js'
3 | // import Write from './write.js'
4 | // import SignInput from './signInput.js'
5 | // import About from './about.js'
6 | // import Talk from './talk.js'
7 |
8 | const rootRoute = {
9 | path: '/',
10 | indexRoute: {
11 | getComponent(nextState, cb) {
12 | require.ensure([], (require) => {
13 | cb(null, require("../component/posts/posts.js").default)
14 | }, 'Posts')
15 | },
16 | },
17 | getComponent(nextState, cb) {
18 | require.ensure([], (require) => {
19 | cb(null, require("../component/nav.js").default)
20 | }, 'Nav')
21 | },
22 | childRoutes: [
23 | require("./posts.js"),
24 | require("./post.js"),
25 | require("./write.js"),
26 | require("./signInput.js"),
27 | require("./about.js"),
28 | require("./talk.js"),
29 | require("./update.js")
30 | ]
31 | }
32 |
33 | export default rootRoute
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require("path")
3 | module.exports = {
4 | entry: ['babel-polyfill', './public/src/index.js'],
5 | output: {
6 | path: path.join(__dirname, '/public/build'),
7 | filename: 'index.js',
8 | publicPath: "/build/",
9 | chunkFilename: '[name].[chunkhash:5].chunk.js',
10 | },
11 | module: {
12 | loaders: [{
13 | test: /\.js$/,
14 | loader: 'babel-loader?presets[]=es2015&presets[]=react'
15 | }, {
16 | test: /\.css$/,
17 | loader: 'style-loader!css-loader'
18 | }, {
19 | test: /\.(png|jpg)$/,
20 | loader: 'url-loader?limit=8192'
21 | }]
22 | },
23 | externals: {
24 | 'react': 'React',
25 | 'react-dom': 'ReactDOM',
26 | 'redux': 'Redux',
27 | 'react-redux': 'ReactRedux',
28 | 'jquery': '$',
29 | 'socket': 'Socket',
30 | 'react-router': 'ReactRouter',
31 | },
32 | plugins: [
33 | new webpack.optimize.UglifyJsPlugin({
34 | compress: {
35 | warnings: false,
36 | },
37 | output: {
38 | comments: false,
39 | },
40 | }),
41 | new webpack.DefinePlugin({
42 | 'process.env': {
43 | 'NODE_ENV': JSON.stringify('production')
44 | }
45 | })
46 | ]
47 | }
--------------------------------------------------------------------------------
/public/src/component/posts/post.js:
--------------------------------------------------------------------------------
1 | import React,{PropTypes} from 'react'
2 | import InputArea from './inputArea.js'
3 | import Article from './article.js'
4 | import {connect} from 'react-redux'
5 | import * as actions from '../../action/index.js'
6 | import QueueAnim from 'rc-queue-anim'
7 | var Loader = require('halogen/ClipLoader');
8 |
9 | class Post extends React.Component{
10 | constructor(props) {
11 | super(props);
12 | }
13 | componentDidMount() {
14 | this.props.getData("posts/getOnePost/"+this.props.params.id,{flash:true})
15 | }
16 | render(){
17 | if(this.props.data.length){
18 | if(this.props.data[0].comments){
19 | return (
20 |
21 |
22 |
23 |
24 |
25 | )
26 | }else{
27 | return
28 | }
29 |
30 | }else{
31 | return
32 | }
33 | }
34 | }
35 |
36 | Post.PropTypes={
37 | data:PropTypes.array.isRequired,
38 | getData:PropTypes.func.isRequired
39 | }
40 |
41 | export default connect(
42 | (state)=>({data:state.getData}),
43 | actions
44 | )(Post)
--------------------------------------------------------------------------------
/public/src/component/posts/posts.js:
--------------------------------------------------------------------------------
1 | import React,{PropTypes} from 'react'
2 | import Article from './article.js'
3 | import $ from 'jquery'
4 | import {connect} from 'react-redux'
5 | import * as actions from '../../action/index.js'
6 | import QueueAnim from 'rc-queue-anim'
7 | var Loader = require('halogen/ClipLoader');
8 |
9 |
10 | class Posts extends React.Component{
11 | constructor(props) {
12 | super(props);
13 | }
14 | componentDidMount() {
15 | this.props.getData("posts/getAllPosts")
16 | }
17 | render(){
18 | /*posts文章页的数据长度大于1时,才显示内容,是因为在单文章页切换回来时,
19 | 加载数据会因为网速原因造成Article组件的内容闪烁。
20 | 所以为了妥协,设置了一个有瑕疵的判断,这个判断会造成只有一篇文章时不显示。*/
21 | if(this.props.Posts.length>1){
22 | return (
23 |
24 |
25 | {this.props.Posts.map(function(item,i){
26 | return
27 | })}
28 |
29 |
30 | )
31 | }else{
32 | return
33 | }
34 | }
35 | }
36 |
37 | Posts.PropTypes={
38 | Posts:PropTypes.array.isRequired,
39 | getData:PropTypes.func.isRequired
40 | }
41 |
42 | export default connect(
43 | state=>({Posts:state.getData}),
44 | actions
45 | )(Posts)
46 |
47 |
--------------------------------------------------------------------------------
/mongo/mongo.js:
--------------------------------------------------------------------------------
1 | var Mongolass=require("mongolass")
2 | var moment=require("moment")
3 | var objectIdToTimestamp=require("objectid-to-timestamp")
4 | /*连接数据库*/
5 | var mongolass=new Mongolass()
6 | mongolass.connect("mongodb://localhost:27017/tang")
7 | /*数据库插件,添加时间戳*/
8 | mongolass.plugin("addCreatedAt",{
9 | afterFind:function(results){
10 | results.forEach(function(item){
11 | item.created_at=moment(objectIdToTimestamp(item._id)).format("YYYY-MM-DD HH:mm");
12 | })
13 | return results
14 | },
15 | afterFindOne:function(result){
16 | if(result){
17 | result.created_at=moment(objectIdToTimestamp(result._id)).format("YYYY-MM-DD HH:mm");
18 | }
19 | return result
20 | }
21 | })
22 | /*用户模型*/
23 | exports.User=mongolass.model("User",{
24 | name:{type:"string"},
25 | password:{type:"string"},
26 | })
27 | exports.User.index({name:1},{unique:true}).exec()
28 | /*文章模型*/
29 | exports.Post=mongolass.model("Post",{
30 | title:{type:"string"},
31 | content:{type:"string"},
32 | good:[{type:"string"}],
33 | updateTime:{type:"string"},
34 | pv:{type:"number"}
35 | })
36 | /*评论模型*/
37 | exports.Comment=mongolass.model("Comment",{
38 | postId:{type:Mongolass.Types.ObjectId},
39 | name:{type:"string"},
40 | content:{type:"string"},
41 | })
42 | /*聊天信息模型*/
43 | exports.Message=mongolass.model("Message",{
44 | name:{type:"string"},
45 | content:{type:"string"}
46 | })
47 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 欢迎来到唐凯的博客
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/public/src/component/posts/comment.js:
--------------------------------------------------------------------------------
1 | import React,{PropTypes} from 'react'
2 | import {Link} from 'react-router'
3 | import {connect} from 'react-redux'
4 | import * as actions from '../../action/index.js'
5 | import {hashHistory} from 'react-router'
6 | import $ from 'jquery'
7 | import ajaxReturn from '../../js/ajaxReturn.js'
8 | import Alert from 'react-s-alert'
9 |
10 | var getCookie=require("../../js/getCookie.js")
11 |
12 | class Comment extends React.Component{
13 | constructor(props) {
14 | super(props);
15 | this.delComment=this.delComment.bind(this)
16 | }
17 | delComment(){
18 | this.props.getData("comments/delComment/"+this.props.postId+"/"+this.props.data._id,{loginState:this.props.loginState},"post",true)
19 | }
20 | render(){
21 | return (
22 |
23 | {this.props.data.name}: {this.props.data.content}
24 | {((getCookie(document.cookie,"name")===this.props.data.name)&&(this.props.loginState===1))||(this.props.loginState===2)?
25 | :""
26 | }
27 |
28 | )
29 | }
30 | }
31 |
32 | Comment.PropTypes={
33 | loginState:PropTypes.string.isRequired,
34 | data:PropTypes.object.isRequired,
35 | getData:PropTypes.func.isRequired
36 | }
37 |
38 | export default connect(
39 | (state)=>({loginState:state.loginState}),
40 | actions
41 | )(Comment)
--------------------------------------------------------------------------------
/public/src/index.js:
--------------------------------------------------------------------------------
1 | import React, {
2 | PropTypes
3 | } from 'react'
4 | import {
5 | render
6 | } from 'react-dom'
7 | import {
8 | Router,
9 | Route,
10 | hashHistory,
11 | IndexRoute
12 | } from 'react-router'
13 | // import Nav from './component/nav.js'
14 | // import Posts from './component/posts/posts.js'
15 | // import Post from './component/posts/post.js'
16 | // import Write from './component/posts/write.js'
17 | // import SignInput from './component/sign/signInput.js'
18 | import {
19 | Provider
20 | } from 'react-redux'
21 | import {
22 | createStore,
23 | applyMiddleware
24 | } from 'redux'
25 | import reducer from "./reducer/index.js"
26 | import thunk from 'redux-thunk'
27 | import PlaseWait from './component/pleaseWait.js'
28 | // import About from './component/about/about.js'
29 | // import Talk from './component/talk/talk.js'
30 | import routes from './route/root.js'
31 |
32 | const store = createStore(reducer, applyMiddleware(thunk))
33 | render(
34 |
35 |
36 | {/*
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | */}
46 |
47 | ,
48 | document.getElementById("main")
49 | )
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tang",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "webpack-dev-server --inline --content-base"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "babel-core": "^6.21.0",
14 | "babel-loader": "^6.2.10",
15 | "babel-polyfill": "^6.20.0",
16 | "babel-preset-es2015": "^6.18.0",
17 | "babel-preset-react": "^6.16.0",
18 | "body-parser": "^1.15.2",
19 | "compression": "^1.6.2",
20 | "cookie-parser": "^1.4.3",
21 | "css-loader": "^0.26.1",
22 | "express": "^4.14.0",
23 | "express-winston": "^2.1.0",
24 | "extract-text-webpack-plugin": "^1.0.1",
25 | "halogen": "^0.2.0",
26 | "jquery": "^3.1.1",
27 | "marked": "^0.3.6",
28 | "moment": "^2.17.1",
29 | "mongolass": "^2.4.1",
30 | "objectid-to-timestamp": "^1.3.0",
31 | "production": "0.0.2",
32 | "promise": "^7.1.1",
33 | "rc-queue-anim": "^0.13.0",
34 | "react": "^15.4.1",
35 | "react-dom": "^15.4.1",
36 | "react-redux": "^5.0.1",
37 | "react-router": "^3.0.0",
38 | "react-s-alert": "^1.2.2",
39 | "redux": "^3.6.0",
40 | "redux-thunk": "^2.1.0",
41 | "sha1": "^1.1.1",
42 | "socket.io": "^1.7.2",
43 | "style-loader": "^0.13.1",
44 | "webpack": "^1.14.0",
45 | "webpack-dev-server": "^1.16.2",
46 | "whatwg-fetch": "^2.0.1",
47 | "winston": "^2.3.0"
48 | },
49 | "devDependencies": {
50 | "compression-webpack-plugin": "^0.3.2"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 项目简介
2 | 使用react技术栈搭建的个人博客,手机端显示为单页面应用。
3 |
4 | [git](https://github.com/tangkai123456/blog)
5 |
6 | ## 功能
7 | - 首页列表,加载所有的文章,预览文章的部分内容,同时显示赞、评论、浏览的数量。
8 | - 文章发布。
9 | - 文章页,能查看详细文章内容,点赞数以及评论。
10 | - 文章的点赞功能。
11 | - 用户的登录与注册。
12 | - 用户能进行评论并管理自己的评论。
13 | - 聊天
14 |
15 | ## 运用的技术主要有
16 | - 采用`react`技术栈,所有状态均由`redux`进行管理,通过`react-router`来设置页面路由。
17 | - 使用`express`+`mongolass`进行后台数据的管理与操作。
18 | - 前后端分离,使用`jquery`的ajax携带cookie进行数据交互。
19 | - 使用`react-s-alert`插件弹出提示消息。
20 | - 使用`babel`转译、`webpack`打包代码。
21 | - 使用`Ant Motion`动画框架实现页面切换动画。
22 | - 响应式设计,在pc端、pad端、手机端体验良好。
23 | - 使用`socket.io`完成聊一聊功能,聊天信息可以实时更新
24 | - `react`等库文件引用自[BootCDN](http://www.bootcdn.cn/)。
25 | - react-router结合webpack设置按需加载。
26 |
27 | ## 预览
28 | [博客](http://tangkai123456.xyz/)
29 |
30 | ## 运行项目
31 | ```
32 | git clone https://github.com/tangkai123456/blog.git
33 | cd blog
34 | npm install
35 | node server
36 | ```
37 |
38 |
39 | ## 状态树
40 | 本项目使用redux管理状态,状态树为:
41 | ```
42 | state={
43 | loginState,//存储登录状态,管理员登录时为2,普通用户登陆时为1,未登录为0
44 | getData:[//首页时存储所有文章信息,单文章页存储一篇文章的信息,但两种情况数据类型都为数组,但文章页时数组长度为1
45 | {
46 | ...postContent,//文章信息
47 | comments:[]//文章的评论,首页时没有这个属性
48 | },
49 | ]
50 | }
51 | ```
52 |
53 | ## redux
54 | 异步ajax使用了thunk中间件,thunk允许action的创建函数返回一个函数,满足条件的情况下才dispatch。
55 |
56 | 使用三个action进行标记,获取文章相关数据的actionCreator形式为:
57 | 1.发起请求时dispatch("GET_DATA")
58 | 2.请求成功并且获取数据时dispatch("GET_DATA_SUCCESS")
59 | 3.请求失败时dispatch("GET_DATA_ERROR")
60 |
61 | 项目中所有ajax数据请求都在action中,也只有ajax可以调用dispatch改变状态树,在组件中不直接调用dispatch,数据流清晰
62 |
63 | ## mongoDB数据结构
64 | 用户:
65 | ```
66 | User={
67 | name:{type:"string"},
68 | password:{type:"string"},
69 | }
70 | ```
71 | 文章:
72 | ```
73 | Post={
74 | title:{type:"string"},
75 | content:{type:"string"},
76 | good:[{type:"string"}],//点赞数
77 | updateTime:{type:"string"},
78 | pv:{type:"number"}//浏览数
79 | }
80 | ```
81 | 评论:
82 | ```
83 | Comment={
84 | postId:{type:Mongolass.Types.ObjectId},
85 | name:{type:"string"},
86 | content:{type:"string"},
87 | }
88 | ```
89 |
90 | ## 待完善的功能
91 | - react-router过渡动画(已完成部分动画)
92 | - 加速首屏加载速度(已增加后台gzip压缩;所有库文件采用cdn加载)
93 | - `聊一聊`(已完成)
94 | - `关于`(暂时用个人简历代替)
95 | - bug记录本
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/routes/comments.js:
--------------------------------------------------------------------------------
1 | var express=require("express")
2 | var router=express.Router()
3 | var postModel=require("../models/posts.js")
4 | var commentModel=require("../models/comments.js")
5 | var getCookie=require("../public/src/js/getCookie.js")
6 | var Promise=require("promise")
7 | /*删除评论*/
8 | router.post("/delComment/:postId/:commentId",function(req,res,next){
9 | var commentId=req.params.commentId,
10 | postId=req.params.postId,
11 | name=getCookie(req.headers.cookie,"name"),
12 | loginState=req.body.loginState;
13 | if(!name&&!loginState){
14 | return res.end(JSON.stringify({state:300,info:"请登录"}))
15 | }
16 | if(loginState==="2"){
17 | Promise.all([
18 | commentModel.delCommentById(commentId),
19 | postModel.getPostById(postId),
20 | commentModel.getComments(postId),
21 | ])
22 | .then(function(result){
23 | var post=result[1];
24 | post.comments=result[2];
25 | res.send(JSON.stringify({state:200,info:"删除成功",data:[post]}))
26 | })
27 | .catch(function(e){
28 | res.send(JSON.stringify({state:400,info:"朋友,你的网络出现问题了"}))
29 | })
30 | }else if(loginState==="1"){
31 | Promise.all([
32 | commentModel.delCommentByIdAndName(commentId,name),
33 | postModel.getPostById(postId),
34 | commentModel.getComments(postId),
35 | ])
36 | .then(function(result){
37 | var post=result[1];
38 | post.comments=result[2];
39 | res.send(JSON.stringify({state:200,info:"删除成功",data:[post]}))
40 | })
41 | .catch(function(e){
42 | res.send(JSON.stringify({state:400,info:"朋友,你的网络出现问题了"}))
43 | })
44 | }
45 | })
46 | /*写评论*/
47 | router.post("/writeComment/:postId",function(req,res,next){
48 | var postId=req.params.postId,
49 | content=req.body.content,
50 | name=getCookie(req.headers.cookie,"name"),
51 | loginState=req.body.loginState;
52 | if(!name||!loginState){
53 | return res.end(JSON.stringify({state:300,info:"请登录"}))
54 | }
55 | var comment={
56 | name:name,
57 | content:content,
58 | postId:postId,
59 | }
60 | Promise.all([
61 | commentModel.create(comment),
62 | postModel.getPostById(postId),
63 | commentModel.getComments(postId),
64 | ])
65 | .then(function(result){
66 | var post=result[1];
67 | post.comments=result[2];
68 | res.send(JSON.stringify({state:200,info:"评论成功",data:[post]}))
69 | })
70 | .catch(function(e){
71 | res.send(JSON.stringify({state:400,info:"朋友,你的网络出现问题了"}))
72 | })
73 | })
74 |
75 | module.exports=router
--------------------------------------------------------------------------------
/models/posts.js:
--------------------------------------------------------------------------------
1 | var Post=require("../mongo/mongo.js").Post
2 | var marked=require("marked")
3 | var Promise=require("promise")
4 | var commentModel=require("./comments.js")
5 |
6 | /*内容加载时marked转化*/
7 | Post.plugin("contentToHtml",{
8 | afterFind:function(posts){
9 | return posts.map(function(post){
10 | post.content=marked(post.content);
11 | return post
12 | })
13 | },
14 | afterFindOne:function(post){
15 | if(post){
16 | post.content=marked(post.content);
17 | }
18 | return post
19 | }
20 | })
21 | /*截取首页加载文章的部分内容*/
22 | Post.plugin("toPartOfConent",{
23 | afterFind:function(posts){
24 | return posts.map(function(post){
25 | post.content=post.content.slice(0,400);
26 | return post
27 | })
28 | }
29 | })
30 | /*添加留言数*/
31 | Post.plugin("addCommentsCount",{
32 | afterFind:function(posts){
33 | return Promise.all(posts.map(function(post){
34 | return commentModel.getCommentsCount(post._id)
35 | .then(function(commentsCount){
36 | post.commentsCount=commentsCount;
37 | return post
38 | })
39 | }))
40 | },
41 | afterFindOne:function(post){
42 | if(post){
43 | return commentModel.getCommentsCount(post._id)
44 | .then(function(count){
45 | post.commentsCount=count;
46 | return post
47 | })
48 | }
49 | return post
50 | }
51 | })
52 |
53 | module.exports={
54 | /*创建文章*/
55 | create:function(post){
56 | return Post
57 | .create(post)
58 | .exec();
59 | },
60 | /*通过文章id获取文章*/
61 | getPostById:function(postId){
62 | return Post
63 | .findOne({_id:postId})
64 | .addCreatedAt()
65 | .addCommentsCount()
66 | .contentToHtml()
67 | .exec()
68 | },
69 | /*获取所有文章*/
70 | getAllPosts:function(){
71 | return Post
72 | .find()
73 | .sort({_id:-1})
74 | .addCreatedAt()
75 | .toPartOfConent()
76 | .addCommentsCount()
77 | .exec()
78 | },
79 | /*更新文章*/
80 | updatePostById:function(postId,data){
81 | return Post
82 | .update({_id:postId},{$set:data})
83 | .exec()
84 | },
85 | /*删除文章*/
86 | delPostById:function(postId){
87 | return Post
88 | .remove({_id:postId})
89 | .exec()
90 | /*删除文章同时删除评论*/
91 | .then(function(res){
92 | if(res.result.ok&&res.result.n>0){
93 | return commentModel.delCommentsByPostId(postId)
94 | }
95 | })
96 | },
97 | /*通过文章id给pv加1*/
98 | incPv:function incPv(postId){
99 | return Post
100 | .update({_id:postId},{$inc:{pv:1}})
101 | .exec()
102 | },
103 | getRawPostById:function(postId){
104 | return Post
105 | .findOne({_id:postId})
106 | .exec()
107 | }
108 | }
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | var express = require("express")
2 | var path = require("path")
3 | var routes = require("./routes/index.js")
4 | var bodyParser = require("body-parser")
5 | var cookieParser = require("cookie-parser")
6 | var compression = require("compression")
7 | var http = require("http").Server(app)
8 | var io = require("socket.io")(http)
9 | var messageModel = require("./models/messages.js")
10 | var Promise = require("promise")
11 | var getCookie = require("./public/src/js/getCookie.js")
12 |
13 | var app = express()
14 | app.use(compression())
15 | /*静态路径*/
16 | app.use(express.static(path.join(__dirname, "public")))
17 | /*设置允许跨域*/
18 | app.use(function(req, res, next) {
19 | res.setHeader("Access-Control-Allow-Origin", "http://localhost:8080");
20 | res.setHeader("Access-Control-Allow-Credentials", "true");
21 | next()
22 | })
23 | /*解析cookie*/
24 | app.use(cookieParser())
25 | /*解析req中的body*/
26 | app.use(bodyParser.json());
27 | app.use(bodyParser.urlencoded({
28 | extended: true
29 | }));
30 |
31 | routes(app);
32 | /*聊天室*/
33 | io.listen("3001").on('connection', function(socket) {
34 | /*连接成功是发送一次数据*/
35 | messageModel.getPartMessages()
36 | .then(function(result) {
37 | var messages = result;
38 | socket.emit('message', {
39 | state: 200,
40 | info: "获取成功",
41 | data: messages
42 | });
43 | })
44 | socket.on('message', function(msg) {
45 | if (msg.getAll) {
46 | messageModel.getAllMessages()
47 | .then(function(results) {
48 | socket.emit("message", {
49 | state: 200,
50 | info: "获取所有数据成功",
51 | data: results
52 | })
53 | })
54 | } else {
55 | if (!msg.name) {
56 | socket.on("message", {
57 | state: 300,
58 | info: "请登录"
59 | })
60 | }
61 | Promise.all([
62 | messageModel.create(msg),
63 | messageModel.getPartMessages()
64 | ])
65 | .then(function(results) {
66 | var messages = results[1];
67 | io.emit('message', {
68 | state: 200,
69 | info: "获取成功",
70 | data: messages,
71 | for: "everyone"
72 | });
73 | })
74 | }
75 | });
76 | });
77 |
78 | app.listen("80")
79 | console.log("open at 80")
--------------------------------------------------------------------------------
/public/src/component/talk/talk.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {
3 | connect
4 | } from 'react-redux'
5 | import * as actions from '../../action/index.js'
6 | import QueueAnim from 'rc-queue-anim'
7 | import Alert from 'react-s-alert'
8 | import config from '../../../../config.js'
9 | var getCookie = require("../../js/getCookie.js")
10 | var Loader = require('halogen/ClipLoader');
11 |
12 | class Talk extends React.Component {
13 | constructor(props) {
14 | super(props);
15 | this.sendMessage = this.sendMessage.bind(this)
16 | this.showAll = this.showAll.bind(this)
17 | }
18 | componentDidMount() {
19 | window.socket = io.connect(config.talkURL);
20 | socket.on("connect", function(msg) {
21 | console.log("connect success")
22 | });
23 | socket.on("message", function(msg) {
24 | this.props.getMessages(msg)
25 | }.bind(this))
26 | }
27 | componentDidUpdate(prevProps, prevState) {
28 | this.refs.messageBox.scrollTop = this.refs.messageBox.scrollHeight
29 | }
30 | sendMessage(e) {
31 | e.preventDefault();
32 | var name = getCookie(document.cookie, "name"),
33 | content = this.refs.input.value;
34 | if (!name) {
35 | Alert.warning("请登录", {
36 | effect: "slide",
37 | timeout: 2000
38 | })
39 | return
40 | }
41 | socket.send({
42 | name: getCookie(document.cookie, "name"),
43 | content: this.refs.input.value
44 | })
45 | this.refs.input.value = ""
46 | }
47 | showAll() {
48 | socket.send({
49 | getAll: true
50 | })
51 | }
52 | render() {
53 | var name = getCookie(document.cookie, "name")
54 | return (
55 |
56 |
57 |
显示全部
58 | {this.props.data?
59 | (
60 | this.props.data.map(function(item,i){
61 | return (
62 |
63 |
{item.name} {item.created_at}
64 |
{item.content}
65 |
66 | )
67 | }.bind(this))
68 | ):(
69 |
70 | )}
71 |
72 |
76 |
77 | )
78 | }
79 | }
80 |
81 | export default connect(
82 | state => ({
83 | loginState: state.loginState,
84 | data: state.getMessages
85 | }),
86 | actions
87 | )(Talk)
--------------------------------------------------------------------------------
/public/src/component/posts/inputArea.js:
--------------------------------------------------------------------------------
1 | import React,{PropTypes} from 'react'
2 | import $ from 'jquery'
3 | import {connect} from 'react-redux'
4 | import * as actions from '../../action/index.js'
5 | import {hashHistory} from 'react-router'
6 | import ajaxReturn from '../../js/ajaxReturn.js'
7 | import Alert from 'react-s-alert'
8 | import QueueAnim from 'rc-queue-anim'
9 |
10 | class InputArea extends React.Component{
11 | constructor(props) {
12 | super(props);
13 | this.submit=this.submit.bind(this);
14 | }
15 | submit(e){
16 | e.preventDefault();
17 | var url="";
18 | var data={};
19 | if(this.props.defaultData){//修改文章
20 | data={content:this.refs.content.value,title:this.refs.title.value}
21 | this.props.getData("posts/updatePost/"+this.props.defaultData._id,data,"post",true)
22 | hashHistory.push("/")
23 | }else{//发表文章
24 | if(this.props.isPost){
25 | data={content:this.refs.content.value,title:this.refs.title.value}
26 | this.props.getData("posts/writePost",data,"post",true)
27 | hashHistory.push("/")
28 | }else{//发表评论
29 | data={content:this.refs.content.value,loginState:this.props.loginState};
30 | this.props.getData("comments/writeComment/"+this.props.postId,data,"post",true)
31 | if(this.props.loginState){
32 | if(this.refs.title){
33 | this.refs.title.value=""
34 | }
35 | this.refs.content.value=""
36 | }
37 | }
38 | }
39 | }
40 | componentDidUpdate() {
41 | /*从修改页跳到发表页,会有数据留下来,所以要清空一次*/
42 | if(this.props.defaultData){
43 | this.refs.title.value=this.props.defaultData?this.props.defaultData.title:"";
44 | this.refs.content.value=this.props.defaultData?this.props.defaultData.content:"";
45 | }else{
46 | if(this.refs.title){
47 | this.refs.title.value=""
48 | }
49 | this.refs.content.value=""
50 | }
51 | }
52 | render(){
53 | return (
54 |
67 |
68 | )
69 | }
70 | }
71 |
72 | InputArea.PropTypes={
73 | loginState:PropTypes.string.isRequired,
74 | isPost:PropTypes.bool.isRequired,
75 | defaultValue:PropTypes.object.isRequired,
76 | getData:PropTypes.func.isRequired
77 | }
78 |
79 | export default connect(
80 | (state)=>({loginState:state.loginState}),
81 | actions
82 | )(InputArea)
83 |
--------------------------------------------------------------------------------
/public/src/component/nav.js:
--------------------------------------------------------------------------------
1 | import React,{PropTypes} from 'react'
2 | import {Link} from 'react-router'
3 | import $ from 'jquery'
4 | import * as actions from '../action/index.js'
5 | import {connect} from 'react-redux'
6 | import Alert from 'react-s-alert'
7 |
8 |
9 | import 'react-s-alert/dist/s-alert-default.css';
10 | import 'react-s-alert/dist/s-alert-css-effects/slide.css';
11 |
12 | var getCookie=require("../js/getCookie.js")
13 |
14 | class Nav extends React.Component{
15 | constructor(props) {
16 | super(props);
17 | this.signout=this.signout.bind(this)
18 | }
19 | signout(){
20 | this.props.signActions("sign/out",{},true,true)
21 | }
22 | componentDidMount() {
23 | this.props.signActions("sign/flashIn",{name:getCookie(document.cookie,"name"),password:getCookie(document.cookie,"password")},true)
24 | }
25 | render(){
26 | /*取出cookie中的name*/
27 | let name=getCookie(document.cookie,"name");
28 | return (
29 |
30 |
61 | {this.props.loginState?(
62 |
63 | 欢迎 {name}
64 |
65 |
66 | ):(
67 |
68 |
69 |
70 |
71 | )}
72 |
73 |
74 | {this.props.children}
75 |
76 |
77 |
80 |
81 | )
82 | }
83 | }
84 |
85 | Nav.PropTypes={
86 | loginState:PropTypes.string.isRequired,
87 | signActions:PropTypes.func.isRequired
88 | }
89 |
90 | export default connect(
91 | state=>({loginState:state.loginState}),
92 | actions
93 | )(Nav)
--------------------------------------------------------------------------------
/public/src/component/sign/signInput.js:
--------------------------------------------------------------------------------
1 | import React,{PropTypes} from 'react'
2 | import $ from 'jquery'
3 | import {hashHistory} from 'react-router'
4 | import {connect} from 'react-redux'
5 | import * as actions from '../../action/index.js'
6 | import QueueAnim from 'rc-queue-anim'
7 | var getCookie=require("../../js/getCookie.js")
8 | /**
9 | * 登录与注册的表单,通过判断属性返回不同的结构和进行不同的js
10 | */
11 | class SignInput extends React.Component{
12 | constructor(props) {
13 | super(props);
14 | this.submit=this.submit.bind(this);
15 | this.checkPwd=this.checkPwd.bind(this)
16 | }
17 | submit(e){
18 | /*提交表单,阻止默认事件,判断是注册还是登录拼接不一样的url和data*/
19 | e.preventDefault();
20 | var url="",
21 | data={
22 | name:this.refs.username.value,
23 | password:this.refs.password.value,
24 | };
25 | /*注册事件*/
26 | if(this.props.params.type=="signup"){
27 |
28 | url="sign/up";
29 | /*登录事件*/
30 | }else if(this.props.params.type=="signin"){
31 | url="sign/in";
32 | }
33 | if(url&&data){
34 | this.props.signActions(url,data,false,true)
35 | }
36 | }
37 | checkPwd(){
38 | if(this.props.params.type=="signup"){
39 | var password=this.refs.password,
40 | rePassword=this.refs.rePassword,
41 | submit=this.refs.submit;
42 | if(password.value==rePassword.value){
43 | submit.disabled=false
44 | rePassword.style.background=""
45 | }else{
46 | rePassword.style.background="red"
47 | submit.disabled=true
48 | }
49 | }else{
50 | this.refs.submit.disabled=false
51 | }
52 | }
53 | render(){
54 | return (
55 |
77 | )
78 | }
79 | }
80 |
81 | SignInput.PropTypes={
82 | loginState:PropTypes.string.isRequired,
83 | signActions:PropTypes.func.isRequired
84 | }
85 |
86 | export default connect(
87 | state=>({loginState:state.loginState}),
88 | actions
89 | )(SignInput)
--------------------------------------------------------------------------------
/routes/sign.js:
--------------------------------------------------------------------------------
1 | var express=require("express")
2 | var router=express.Router()
3 | var sha1=require("sha1")
4 | var cookieParser=require("cookie-parser")
5 |
6 | var userModel=require("../models/users.js")
7 | /*使用cookie登录*/
8 | router.post("/flashIn",function(req,res,next){
9 | var name=req.body.name
10 | userModel.getUserByName(name)
11 | .then(function(result){
12 | if(result){
13 | /*如果用户存在,且密码与输入的密码相同,则成功*/
14 | if(result.password===req.body.password){
15 | var loginState=1;
16 | if(name==="tangkai"){
17 | loginState=2
18 | }
19 | res.cookie("name",name,{maxAge:1000*60*60*24*10});
20 | res.cookie("password",result.password,{maxAge:1000*60*60*24*10});
21 | return res.send(JSON.stringify({state:200,info:"登录成功",loginState:loginState}))
22 | }
23 | }
24 | return res.send(JSON.stringify({state:300,info:"用户名或密码错误",loginState:0}))
25 | })
26 | })
27 | /*登录*/
28 | router.post("/in",function(req,res,next){
29 | var name=req.body.name
30 | userModel.getUserByName(name)
31 | .then(function(result){
32 | if(result){
33 | /*如果用户存在,且密码与输入的密码相同,则成功*/
34 | if(result.password===sha1(req.body.password)){
35 | res.cookie("name",name,{maxAge:1000*60*60*24*10});
36 | res.cookie("password",result.password,{maxAge:1000*60*60*24*10});
37 | var loginState=1;
38 | if(name==="tangkai"){
39 | loginState=2
40 | }
41 | return res.send(JSON.stringify({state:200,info:"登录成功",loginState:loginState}))
42 | }
43 | }
44 | return res.send(JSON.stringify({state:300,info:"用户名或密码错误",loginState:0}))
45 | })
46 | })
47 | /*注册用户*/
48 | router.post("/up",function(req,res,next){
49 | var name=req.body.name,
50 | password=req.body.password;
51 | /*注册信息验证*/
52 | if(name.match(" ")||name.match(" ")){
53 | return res.end(JSON.stringify({state:300,info:"用户名或密码中存在空格"}))
54 | }else if(name.length<6||name.length>20||password.length<6||password.length>20){
55 | return res.end(JSON.stringify({state:300,info:"用户名或密码长度不正确"}))
56 | }
57 | /*查询用户名是否重复*/
58 | userModel.getUserByName(name)
59 | .then(function(result){
60 | /*如果已经存在则返回repeat*/
61 | if(result){
62 | return res.end(JSON.stringify({state:300,info:"用户名已存在"}))
63 | }else{
64 | var user={
65 | name:req.body.name,
66 | password:sha1(req.body.password),
67 | }
68 | userModel.create(user)
69 | .then(function(result){
70 | res.cookie("name",name,{maxAge:1000*60*60*24*10});
71 | res.cookie("password",result.password,{maxAge:1000*60*60*24*10});
72 | res.send(JSON.stringify({state:200,info:"登录成功",loginState:1}))
73 | })
74 | .catch(function(e){
75 | res.send(JSON.stringify({state:400,info:"朋友,你的网络出现问题了"}))
76 | })
77 | }
78 | })
79 | .catch(function(e){
80 | res.send(JSON.stringify({state:400,info:"朋友,你的网络出现问题了"}))
81 | })
82 | })
83 | /*退出*/
84 | router.post("/out",function(req,res,next){
85 | res.clearCookie("name")
86 | res.clearCookie("password")
87 | res.send(JSON.stringify({state:200,info:"退出成功",loginState:0}))
88 | })
89 |
90 | module.exports=router
--------------------------------------------------------------------------------
/public/src/component/posts/article.js:
--------------------------------------------------------------------------------
1 | import React,{PropTypes} from 'react'
2 | import {Link} from 'react-router'
3 | import Comment from './comment.js'
4 | import InputArea from './inputArea.js'
5 | import {connect} from 'react-redux'
6 | import * as actions from '../../action/index.js'
7 | import $ from 'jquery'
8 | import {hashHistory} from 'react-router'
9 | import Alert from 'react-s-alert'
10 | import ajaxReturn from '../../js/ajaxReturn.js'
11 | import QueueAnim from 'rc-queue-anim'
12 |
13 | class Article extends React.Component{
14 | constructor(props) {
15 | super(props);
16 | this.del=this.del.bind(this)
17 | this.clickGood=this.clickGood.bind(this)
18 | }
19 | del(){
20 | this.props.getData("posts/deletePost/"+this.props.data._id,{},"post",true)
21 | hashHistory.push("/")
22 | }
23 | clickGood(){
24 | this.props.getData("posts/clickGood/"+this.props.data._id+"/"+(this.props.data.comments?0:1),{},"post",true)
25 | }
26 | render(){
27 | return (
28 |
29 |
30 |
31 | {/*{this.props.data.title}*/}
32 |
33 |
34 | 发布时间:{this.props.data.created_at} 最后一次修改:{this.props.data.updateTime}
35 | {this.props.loginState==2?(
36 |
37 |
38 | ):""
39 | }
40 |
41 | {
42 | this.props.data.comments?(
43 |
44 |
45 |
46 |
47 | {/*后台返回的是html字符串,需要用dangerouslySetInnerHTML放置到div中,防止script注入*/}
48 |
49 |
50 |
51 | ):(
52 |
53 |
54 | {/*后台返回的是html字符串,需要用dangerouslySetInnerHTML放置到div中,防止script注入*/}
55 |
56 |
57 | )
58 | }
59 |
60 | {this.props.data.good.length}赞 {this.props.data.commentsCount}评论 {this.props.data.pv}浏览
61 |
62 | {this.props.children}
63 |
64 | {this.props.data.comments?this.props.data.comments.map(function(item,i){
65 | return
66 | }.bind(this)):""}
67 |
68 |
69 | )
70 | }
71 | }
72 |
73 | Article.PropTypes={
74 | loginState:PropTypes.string.isRequired,
75 | data:PropTypes.object.isRequired,
76 | getData:PropTypes.func.isRequired
77 | }
78 |
79 | export default connect(
80 | (state)=>({loginState:state.loginState}),
81 | actions
82 | )(Article)
--------------------------------------------------------------------------------
/routes/posts.js:
--------------------------------------------------------------------------------
1 | var express=require("express")
2 | var router=express.Router()
3 | var postModel=require("../models/posts.js")
4 | var commentModel=require("../models/comments.js")
5 | var getCookie=require("../public/src/js/getCookie.js")
6 | var moment=require("moment")
7 | var Promise=require("promise")
8 | /*获取所有文章*/
9 | router.get("/getAllPosts",function(req,res,next){
10 | postModel.getAllPosts()
11 | .then(function(posts){
12 | res.send(JSON.stringify({state:200,info:"get all posts success",data:posts}))
13 | })
14 | .catch(function(e){
15 | res.send(JSON.stringify({state:400,info:"朋友,你的网络出现问题了"}))
16 | })
17 | })
18 | /*写文章*/
19 | router.post("/writePost",function(req,res){
20 | if(getCookie(req.headers.cookie,"name")!=="tangkai"){
21 | return res.send(JSON.stringify({state:300,info:"你没有权限"}))
22 | }
23 | var title=req.body.title;
24 | var content=req.body.content;
25 | var post={
26 | title:title,
27 | content:content,
28 | good:[],
29 | updateTime:moment().format("YYYY-MM-DD HH:mm"),
30 | pv:0
31 | }
32 | postModel.create(post)
33 | .then(function(result){
34 | res.send(JSON.stringify({state:200,info:"发表成功"}))
35 | })
36 | .catch(function(){
37 | res.send(JSON.stringify({state:400,info:"朋友,你的网络出现问题了"}))
38 | })
39 | })
40 | /*获取一篇文章*/
41 | router.get("/getOnePost/:postId",function(req,res,next){
42 | var postId=req.params.postId;
43 | Promise.all([
44 | postModel.getPostById(postId),
45 | commentModel.getComments(postId),
46 | req.query.flash?postModel.incPv(postId):null
47 | ])
48 | .then(function(results){
49 | var post=results[0];
50 | post.comments=results[1];
51 | res.send(JSON.stringify({state:200,info:"get post success",data:[post]}))
52 | })
53 | .catch(function(){
54 | res.send(JSON.stringify({state:400,info:"朋友,你的网络出现问题了"}))
55 | })
56 | })
57 | /*获取一篇文章的初始内容,没有marked的*/
58 | router.get("/getRawPost/:postId",function(req,res,next){
59 | var postId=req.params.postId;
60 | postModel.getRawPostById(postId)
61 | .then(function(result){
62 | res.send(JSON.stringify({state:200,info:"get post success",data:[result]}))
63 | })
64 | .catch(function(){
65 | res.send(JSON.stringify({state:400,info:"朋友,你的网络出现问题了"}))
66 | })
67 | })
68 | /*删除一篇文章*/
69 | router.post("/deletePost/:postId",function(req,res,next){
70 | if(getCookie(req.headers.cookie,"name")!=="tangkai"){
71 | return res.send(JSON.stringify({state:300,info:"你没有权限"}))
72 | }
73 | var postId=req.params.postId;
74 | Promise.all([
75 | postModel.delPostById(postId),
76 | postModel.getAllPosts()
77 | ])
78 | .then(function(results){
79 | var posts=results[1];
80 | res.send(JSON.stringify({state:200,info:"删除成功",data:posts}))
81 | })
82 | .catch(function(){
83 | res.send(JSON.stringify({state:400,info:"朋友,你的网络出现问题了"}))
84 | })
85 | })
86 | /*修改文章*/
87 | router.post("/updatePost/:postId",function(req,res,next){
88 | if(getCookie(req.headers.cookie,"name")!=="tangkai"){
89 | return res.send(JSON.stringify({state:300,info:"你没有权限"}))
90 | }
91 | var postId=req.params.postId,
92 | title=req.body.title,
93 | content=req.body.content;
94 | var post={
95 | title:title,
96 | content:content,
97 | updateTime:moment().format("YYYY-MM-DD HH:mm")
98 | }
99 | postModel.updatePostById(postId,post)
100 | .then(function(){
101 | res.end(JSON.stringify({state:200,info:"修改成功"}))
102 | })
103 | .catch(function(){
104 | res.send(JSON.stringify({state:400,info:"朋友,你的网络出现问题了"}))
105 | })
106 | })
107 | /*点赞,isMain参数表示是不是主页传来的请求,因为要根据不同的页面返回不同的数据*/
108 | router.post("/clickGood/:postId/:isMain",function(req,res,next){
109 | var name=getCookie(req.headers.cookie,"name"),
110 | postId=req.params.postId;
111 | if(!name){
112 | return res.end(JSON.stringify({state:300,info:"请登录"}))
113 | }
114 | postModel.getRawPostById(postId)
115 | .then(function(result){
116 | var isFound=false;
117 | for(var i=0,len=result.good.length;i {
22 | dispatch({
23 | type: CHANGE_LOGIN_STATE,
24 | userType: 0
25 | })
26 | // fetch("http://localhost/"+url,{
27 | // method:"post",
28 | // body:JSON.stringify(data),
29 | // headers: {
30 | // 'Accept': 'application/json, text/javascript, */*; q=0.01',
31 | // 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
32 | // },
33 | // credentials: 'credentials',
34 | // })
35 | // .then(function(response) {
36 | // return response.json()
37 | // }).then(function(json) {
38 | // console.log('parsed json', json)
39 | // }).catch(function(ex) {
40 | // console.log('parsing failed', ex)
41 | // })
42 | $.ajax({
43 | url: config.url + url,
44 | type: "post",
45 | data: data,
46 | dataType: "json",
47 | xhrFields: {
48 | withCredentials: true
49 | },
50 | success: function(res) {
51 | if (res.loginState) {
52 | dispatch({
53 | type: CHANGE_LOGIN_STATE,
54 | userType: res.loginState
55 | })
56 | if (!noFlash) {
57 | hashHistory.push("/");
58 | }
59 | }
60 | if (showAlert) {
61 | if (res.state === 200) {
62 | Alert.success(res.info, {
63 | effect: "slide",
64 | timeout: 2000
65 | })
66 | } else if (res.state === 300) {
67 | dispatch({
68 | type: "SHOW_INFO",
69 | info: {
70 | info: res.info,
71 | xuhao: 3
72 | }
73 | })
74 | Alert.warning(res.info, {
75 | effect: "slide",
76 | timeout: 2000
77 | })
78 | } else if (res.state === 400) {
79 | Alert.error(res.info, {
80 | effect: "slide",
81 | timeout: 2000
82 | })
83 | }
84 | }
85 | },
86 | error: function() {
87 | dispatch({
88 | type: CHANGE_LOGIN_STATE,
89 | userType: 0
90 | });
91 | Alert.error("朋友,你的网络出现问题了", {
92 | effect: "slide",
93 | timeout: 2000
94 | })
95 | },
96 | failed: function() {
97 | dispatch({
98 | type: CHANGE_LOGIN_STATE,
99 | userType: 0
100 | });
101 | Alert.error("朋友,你的网络出现问题了", {
102 | effect: "slide",
103 | timeout: 2000
104 | })
105 | }
106 | })
107 | }
108 | }
109 |
110 | /*ajax相关,需要有返回值的*/
111 | export const GET_DATA = "GET_DATA"
112 | export const GET_DATA_SUCCESS = "GET_DATA_SUCCESS"
113 | export const GET_DATA_ERROR = "GET_DATA_ERROR"
114 | /**
115 | * 所有获取数据的ajax请求
116 | * @param {string} url 请求数据的后台接口
117 | * @param {object} data 传送到后台的数据
118 | * @param {string} type ajax种类
119 | * @param {bool} alert 是否弹出提示信息
120 | * @return {[type]} [description]
121 | */
122 | export function getData(url, data, type = "get", alert) {
123 | return (dispatch, getState) => {
124 | dispatch({
125 | type: GET_DATA,
126 | })
127 | $.ajax({
128 | url: config.url + url,
129 | type: type,
130 | data: data,
131 | xhrFields: {
132 | withCredentials: true
133 | },
134 | dataType: "json",
135 | success: function(res) {
136 | if (res.data) {
137 | dispatch({
138 | type: GET_DATA_SUCCESS,
139 | data: res.data
140 | })
141 | }
142 | if (alert) {
143 | switch (res.state) {
144 | case 200:
145 | Alert.success(res.info, {
146 | effect: "slide",
147 | timeout: 2000
148 | });
149 | break;
150 | case 300:
151 | Alert.warning(res.info, {
152 | effect: "slide",
153 | timeout: 2000
154 | });
155 | break;
156 | case 400:
157 | Alert.error(res.info, {
158 | effect: "slide",
159 | timeout: 2000
160 | })
161 | }
162 | }
163 | }.bind(this),
164 | error: function(res) {
165 | dispatch({
166 | type: GET_DATA_ERROR,
167 | error: res
168 | })
169 | Alert.error("朋友,你的网络出现问题了", {
170 | effect: "slide",
171 | timeout: 2000
172 | })
173 | },
174 | failed: function() {
175 | Alert.error("朋友,你的网络出现问题了", {
176 | effect: "slide",
177 | timeout: 2000
178 | })
179 | }
180 | })
181 | }
182 | }
183 |
184 | export const GET_MESSAGES = "GET_MESSAGES"
185 |
186 | export function getMessages(res) {
187 | return (dispatch, getState) => {
188 | if (res.state === 200) {
189 | dispatch({
190 | type: GET_MESSAGES,
191 | data: res.data
192 | })
193 | } else if (res.state === 300) {
194 | Alert.warning(res.info, {
195 | effect: "slide",
196 | timeout: 2000
197 | })
198 | } else {
199 | Alert.error("朋友,你的网络出现问题了", {
200 | effect: "slide",
201 | timeout: 2000
202 | })
203 | }
204 | }
205 | }
--------------------------------------------------------------------------------
/public/css/index.css:
--------------------------------------------------------------------------------
1 | *{margin:0;padding:0;font-family: "MicroSoft YaHei";box-sizing:border-box;}
2 | html,body,#main{width:100%;height:100%;}
3 | .main{min-height:100%;background: url('../img/bg.jpg');background-attachment:fixed;}
4 | a{text-decoration: none;color:#654321}
5 | button{box-shadow: 1px 1px 5px #654321;margin:0 2px;border:none;transition:.2s;border-radius: 5px}
6 | button:hover{background:#654321;color:white;padding:10px!important;z-index:20;cursor: pointer}
7 |
8 | .loading-icon{position:absolute;left:50%;top:20%;margin-left:-25px}
9 | /* 左侧导航 */
10 | nav{text-align:center;line-height:40px;font-size:18px;}
11 | nav ul{width:100%;list-style:none}
12 | nav li{transition: .5s}
13 | nav li:hover{color:black;}
14 | .logo{width:40px;height:40px;}
15 | .nav{height:100%;width:150px;background:rgba(101,67,33,.8);position:fixed;z-index:100;left:0;top:0;display:flex;justify-content:center}
16 | .nav-list{margin-top:50px;}
17 | .nav-list a{color:#fff}
18 | .nav-list a:nth-of-type(1){color:#654321;}
19 | .nav-list-bottom{position:absolute;width:150px;bottom:50px;left:0;text-align: center}
20 | .nav-list-bottom a{color:#fff}
21 | .sign-button-group{position:fixed;right:10px;top:2px;z-index:101}
22 | .sign-button-group button{border:none;padding:10px;}
23 | .alert{position: fixed;left:150px;top:0}
24 | .activeClass li{background:#8d7155;color:black;}
25 |
26 | @media screen and (max-width:768px){
27 | .nav{position:fixed;bottom:0;top:auto;width:100%;height:3em}
28 | nav ul{display: flex;line-height:3em;justify-content:space-around}
29 | .nav-list>a:nth-of-type(1){position:fixed;top:0;left:0;width:100%;line-height:1;background:rgba(101,67,33,.8);text-align: left;}
30 | .nav-list{margin:0}
31 | .activeClass li{background:none;}
32 | .activeClass a:focus{background: none}
33 | .nav-list-bottom{position:static;width:auto}
34 | .nav-list-bottom{color:white}
35 | .nav-list span{visibility: hidden}
36 | .nav-posts li{background:url("../img/post n.png") no-repeat center;background-size: 50px 50px}
37 | .nav-talk li{background:url("../img/talk (1).png") no-repeat center;background-size: 25px 25px}
38 | .nav-about li{background:url("../img/about.png") no-repeat center;background-size: 36px 36px}
39 | .nav-list-bottom li{background:url("../img/write.png") no-repeat center;background-size: 25px 25px}
40 | .actPosts li{background:url("../img/icon post.png") no-repeat center;background-size: 35px 35px}
41 | .actTalk li{background:url("../img/talk.png") no-repeat center;background-size: 25px 25px}
42 | .actAbout li{background:url("../img/about (1).png") no-repeat center;background-size: 36px 36px}
43 | .actWrite li{background:url("../img/write (1).png") no-repeat center;background-size: 25px 25px}
44 | }
45 | /* 登录注册页面 */
46 | .signInput{width:40%;margin:0 auto}
47 | .signInput input{width:100%;margin:5px 0;border-radius: 5px;border:none;padding:5px;transition:.2s}
48 | .signInput input:hover{box-shadow: 0 0 5px #654321;transform:scale(1.1)}
49 | .signInput input:focus{box-shadow: 0 0 5px #654321;transform:scale(1.1);border:none;outline:none}
50 | .input-check{font-size:12px;color:red}
51 | @media screen and (max-width:768px){
52 | .signInput{width:70%}
53 | }
54 | /* 右侧内容区域 */
55 | .main-right{padding-left:150px;padding-top:40px;}
56 | .main-right .container{width:70%;margin:0 auto;padding:15px 0;position: relative;}
57 | @media screen and (max-width:768px){
58 | .main-right{padding-left:0}
59 | .main-right .container{width:95%}
60 | }
61 |
62 | .manager-btn{float:right;border:none;padding:4px 5px}
63 | /* 文章样式 */
64 | .post{box-shadow: 0 0 10px lightgray;padding:15px;border-radius: 5px 5px;transition:.2s;margin-bottom:15px}
65 | .post .post-head{text-align: center;margin:10px 0 5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
66 | .post .createTime{font-size:12px;line-height:24px}
67 | .createTime button{font-size:12px}
68 | .post .content{font-size:16px;margin:15px 0;}
69 | .post .comments-list{margin-bottom:5px;font-size:14px}
70 | .post .clickGood{cursor: pointer;}
71 | /* 文章内容样式 */
72 | .content{padding:2px}
73 | .content h2{padding-bottom: 0.3em;font-size: 1.5em;border-bottom: 1px solid #654321;margin-bottom: 16px;font-weight: 600;line-height: 1.25;}
74 | .content p{margin-bottom: 16px;}
75 | .content ul{padding-left: 1em;margin-bottom: 16px;list-style:auto;}
76 | .content pre{padding:5px;overflow-x: auto;font-size: 85%;line-height: 1.45;background-color: rgba(255,255,255,.4);border-radius: 3px;margin-bottom:16px;}
77 | /* 主页时文章的样式 */
78 | .posts-list .post-head{text-align:left;}
79 | .posts-list .post:hover{box-shadow: 0 5px 10px #654321;transform:translate(0,-5px)!important;background:rgba(255,255,255,.5)}
80 | .posts-list .content{height:64px;overflow: hidden;position:relative;}.posts-list .content::after {content: " ... "; bottom:0px;right: 3px;position: absolute;}
81 | /* 输入框 */
82 | textarea{background:rgba(255,255,255,.5);width:100%;padding:10px;border:none;transition: .2s;resize:none}
83 | textarea:hover{box-shadow: 0 0 5px #654321;transform:scale(1.01);border-radius: 10px}
84 | textarea:focus{box-shadow: 0 0 5px #654321;transform:scale(1.01);border-radius: 10px;border:none;outline:none}
85 | .input-area button{font-size:14px;padding:3px 5px;}
86 | input{background:rgba(255,255,255,.5);}
87 | /* 评论 */
88 | .aComment{position:relative;font-size:14px;margin:5px 0;padding-right:35px}
89 | .aComment .comment-user{color:#654321}
90 | .aComment .comment-content{color:gray}
91 | .aComment button{position: absolute;right:0;top:0;font-size:12px;padding:2px}
92 | /* 发表页面 */
93 | .write-post h3{margin-bottom:5px;}
94 | .write-post #head{margin: 5px 0;width:100%;border-radius: 2px;border:1px solid lightgray;transition:.2s;padding:5px;}
95 | .write-post #head:hover{box-shadow: 0 0 5px #654321}
96 | .write-post textarea{resize:auto;height:200px}
97 |
98 | /* 敬请期待 */
99 | .please-wait{text-align: center;font-size:20px}
100 |
101 | /* 聊天 */
102 | .talkroom .message-box{position:fixed;width:60%;max-height: 70%;overflow-x: auto;padding:0 5px}
103 | .message-box .message{margin-bottom:15px;}
104 | .message-head{color:#666}
105 | .message-head .message-name{font-weight: bold}
106 | .message-head .message-time{font-size:12px;margin:0 5px}
107 | .talkroom .talk-input-group{position: fixed;top:80%;width:60%;z-index:10}
108 | .talk-input-group .talk-input{width:90%;margin:5px 0;border-radius: 5px;border:none;padding:5px;transition:.2s}
109 | .talk-input-group .talk-input:hover{box-shadow: 0 0 5px #654321}
110 | .talk-input-group .talk-input:focus{box-shadow: 0 0 5px #654321;border:none;outline:none}
111 | .self .message-name{float:right}
112 | .self .message-time{float:right}
113 | .self .message-content{float:right;}
114 | .self:after{content:" ";display:block;clear:both}
115 | .showAll{cursor:pointer}
116 | @media screen and (max-width:768px){
117 | .talkroom .message-box{width:95%;padding:0 15px;height:90%}
118 | .talkroom .talk-input-group{width:100%}
119 | .talk-input-group .talk-input{width:80%}
120 | .talk-submit{background:#654321;color:white;padding:5px 10px!important;z-index:20;cursor: pointer}
121 | .talkroom .talk-input-group{top:auto;bottom:4em;}
122 | .talkroom .message-box{max-height:100%;padding-bottom:5.5em}
123 | }
124 |
125 |
--------------------------------------------------------------------------------
/public/src/component/about/about.js:
--------------------------------------------------------------------------------
1 | import React,{PropTypes} from 'react'
2 |
3 | export default class About extends React.Component{
4 | render(){
5 | return (
6 |
7 |
8 |
9 |
10 |

11 |

12 |
13 |
14 |
15 |
16 |
17 | 唐凯
18 |
19 |
20 | hello world
21 |
22 |
23 |
24 |
25 |
26 | 计算机科学与技术 · 贵州大学
27 |
28 |
29 |
30 | 男 22岁 本科
31 | 1年工作经验1994.08年出生 北京
32 |
33 |
34 | 18519772682
35 | tangkai123456@live.com
36 |
37 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
贵州鼎慧科技有限公司
62 | 前端
63 |
64 |
65 |
66 | 2016.03 -- 2016.10
67 |
68 |
69 |
70 |
71 |
1、根据产品设计的需求,配合后台开发人员实现产品的界面以及功能,维护及优化前端页面性能。
72 |
2、参与设计并且编写web前端构架以及应用。
73 |
3、产品、设计、后台开发各个部门沟通,利用HTML以及JavaScript等相关技术开发网站和客户端的前端页面。
74 |
4、利用css3以及JavaScript构建公司的网站,将公司的信息以及产品的介绍通过HTML的页面展示出来,并且保证产品信息的更新。
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
91 |
92 |
93 |
94 |
95 |
96 |

97 |
98 |
99 |
贵州大学
100 | 本科 · 计算机科学与技术
101 |
102 |
103 |
104 | 2016年毕业
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | 项目经验
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
个人博客
127 |
全栈
128 |
129 |
130 |
131 |
132 | 2016.12 -- 2016.12
133 |
134 |
135 |
136 |
使用react+react-router构建前台页面,所有状态交由redux管理。
137 |
后台使用nodejs的express框架+mongodb进行数据操作与存储。
138 |
项目部署在腾讯云上
139 |
140 |
141 |
142 |
143 |
149 |
150 |
151 | 2016.11 -- 2016.11
152 |
153 |
154 |
155 |
编写全屏滚动网页展示信息,分页使用fullPage库完成,链式调用组件加载页面,详细信息展示使用canvas实现。
156 |
157 |
158 |
159 |
160 |
166 |
167 |
168 | 2016.11 -- 2016.11
169 |
170 |
171 |
172 |
使用skrollr库,制作视差滚动特效的个人简历网站
173 |
174 |
175 |
176 |
177 |
183 |
184 |
185 | 2016.11 -- 2016.11
186 |
187 |
188 |
189 |
使用webpack + react + react-router + nodejs + mongodb完成糗事百科部分功能
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 | 自我描述
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |

210 |
211 |
212 |
个人主页:www.tangkai123456.xyz
213 |
git: tangkai123456
214 |
熟练使用react、react-router、redux进行组件化开发,组件复用程度高。
215 |
熟悉es6,喜欢尝试新特性。
216 |
熟悉nodejs,常用express等框架编写后端逻辑。
217 |
能使用webpack、git对项目打包和版本控制。
218 |
熟练编写各种常用特效,以及ajax数据交互。
219 |
熟练使用bootstrap完成体验良好的响应式页面。
220 |
221 |
222 |
223 |
诚实开朗,思维活跃,喜欢学习新技术
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 | 期望工作
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 | - 前端工程师
244 | - 全职
245 | - 北京
246 | - 5k-10k
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 | 技能评价
260 |
261 |
262 |
263 |
264 |
265 | html+css
266 |
267 |
268 |
269 | 精通
270 |
271 |
272 | js、jq
273 |
274 |
275 |
276 | 精通
277 |
278 |
279 | react、angular
280 |
281 |
282 |
283 | 掌握
284 |
285 |
286 | nodejs
287 |
288 |
289 |
290 | 掌握
291 |
292 |
293 | webpack、git
294 |
295 |
296 |
297 | 熟悉
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 | · 我目前已离职,可快速到岗 ·
307 |
308 |
309 |
310 |
311 |
312 | )
313 | }
314 | }
--------------------------------------------------------------------------------
/public/build/About.6577d.chunk.js:
--------------------------------------------------------------------------------
1 | webpackJsonp([5],{350:function(e,t,a){"use strict";function l(e){return e&&e.__esModule?e:{default:e}}function m(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function r(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var s=function(){function e(e,t){for(var a=0;a=0&&h.splice(r,1)}function o(t){var r=document.createElement("style");return r.type="text/css",m(t,r),r}function s(t){var r=document.createElement("link");return r.rel="stylesheet",m(t,r),r}function f(t,r){var a,i,e;if(r.singleton){var m=p++;a=d||(d=o(r)),i=l.bind(null,a,m,!1),e=l.bind(null,a,m,!0)}else t.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(a=s(r),i=b.bind(null,a),e=function(){n(a),a.href&&URL.revokeObjectURL(a.href)}):(a=o(r),i=x.bind(null,a),e=function(){n(a)});return i(t),function(r){if(r){if(r.css===t.css&&r.media===t.media&&r.sourceMap===t.sourceMap)return;i(t=r)}else e()}}function l(t,r,a,i){var e=a?"":i.css;if(t.styleSheet)t.styleSheet.cssText=g(r,e);else{var m=document.createTextNode(e),n=t.childNodes;n[r]&&t.removeChild(n[r]),n.length?t.insertBefore(m,n[r]):t.appendChild(m)}}function x(t,r){var a=r.css,i=r.media;if(i&&t.setAttribute("media",i),t.styleSheet)t.styleSheet.cssText=a;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(a))}}function b(t,r){var a=r.css,i=r.sourceMap;i&&(a+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(i))))+" */");var e=new Blob([a],{type:"text/css"}),m=t.href;t.href=URL.createObjectURL(e),m&&URL.revokeObjectURL(m)}var c={},k=function(t){var r;return function(){return"undefined"==typeof r&&(r=t.apply(this,arguments)),r}},u=k(function(){return/msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase())}),w=k(function(){return document.head||document.getElementsByTagName("head")[0]}),d=null,p=0,h=[];t.exports=function(t,r){r=r||{},"undefined"==typeof r.singleton&&(r.singleton=u()),"undefined"==typeof r.insertAt&&(r.insertAt="bottom");var a=e(t);return i(a,r),function(t){for(var m=[],n=0;n.dropdown_menu{margin-top:58px !important;*margin:70px 0 0 -220px !important;opacity:1;visibility:visible}
41 |
42 | .mr_w604{width:604px;margin:0 auto;}
43 | .mr_p_name{height:40px;line-height:38px;margin-bottom:8px;}
44 | .mr_name{display:block;height:40px;width:468px;margin:0 auto;line-height:40px;font-size:30px;color:#333;text-align:center;}
45 | .mr_intro{display:block;color:#333;text-align:center;margin:0 auto;}
46 | .mr_p_introduce .mr_intro{font-size:16px;width:468px;line-height:26px;}
47 | .mr_p_introduce .mr_intro_grey{color:#bdbdbd;font-style: italic;}
48 | .mr_edit{float:right;margin-right:12px;cursor:pointer;}
49 | .mr_edit em{font-size:16px;color:#00b38a;}
50 | .mr_edit i{display:inline-block;width:12px;height:14px;background:url(../images/myresume/icons_mr.png) -53px -6px no-repeat;margin-right:7px;}
51 | .mr_edit *{vertical-align: middle;}
52 | .mr_active{background-color: #fefef2;}
53 | /* 未创建在线 基本信息 */
54 | .mr_myresume_l input{margin:0;}
55 | .mr_p_info{position:relative;color:#666;padding:5px 0 7px 0;}
56 | .mr_p_info .mr_edit{position:absolute;right:0px;top:4px;}
57 | .mr_edit i {display: inline-block;width: 12px;height: 14px;background: url(http://www.lagou.com/images/myresume/icons_mr.png) -53px -6px no-repeat;margin-right: 7px;}
58 | .mr_name_edit,.mr_intro_edit{padding-left:154px;margin-bottom:8px;}
59 | .mr_name_edit input,.mr_name_edit a,.mr_intro_edit input,.mr_introduce_edit *{vertical-align: middle;}
60 | .mr_name_edit .ed_name,.mr_intro_edit .ed_name{width:368px; height:30px;border:1px solid #eeeff1;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;margin:0;text-align:center;font: 30px/30px "微软雅黑","宋体",Arial;margin-right:12px;}
61 | .mr_name_edit input[type="text"]:focus,.mr_intro_edit input[type="text"]:focus{border-width:1px;}
62 | .mr_name_edit .save,.mr_intro_edit .save{border:none;margin:0;display:inline;padding:0 11px;*padding:0 4px;font-size:14px;height:30px;text-align:center;line-height:30px;color:#fff;background-color: #00b38a;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;margin-right:12px;}
63 | .mr_intro_edit .ed_name{font-size:16px;}
64 | .mr_name_edit .cancel,.mr_intro_edit .cancel{color:#00b38a;}
65 | .mr_p_info .info_t{text-align:center;margin-bottom:8px;}
66 | .mr_p_info .info_b{text-align:center;}
67 | .mr_p_info .mobile{margin-right:18px;}
68 | .mr_p_info .mobile i{width:12px;height:14px;background-position:-131px -70px;}
69 | .mr_p_info .email i{width:14px;height:10px;background-position:-150px -73px;}
70 | .mr_info_edit{padding:40px 0 50px 155px;background-color:#fefef2;}
71 | .mr_info_edit label{display:block;color:#afafa9;padding-bottom:4px;padding-left:3px;}
72 | .mr_info_on{padding-left:83px;}
73 | .form_wrap{position:relative;cursor:pointer;width:396px;height:46px;border:1px solid #f1f3e9;background-color:#fff;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;margin-bottom:9px;}
74 | .form_wrap .mr_button{text-align:left;padding-left:17px;width:327px;height:46px;background-color:#fff;}
75 | .form_wrap .mr_input{width:327px;padding:0 0 0 17px;border:none;height:46px;}
76 | .form_wrap .mr_input:focus{border:none;}
77 | .form_wrap .mr_selCity{width:395px;}
78 | .form_wrap_y .mr_button{width:150px;}
79 | .mr_sns_m .mr_button:focus{border:none;}
80 | .mr_sj{position:absolute;right:18px;top:20px;border: 6px solid #fff;border-color: #d3d3d3 transparent transparent;display: block;font-size: 0px;height: 0;width: 0;}
81 | .form_wrap_y .xl_list{width:190px;}
82 | .xl_list{position:absolute;top:49px;left:-1px;z-index:2;width:395px;background-color:#fff;border:1px solid #e7e7e7;box-shadow:2px 2px 4px #efefe4;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;}
83 | .xl_list li{height:36px;line-height:36px;padding-left:17px;}
84 | .xl_list li:hover{background-color:#f4f4f4;}
85 | .xl_list .mr_selCity{margin:0;}
86 | .xl_list *{list-style:none;}
87 | .form_wrap_y{width:188px;}
88 | .mr_basic .mr_basicform .mr_topdegree ul li,.mr_basic .mr_basicform .mr_workyear ul li,.mr_selCity ul.mr_province li,.mr_selCity ul.mr_province li,.mr_education ul li{ height: 33px;font-size: 14px;padding-left: 15px;line-height: 33px; cursor: pointer;}
89 | .mr_selCity ul.mr_province li{padding: 0;text-align: center;}
90 | .mr_selCity{height: 130px; background: #fff;width: 300px; overflow: hidden; margin-left: -1px;top: 45px; position: absolute;box-shadow:2px 2px 4px #efefe4;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;border:1px solid #e7e7e7;}
91 | .mr_selCity{height: 130px; background: #fff;width: 300px; overflow: hidden; margin-left: -1px;top: 45px; position: absolute;box-shadow:2px 2px 4px #efefe4;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;border:1px solid #e7e7e7;}
92 | .mr_selCity ul.mr_province{width: 90px; border-right: 1px solid #ececec;font-size: 14px;text-align: center;line-height: 33px; height: 130px; overflow: auto;}
93 | .mr_selCity ul.mr_province li span{ cursor: pointer; display: inline-block;width: 73px;}
94 | .mr_selCity ul.mr_province li ul{position: absolute;top:0;left: 90px;width: 209px;height: 130px;overflow: auto; color: #555}
95 | .mr_selCity ul.mr_province li ul li{float: left;padding: 0px 8px;border-radius: 3px;margin:4px;height: 23px; line-height: 23px; cursor: pointer;}
96 | .mr_locks{position:absolute;width:30px;height:30px;top:8px;right:8px;background:url(http://www.lagou.com/images/myresume/icons_mr.png) -144px -83px no-repeat;}
97 |
98 | /*已创建在线简历 jason 2014/9/8*/
99 | .mr_p_introduce{min-height:34px;line-height:32px;margin-bottom:4px;}
100 | .mr_add_m{position:absolute;top:44px;left:0;padding:18px 0 0 20px;background-color:#fff;z-index:2;border:1px solid #e7e7e7;box-shadow:2px 2px 4px #efefe4;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;}
101 | .mr_add_m li.mr0{margin-right:0;}
102 | .mr_month .mr0{margin-right:0;}
103 | .mr_year_se span i,.mr_year_se span em{vertical-align:middle;}
104 | .mr_year_se i{margin-right:11px;}
105 | .mr_years,.mr_man{margin-right:12px;}
106 | span.mr_man,span.mr_women{width:63px;padding-left:27px;color:#b5b5b5;;height:46px;line-height:46px;border:1px solid #f1f3e9;background-color:#fff;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;cursor:pointer;}
107 | span.active{color:#333;}
108 | span.mr_man i,span.mr_women i{display:inline-block;width:16px;height:16px;background:url(http://www.lagou.com/images/myresume/icons_mr.png) no-repeat;}
109 | span.mr_man i{background-position:-4px -25px;}
110 | span.mr_man i.active{background-position:-4px -5px;}
111 | span.mr_women i{background-position:-27px -25px;}
112 | span.mr_women i.active{background-position:-27px -5px;}
113 | .sns_area .mr_sns_m{position:relative;width:534px;margin-bottom:16px;}
114 | .mr_add_sns{position:relative;}
115 | .mr_add_sns i,.mr_add_sns em{vertical-align:middle;}
116 | .mr_add_sns i{display:inline-block;margin-right:10px;width:15px;height:15px;background:url(http://www.lagou.com/images/myresume/icons_mr.png) -5px -69px no-repeat;}
117 | .mr_add_sns em{color:#afafa9;}
118 | .mr_add_m i,.mr_add_m em{position:absolute;background:none;top:-16px;border: 8px solid #e7e7e7;border-color: transparent transparent #e7e7e7;display: block;font-size: 0px;height: 0;width: 0;}
119 | .mr_add_m em{border-color: transparent transparent #fff;top:-15px;}
120 | .mr_add_m ul{width:276px;}
121 | .mr_add_m li{float:left;width:42px;height:42px;margin:0 4px 10px 0;}
122 | .mr_add_m li.mr0{margin-right:0;}
123 | .mr_add_m .sns1{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -2px 3px no-repeat;}
124 | .mr_add_m .sns2{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -54px 3px no-repeat;}
125 | .mr_add_m .sns3{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -106px 3px no-repeat;}
126 | .mr_add_m .sns4{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -158px 3px no-repeat;}
127 | .mr_add_m .sns5{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -210px 3px no-repeat;}
128 | .mr_add_m .sns6{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -261px 3px no-repeat;}
129 | .mr_add_m .sns7{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -312px 3px no-repeat;}
130 | .mr_add_m .sns8{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -364px 3px no-repeat;}
131 | .mr_add_m .sns9{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -415px 3px no-repeat;}
132 | .mr_add_m .sns10{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -467px 3px no-repeat;}
133 | .mr_add_m .sns11{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -518px 3px no-repeat;}
134 | .mr_add_m .sns12{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -570px 3px no-repeat;}
135 |
136 | .mr_add_m .sns1.active{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -1px -43px no-repeat;}
137 | .mr_add_m .sns2.active{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -54px -43px no-repeat;}
138 | .mr_add_m .sns3.active{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -106px -43px no-repeat;}
139 | .mr_add_m .sns4.active{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -158px -43px no-repeat;}
140 | .mr_add_m .sns5.active{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -210px -43px no-repeat;}
141 | .mr_add_m .sns6.active{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -261px -43px no-repeat;}
142 | .mr_add_m .sns7.active{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -313px -43px no-repeat;}
143 | .mr_add_m .sns8.active{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -364px -43px no-repeat;}
144 | .mr_add_m .sns9.active{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -415px -43px no-repeat;}
145 | .mr_add_m .sns10.active{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -467px -43px no-repeat;}
146 | .mr_add_m .sns11.active{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -518px -43px no-repeat;}
147 | .mr_add_m .sns12.active{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -570px -43px no-repeat;}
148 | .mr_add_op{padding:10px 0;margin-left:-20px;background-color:#fafafa;}
149 | .mr_add_op a{vertical-align:middle;}
150 | .mr_add_op .mr_none_my{float:left;color:#b5b5b5;padding:6px 0;margin-left:20px;}
151 | .mr_add_op .sns_cancel,.mr_add_op .sns_save{float:right;padding:6px 13px;text-align:center;}
152 | .mr_add_op .sns_save{background-color:#00b88d;color:#fff;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;}
153 | .sns_add{cursor:pointer;}
154 | .mr_sns_m i{position:absolute;left:-43px;top:7px;width:30px;height:30px;background:url(http://www.lagou.com/images/myresume/sns_bg.png) no-repeat;}
155 | .mr_sns_m .mr_button{width:467px;padding:0 0 0 17px;border:none;}
156 | .mr_sns_m em{position:absolute;width:20px;height:20px;right:10px;top:13px;}
157 | .mr_sns_m .mr_ok{background:url(http://www.lagou.com/images/myresume/icons_mr.png) -4px -46px no-repeat;}
158 | #expectJob .mr_moudle_content{padding-bottom:25px;}
159 | /*在线简历页面主内容区域*/
160 | .mr_myresume_l .mr_content{padding-top:26px;background-color: #fafafa;border: 1px solid #f2f2f2;border-bottom:2px solid #f2f2f2;border-top:none;border-bottom-right-radius: 3px;border-bottom-left-radius: 3px;}
161 | .mr_moudle_head{margin-bottom:23px;}
162 | #customBlock .mr_moudle_head{margin-bottom:33px;}
163 | .mr_moudle_head .mr_head_l{float:left;}
164 | .mr_moudle_head .mr_head_r{float:right;margin-top:3px;cursor:pointer;}
165 | .mr_title span{vertical-align:middle;display:inline-block;}
166 | .mr_title .mr_title_l{width:230px;height:0;border-top:1px solid #ededed;}
167 | .mr_title .mr_title_c{font-size:18px;padding:6px 24px;text-align:center;background-color:#eee;-moz-border-radius:26px;-webkit-border-radius:26px;border-radius:26px;margin:0 13px;}
168 | .mr_title .mr_title_r{width:152px;height:0;border-top:1px solid #ededed;}
169 | .mr_moudle_head .mr_head_r *{vertical-align:middle;}
170 | .mr_moudle_head .mr_head_r em{font-size:16px;color:#00b88d;}
171 | .mr_moudle_head .mr_head_r i{display: inline-block;width: 15px;height: 15px;background: url(http://www.lagou.com/images/myresume/icons_mr.png) -5px -69px no-repeat;margin-right:6px;}
172 | .mr_moudle_content{padding-bottom:21px;color:#555;font-size:14px;} /* 块 margin-bottom 48*/
173 | .mr_moudle_content .mr_content_l{float:left;max-width: 445px;}
174 | .mr_moudle_content .mr_content_r{float:right;}
175 | .mr_content_l .l1{float:left;margin-right:10px;}
176 | .mr_content_l .l2{position: relative;float: left;padding-top: 10px;max-width: 380px;}
177 | #workExperience .mr_content_l .l2,#educationalBackground .mr_content_l .l2{padding-top:4px;}
178 | .mr_content_l .l2 a.projectTitle{/* position:relative; */font-size:16px;color:#555;text-decoration:none}
179 | .mr_content_l .l2 a.projectTitle:hover{color:#00b88d}
180 | .mr_content_l .l2 a.nourl{cursor:default;}
181 | .mr_content_l .l2 a.nourl:hover{color:#555;}
182 | .mr_content_l .l2 p{color:#999;}
183 | .mr_content_l .l2 a.projectTitle span{position:absolute;top:14px;right:-18px;width:12px;height:12px;background:url(http://www.lagou.com/images/myresume/icons_mr.png) -95px -197px no-repeat;}
184 | .mr_content_l .l1 img{width:46px;height:46px;border:2px solid #eee;}
185 | .mr_content_l .l2 h4{font-size:16px;}
186 | .mr_content_l .l2 span{color:#999;display:block;}
187 | .mr_c_r_t{text-align:right;margin:5px 0 2px 0;*margin-top:8px;float:none;}
188 | .mr_content_r span{color:#999;}
189 | .mr_content_m{padding:14px 0 0 0px;*padding-left:1px;color:#555;}
190 | .mb46{margin-bottom:46px;}
191 | .mr_jobe_list{padding-bottom:44px;}
192 | /* #educationalBackground .mr_moudle_content{padding-bottom:15px;} */
193 | .mr_wo_show{padding:13px 18px 46px 42px;background-color:#00b88d;margin-bottom:38px;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;}
194 | .mr_wo_show p{line-height:26px;color:#fff;}
195 | .mr_self_site{color:#fff;margin-bottom:8px;font-size:24px;}
196 | .mr_self_sitelink {font-weight:bold;text-decoration:none;/* display:inline-block;width:558px; */word-break:break-all;color: #fff;}
197 | .mr_self_sitelink:hover{color:#fff;}
198 | .mr_wo_show .mr_c_r_t em{color:#50f9d2;}
199 | .mr_wo_show .mr_c_r_t i{background:url(http://www.lagou.com/images/myresume/icons_mr.png) -131px -115px no-repeat;}
200 | .wh43{width:100%;}
201 | .mr_work_upload .l2 span{display:inline-block;}
202 | .mr_wu_con .mr_work_title{margin:0 6px;}
203 | .mr_wu_show{margin-bottom:20px;}
204 | .mr_wu_show .mr_c_r_t{padding-top:4px;}
205 | .mr_wu_con .l2 span{color:#333;}
206 | .mr_wu_show .mr_wu_con_m{color:#555;}
207 | .mr_self_l{position:relative;height:81px;}
208 | #selfDescription .mr_head_r i,#expectJob .mr_head_r i,#skillsAssess .mr_head_r i,#customBlock .mr_head_r i{display: inline-block;width: 15px;height: 15px;background: url(http://www.lagou.com/images/myresume/icons_mr.png) -53px -6px no-repeat;margin-right: 7px;}
209 | /* .mr_self_l img{width:73px;height:73px;border-radius:50%;border:4px solid #f7f7f7;box-shadow:0px 2px 3px #dfdfdf;} */
210 | .mr_self_l img{position:absolute;left:4px;width:73px;height:73px;top:8px;}
211 | .mr_self_l i{position:absolute;z-index:2;width:81px;height:81px;background:url(http://www.lagou.com/images/myresume/mr_txs.png) no-repeat;}
212 | .mr_moudle_content .mr_self_l{float:left;width:100px;padding-top:5px;}
213 | .mr_moudle_content .mr_self_r{float:left;width:504px;color:#555;line-height:26px;}
214 | #selfDescription .mr_moudle_content{padding-bottom:48px;}
215 | #expectJob .expectjob_list{position:relative;}
216 | #expectJob .mr_job_des i{position:absolute;width:32px;height:31px;background:url(http://www.lagou.com/images/myresume/icons_mr.png) no-repeat;}
217 | #expectJob .mr_moudle_content .mr_job_t{left:0;top:1px;background-position:-160px -110px;}
218 | #expectJob .mr_moudle_content .mr_job_b{right:0;bottom:5px;background-position:-160px -153px;}
219 | .mr_moudle_content .mr_job_info{text-align:center;padding-left:28px;}
220 | .mr_job_info{color:#555;}
221 | .mr_job_info li{list-style:none;float:left;text-align:left;height:24px;line-height:24px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis;}
222 | .mr_name_li{width:188px;}
223 | .mr_jobtype_li{width:128px;}
224 | .mr_city_li{width:124px;}
225 | .mr_sns .sns10 span{min-width:56px;}
226 | .mr_jobrange_li{width:94px;}
227 | .mr_job_info i{display:inline-block;margin-right:10px;background:url(http://www.lagou.com/images/myresume/icons_mr.png) no-repeat;}
228 | .mr_name_li i{width:9px;height:19px;background-position:-97px -220px;}
229 | .mr_jobtype_li i{width:17px;height:17px;background-position:-93px -247px;}
230 | .mr_city_li i{width:14px;height:17px;background-position:-93px -273px;}
231 | .mr_jobrange_li i{width:18px;height:18px;background-position:-92px -294px;}
232 | .mr_job_info li *{vertical-align:middle;}
233 | .mr_job_info li{overflow:hidden;white-space:nowrap;text-overflow: ellipsis;}
234 |
235 | .mr_job_info p .mr_333{color:#333;}
236 | .expectjob_list .mr_job_des {position:relative;margin-top:28px;padding:15px 38px 25px 50px;}.mr_moudle_content .mr_job_info{text-align:center;}
237 | .mr_job_info{color:#555;}
238 | .mr_job_info p .mr_333{color:#333;}
239 | .expectjob_list .clearfixs li{font-size:16px;}
240 | /*
241 | #skillsAssess{padding-bottom:50px;}
242 | .mr_skill_con{padding-left:20px;margin-bottom:18px;}
243 | .mr_skill_con span{vertical-align:middle;display:inline-block;}
244 | .mr_skill_con .mr_skill_name{width:90px;height:22px;text-align:right;margin-right:13px;word-wrap:break-word;white-space:nowrap;overflow:hidden;text-overflow: ellipsis;}
245 | .mr_skill_con .mr_skill_name:after{
246 | content:"...";
247 | }
248 | .mr_skill_con .mr_skill_plan{position:relative;width:420px;height:8px;border-radius:4px;background-color:#eee;margin-right:21px;overflow:hidden;}
249 | .mr_skill_plan em{position:absolute;left:0;top:0;display:inline-block;height:8px;width:370px;background-color:#00b88d;border-radius:4px;overflow:hidden;} */
250 | #skillsAssess{padding-bottom:12px;}
251 | .mr_skill_con{padding-left:16px;margin-bottom:14px;position:relative;}
252 | .mr_skill_con span{vertical-align:middle;display:inline-block;}
253 | .mr_skill_con .mr_skill_name{width:90px;height:22px;text-align:right;margin-right:13px;word-wrap:break-word;white-space:nowrap;overflow:hidden;text-overflow: ellipsis;}
254 | /* .mr_skill_con .mr_skill_name:after{
255 | content:"...";
256 | } */
257 | .mr_skill_con .mr_skill_plan{position:relative;width:410px;height:8px;border-radius:4px;background-color:#eee;margin-right:21px;overflow:hidden;}
258 | .mr_skill_plan em{position:absolute;left:0;top:0;display:inline-block;height:8px;background-color:#00b88d;border-radius:4px;overflow:hidden;}
259 | .mr_skill_con .mr_skill_delete{width:13px;height:13px;background:url(http://www.lagou.com/images/myresume/skill_delete.png) center top no-repeat;cursor:pointer;}
260 | .mr_moudle_content .mr_skill_add{padding-left:125px;*padding-left:104px;color:#999999;font-size:16px;}
261 | .mr_skill_add span{display:inline-block;width:88px;text-indent:22px;background:url(http://www.lagou.com/images/myresume/skill_add.png) left 3px no-repeat;cursor:pointer;}
262 | #customBlock{padding-bottom:30px;}
263 | #customBlock .mr_title{position:relative;}
264 | .mr_title .cust_title{position:absolute;top:-4px;left: 50%;padding:0 13px;background-color:#FAFAFA;}
265 | #customBlock #width604{width:604px;}
266 | #customBlock .mr_line_tl{width:528px;height: 0;border-top: 1px solid #ededed;}
267 | .cust_title span{padding:6px 24px;text-align: center;font-size: 18px;background-color: #eee;-moz-border-radius: 26px;-webkit-border-radius: 26px;border-radius: 26px;}
268 | #customBlock .mr_prolink .mr_btn{width:484px;}
269 | .mr_skill_con .mr_skill_circle{display:inline-block;width:20px;height:19px;position:absolute;left:122px;top:3px;background:url(http://www.lagou.com/images/myresume/skill_circle.png) no-repeat center top;}
270 | .mr_skill_circle em{display:inline-block;width:29px;height:23px;position:absolute;right: -4px;top: -22px;text-align: center;line-height:18px;padding: 0px;color: #ffffff;background:url(http://www.lagou.com/images/myresume/skill_img.png) center top no-repeat;font-size:10px;}
271 |
272 |
273 | /****一句话介绍****/
274 | .mrcenter{margin:0 auto 20px auto; float:none;}
275 |
276 | /*创建在线简历 基本信息样式*/
277 | .mr_infoed{margin-bottom:63px;}
278 | .mr_created .mr_infoed{margin-bottom:0px;}
279 | .mr_p_info .shenfen{margin-right:10px;}
280 | .mr_p_info .shenfen i{width:14px;height:12px;background-position:-90px -72px;}
281 | .mr_p_info .base_info{}
282 | .mr_p_info .base_info i{width:13px;height:13px;background-position:-111px -70px;}
283 | .mr_p_info .base_info em{margin-right:12px;}
284 | .mr_p_info .base_info em.mr0{margin:0;}
285 | #workExperience .mr_content_m{padding:4px 0 1px 0;}
286 | #workExperience .list_show{padding-bottom:6px;}
287 | #workExperience .mr_moudle_content{padding-bottom:0;}
288 | #educationalBackground .mb46{margin-bottom:0;}
289 | #educationalBackground .mr_moudle_content{padding-bottom:5px;}
290 | #projectExperience .mr_content_m{padding-top:8px;}
291 | #projectExperience .mr_jobe_list{padding-bottom:32px;}
292 | #projectExperience .mr_moudle_content{padding-bottom:18px;}
293 | .mr_sns a{position:relative;display:inline-block;width:30px;background:none;height:30px;margin:0 8px;}
294 | .mr_sns a span{position:absolute;min-width:28px;display:none;top:-29px;left:50%;height:20px;line-height:20px;line-height:18px\9;color:#fff;text-align:center;background-color:#666660;padding:0 10px;-moz-border-radius:10px;-webkit-border-radius:10px;border-radius:10px;}
295 | .mr_sns a em{position:absolute; top:20px;left:50%;margin-left:-4px;font-size:0px; height:0; width:0; border-width:4px 4px 0; border-style:solid dashed; border-color:#666 transparent transparent;overflow: hidden;-webkit-transition:all 0.4s ease 0s;-moz-transition:all 0.4s ease 0s;-o-transition:all 0.4s ease 0s;transition:all 0.4s ease 0s;}
296 | .mr_sns .mr0{margin-right:0;}
297 | .mr_sns i{display:inline-block;width:30px;background:none;height:30px;margin-right:17px;}
298 | .mr_sns .sns1,.mr_sns_m .sns1,.mr_add_m .sns1{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -4px -5px no-repeat;}
299 | .mr_sns .sns2,.mr_sns_m .sns2,.mr_add_m .sns2{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -56px -5px no-repeat;}
300 | .mr_sns .sns3,.mr_sns_m .sns3,.mr_add_m .sns3{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -108px -5px no-repeat;}
301 | .mr_sns .sns4,.mr_sns_m .sns4,.mr_add_m .sns4{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -160px -5px no-repeat;}
302 | .mr_sns .sns5,.mr_sns_m .sns5,.mr_add_m .sns5{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -212px -5px no-repeat;}
303 | .mr_sns .sns6,.mr_sns_m .sns6,.mr_add_m .sns6{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -263px -5px no-repeat;}
304 | .mr_sns .sns7,.mr_sns_m .sns7,.mr_add_m .sns7{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -314px -5px no-repeat;}
305 | .mr_sns .sns8,.mr_sns_m .sns8,.mr_add_m .sns8{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -366px -5px no-repeat;}
306 | .mr_sns .sns9,.mr_sns_m .sns9,.mr_add_m .sns9{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -417px -5px no-repeat;}
307 | .mr_sns .sns10,.mr_sns_m .sns10,.mr_add_m .sns10{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -469px -5px no-repeat;}
308 | .mr_sns .sns11,.mr_sns_m .sns11,.mr_add_m .sns11{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -520px -5px no-repeat;}
309 | .mr_sns .sns12,.mr_sns_m .sns12,.mr_add_m .sns12{background:url(http://www.lagou.com/images/myresume/sns_bg.png) -572px -5px no-repeat;}
310 | .mr_infoed .mr_sns{text-align:center;padding-top:20px;}
311 | #projectExperience .mr_content_l .l2{padding-top:4px;}
312 | .mr_ope .mr_delete{position:relative;cursor:pointer;float:right;font-size:16px;color:#ff685e;margin-top:13px;}
313 | .mr_ope{padding-top:34px;}
314 | .mr_ope .mr_save,.mr_ope .mr_cancel{padding:12px 18px;font-size:16px;vertical-align:middle;}
315 | .mr_cancel{color:#00b88d;}
316 | .mr_save{background-color:#00b38a;margin-right:5px;color:#fff;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;}
317 |
318 | /*底部求职者职场状态*/
319 | .mr_self_state{position:relative;height:94px;background-color:#f6f6f6;color:#555;font-size:14px;text-align: center;}
320 | .mr_self_state *{list-style:none;}
321 | .mr_self_state .form_wrap{position:absolute;top:50%;left:50%;margin:-24px 0 0 -135px;border:1px solid #eaeced;width:270px;}
322 | .mr_self_state .mr_button{width:240px;}
323 | .mr_self_state .select_color{border-color:#32dbb3;}
324 | .mr_self_state .xl_list{width:270px;}
325 | .mr_bottom{margin-top:5px;}
326 | .mr_bottom *{list-style:none;}
327 | .mr_bottom .mr_bottom_l{float:left;position:relative;cursor:pointer;}
328 | .mr_bottom .mr_bottom_r{float:right;}
329 | .mr_bottom_l i{display:inline-block;margin-right:10px;width:16px;height:12px;background:url(http://www.lagou.com/images/myresume/icons_mr.png) -90px -140px no-repeat;}
330 | .mr_bottom_l em{color:#c5c5c5;}
331 | .mr_bottom .mr_down:hover em{color:#333;}
332 | .mr_bottom .mr_down:hover i{background:url(http://www.lagou.com/images/myresume/icons_mr.png) -117px -140px no-repeat;}
333 | .mr_bottom_r{text-align:right;color:#c6c6c6;}
334 | .mr_bottom_l .mr_down_tip{position:absolute; width:96px;height:116px;top:-126px;left:12px;background-color:#fff;border:1px solid #e7e7e7;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;}
335 | .mr_down_tip i, .mr_down_tip em {position: absolute;background: none;border: 8px solid #e7e7e7;border-color:#e7e7e7 transparent transparent;display: block;font-size: 0px;height: 0;width: 0;}
336 | .mr_down_tip i{right:2px;bottom:-16px;}
337 | .mr_down_tip em{right:12px;bottom:-15px;border-color:#fff transparent transparent;;}
338 | .mr_down_tip li{height:38px;line-height:38px;}
339 | .mr_down_tip li a{display:block;text-align:center;}
340 | .mr_down_tip li.active a{background-color:#00b88d;color:#fff;}
341 | .mr_sns_m .mr_no{background:url(http://www.lagou.com/images/myresume/icons_mr.png) -28px -46px no-repeat;}
342 | .mr_sns_m .sns_del{position:absolute;width:16px;height:16px;right:-30px;top:15px;background:url(http://www.lagou.com/images/myresume/icons_mr.png) -57px -49px no-repeat;}
343 | .mr_add_sns{position:relative;}
344 | .m_portrait{width:100%;height:135px;position:relative;z-index:2;background:url(http://www.lagou.com/images/myresume/head_bg.jpg) no-repeat;}
345 | .m_portrait .opa{position:absolute;}
346 | .mr_wo_preview ol,.mr_wu_con_m ol,.mr_self_r ol,.mr_expjob_content ol,.mr_wo_preview ul,.mr_wu_con_m ul,.mr_self_r ul,.mr_expjob_content ul{padding-left:19px;}
347 | .olpf ol,.olpf ul{padding-left:19px;}
348 | .mr_wo_preview {color:#fff;}
349 | .mr_preview .mr_title .mr_title_r{width:228px;}
350 | .resume_status {background: #f6f6f6;border: none!important;text-align: center;margin: -12px 0 0 -135px!important;cursor: default;}
351 | .m_portrait div {
352 | /* background: url(http://www.lagou.com/images/profile_cover.png) no-repeat;
353 | width: 120px;
354 | height: 120px;
355 | position: absolute;
356 | z-index: 5; */
357 | width:200px;
358 | height:132px;
359 | position:absolute;
360 | left:41%;
361 | top:39px;
362 | z-index:100;
363 | }
--------------------------------------------------------------------------------
/public/build/SignInput.d5958.chunk.js:
--------------------------------------------------------------------------------
1 | webpackJsonp([4],{329:function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var o=r(330),a=n(o);t.default=a.default,e.exports=t.default},330:function(e,t,r){(function(n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function a(e,t){for(var r=Object.getOwnPropertyNames(t),n=0;n=0||Object.prototype.hasOwnProperty.call(e,n)&&(r[n]=e[n]);return r}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function l(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!==("undefined"==typeof t?"undefined":c(t))&&"function"!=typeof t?e:t}function u(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+("undefined"==typeof t?"undefined":c(t)));e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):a(e,t))}var c="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};Object.defineProperty(t,"__esModule",{value:!0});var p=Object.assign||function(e){for(var t=1;t=1?t:1,a=(r||1)/(t<1?t:1),i=a/Math.PI*2*(Math.asin(1/o)||0);return-(o*Math.pow(2,10*(n-=1))*Math.sin((n-i)*a))},easeOutElastic:function(e,t,r){var n=t>=1?t:1,o=(r||1)/(t<1?t:1),a=o/Math.PI*2*(Math.asin(1/n)||0);return n*Math.pow(2,-10*e)*Math.sin((e-a)*o)+1},easeInOutElastic:function(e,t,r){var n=e,o=t>=1?t:1,a=(r||1)/(t<1?t:1),i=a/Math.PI*2*(Math.asin(1/o)||0);return n*=2,n<1?-.5*(o*Math.pow(2,10*(n-=1))*Math.sin((n-i)*a)):o*Math.pow(2,-10*(n-=1))*Math.sin((n-i)*a)*.5+1},easeInBounce:function(e){var t=e,r=1-t;return r<1/2.75?1-7.5625*t*t:t<2/2.75?1-(7.5625*(t-=1.5/2.75)*t+.75):t<2.5/2.75?1-(7.5625*(t-=2.25/2.75)*t+.9375):1-(7.5625*(t-=2.625/2.75)*t+.984375)},easeOutBounce:function(e){var t=e;return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},easeInOutBounce:function(e){var t=e,r=t<.5;return t=r?1-2*t:2*t-1,t<1/2.75?t*=7.5625*t:t=t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375,r?.5*(1-t):.5*t+.5}},b=void 0;"undefined"!=typeof document&&"undefined"!=typeof window?(b=r(335),Object.keys(v).forEach(function(e){b.Easings&&(b.Easings[e]=v[e])})):b=function(){var e=arguments[arguments.length-1];n(function(){return e()})};var w={easeInBack:[.6,-.28,.735,.045],easeOutBack:[.175,.885,.32,1.275],easeInOutBack:[.68,-.55,.265,1.55]},x="ant-queue-anim-placeholder-",P=function(){},S=function(e){function t(){s(this,t);var r=l(this,e.apply(this,arguments));k.call(r),r.keysToEnter=[],r.keysToLeave=[],r.keysAnimating=[],r.placeholderTimeoutIds={};var n=(0,m.toArrayChildren)((0,m.getChildrenFromProps)(r.props)),o={};return n.forEach(function(e){e&&e.key&&(r.props.appear?r.keysToEnter.push(e.key):o[e.key]=!0)}),r.originalChildren=(0,m.toArrayChildren)((0,m.getChildrenFromProps)(r.props)),r.state={children:n,childrenShow:o},r}return u(t,e),t.prototype.componentDidMount=function(){this.props.appear&&this.componentDidUpdate()},t.prototype.componentWillReceiveProps=function(e){var t=this,r=(0,m.toArrayChildren)(e.children),n=this.originalChildren,o=(0,m.mergeChildren)(n,r),a=o.length?this.state.childrenShow:{};this.keysToLeave.forEach(function(r){var n=(0,y.findDOMNode)(t.refs[r]);b(n,"stop"),e.enterForcedRePlay&&delete a[r]}),this.keysToEnter=[],this.keysToLeave=[],this.keysAnimating=[],this.setState({childrenShow:a,children:o}),r.forEach(function(e){if(e){var r=e.key,o=(0,m.findChildInChildrenByKey)(n,r);!o&&r&&t.keysToEnter.push(r)}}),n.forEach(function(e){if(e){var n=e.key,o=(0,m.findChildInChildrenByKey)(r,n);!o&&n&&t.keysToLeave.push(n)}})},t.prototype.componentDidUpdate=function(){this.originalChildren=(0,m.toArrayChildren)((0,m.getChildrenFromProps)(this.props));var e=Array.prototype.slice.call(this.keysToEnter),t=Array.prototype.slice.call(this.keysToLeave);0===this.keysAnimating.length&&(this.keysAnimating=e.concat(t)),e.forEach(this.performEnter),t.forEach(this.performLeave)},t.prototype.componentWillUnmount=function(){var e=this;[].concat(this.keysToEnter,this.keysToLeave,this.keysAnimating).forEach(function(t){return e.refs[t]&&b((0,y.findDOMNode)(e.refs[t]),"stop")}),Object.keys(this.placeholderTimeoutIds).forEach(function(t){clearTimeout(e.placeholderTimeoutIds[t])}),this.keysToEnter=[],this.keysToLeave=[],this.keysAnimating=[]},t.prototype.render=function(){var e=this,t=(0,m.toArrayChildren)(this.state.children).map(function(t){return t&&t.key?e.state.childrenShow[t.key]?(0,f.cloneElement)(t,{ref:t.key,key:t.key}):(0,f.createElement)("div",{ref:x+t.key,key:x+t.key}):t}),r=i(this.props,[]);return["component","interval","duration","delay","type","animConfig","ease","leaveReverse","animatingClassName","enterForcedRePlay","onEnd","appear"].forEach(function(e){return delete r[e]}),(0,f.createElement)(this.props.component,p({},r),t)},t}(d.default.Component),k=function(){var e=this;this.getVelocityConfig=function(t){for(var r=arguments.length,n=Array(r>1?r-1:0),o=1;o=0){s="transform";var l=i[(0,m.checkStyleName)(s)];if(l&&"none"!==l&&l.match(t)){var u=new RegExp("^.*"+t+"\\(([^\\)]+?)\\).*","i"),c=l.replace(u,"$1");r[t][1]=parseFloat(c)}}else i[t]&&parseFloat(i[t])&&(r[t][1]=parseFloat(i[t]));o(e,s,""+r[t][1]+a(t))}),r},this.performEnter=function(t,r){var n=(0,m.transformArguments)(e.props.interval,t,r)[0],o=(0,m.transformArguments)(e.props.delay,t,r)[0];e.placeholderTimeoutIds[t]=setTimeout(e.performEnterBegin.bind(e,t,r),n*r+o),e.keysToEnter.indexOf(t)>=0&&e.keysToEnter.splice(e.keysToEnter.indexOf(t),1)},this.performEnterBegin=function(t,r){var n=e.state.childrenShow;n[t]=!0,e.setState({childrenShow:n},e.realPerformEnter.bind(e,t,r))},this.realPerformEnter=function(t,r){var n=(0,y.findDOMNode)(e.refs[t]);if(n){var o=(0,m.transformArguments)(e.props.duration,t,r)[0];b(n,"stop");var a=e.props.enterForcedRePlay?e.getVelocityEnterConfig(t,r):e.getInitAnimType(n,e.getVelocityEnterConfig(t,r));e.props.enterForcedRePlay&&(n.style.visibility="hidden"),b(n,a,{duration:o,easing:e.getVelocityEasing(t,r)[0],visibility:"visible",begin:e.enterBegin.bind(e,t),complete:e.enterComplete.bind(e,t)})}},this.performLeave=function(t,r){clearTimeout(e.placeholderTimeoutIds[t]),delete e.placeholderTimeoutIds[t];var n=(0,y.findDOMNode)(e.refs[t]);if(n){var o=(0,m.transformArguments)(e.props.interval,t,r)[1],a=(0,m.transformArguments)(e.props.delay,t,r)[1],i=(0,m.transformArguments)(e.props.duration,t,r)[1],s=e.props.leaveReverse?e.keysToLeave.length-r-1:r;b(n,"stop"),n.style.visibility="visible";var l=e.getInitAnimType(n,e.getVelocityLeaveConfig(t,r));b(n,l,{delay:o*s+a,duration:i,easing:e.getVelocityEasing(t,r)[1],begin:e.leaveBegin.bind(e,t),complete:e.leaveComplete.bind(e,t)})}},this.enterBegin=function(t,r){r.forEach(function(t){var r=e.props.animatingClassName;t.className=t.className.replace(r[1],""),t.className.indexOf(r[0])===-1&&(t.className+=" "+r[0])})},this.enterComplete=function(t,r){e.keysAnimating.indexOf(t)>=0&&e.keysAnimating.splice(e.keysAnimating.indexOf(t),1),r.forEach(function(t){t.className=t.className.replace(e.props.animatingClassName[0],"").trim()}),e.props.onEnd({key:t,type:"enter"})},this.leaveBegin=function(t,r){r.forEach(function(t){var r=e.props.animatingClassName;t.className=t.className.replace(r[0],""),t.className.indexOf(r[1])===-1&&(t.className+=" "+r[1])})},this.leaveComplete=function(t,r){if(!(e.keysAnimating.indexOf(t)<0)){e.keysAnimating.splice(e.keysAnimating.indexOf(t),1);var n=e.state.childrenShow;n[t]=!1,e.keysToLeave.indexOf(t)>=0&&e.keysToLeave.splice(e.keysToLeave.indexOf(t),1);var o=e.keysToLeave.some(function(e){return n[e]});if(!o){var a=(0,m.toArrayChildren)((0,m.getChildrenFromProps)(e.props));e.setState({children:a,childrenShow:n})}r.forEach(function(t){t.className=t.className.replace(e.props.animatingClassName[1],"").trim()}),e.props.onEnd({key:t,type:"leave"})}}};S.propTypes={component:d.default.PropTypes.any,interval:d.default.PropTypes.any,duration:d.default.PropTypes.any,delay:d.default.PropTypes.any,type:d.default.PropTypes.any,animConfig:d.default.PropTypes.any,ease:d.default.PropTypes.any,leaveReverse:d.default.PropTypes.bool,enterForcedRePlay:d.default.PropTypes.bool,animatingClassName:d.default.PropTypes.array,onEnd:d.default.PropTypes.func,appear:d.default.PropTypes.bool},S.defaultProps={component:"div",interval:100,duration:450,delay:0,type:"right",animConfig:null,ease:"easeOutQuart",leaveReverse:!1,enterForcedRePlay:!1,animatingClassName:["queue-anim-entering","queue-anim-leaving"],onEnd:P,appear:!0},t.default=S,e.exports=t.default}).call(t,r(331).setImmediate)},331:function(e,t,r){"use strict";function n(e,t){this._id=e,this._clearFn=t}var o=Function.prototype.apply;t.setTimeout=function(){return new n(o.call(setTimeout,window,arguments),clearTimeout)},t.setInterval=function(){return new n(o.call(setInterval,window,arguments),clearInterval)},t.clearTimeout=t.clearInterval=function(e){e&&e.close()},n.prototype.unref=n.prototype.ref=function(){},n.prototype.close=function(){this._clearFn.call(window,this._id)},t.enroll=function(e,t){clearTimeout(e._idleTimeoutId),e._idleTimeout=t},t.unenroll=function(e){clearTimeout(e._idleTimeoutId),e._idleTimeout=-1},t._unrefActive=t.active=function(e){clearTimeout(e._idleTimeoutId);var t=e._idleTimeout;t>=0&&(e._idleTimeoutId=setTimeout(function(){e._onTimeout&&e._onTimeout()},t))},r(332),t.setImmediate=setImmediate,t.clearImmediate=clearImmediate},332:function(e,t,r){(function(e,t){"use strict";!function(e,r){function n(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),r=0;r0&&t-1 in e))}if(!e.jQuery){var r=function e(t,r){return new e.fn.init(t,r)};r.isWindow=function(e){return e&&e===e.window},r.type=function(e){return e?"object"===("undefined"==typeof e?"undefined":a(e))||"function"==typeof e?o[s.call(e)]||"object":"undefined"==typeof e?"undefined":a(e):e+""},r.isArray=Array.isArray||function(e){return"array"===r.type(e)},r.isPlainObject=function(e){var t;if(!e||"object"!==r.type(e)||e.nodeType||r.isWindow(e))return!1;try{if(e.constructor&&!i.call(e,"constructor")&&!i.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(e){return!1}for(t in e);return void 0===t||i.call(e,t)},r.each=function(e,r,n){var o,a=0,i=e.length,s=t(e);if(n){if(s)for(;a0?o=i:r=i;while(Math.abs(a)>h&&++s=g?c(t,s):0===l?s:f(t,r,r+w)}function y(){k=!0,e===r&&n===o||p()}var m=4,g=.001,h=1e-7,v=10,b=11,w=1/(b-1),x="Float32Array"in t;if(4!==arguments.length)return!1;for(var P=0;P<4;++P)if("number"!=typeof arguments[P]||isNaN(arguments[P])||!isFinite(arguments[P]))return!1;e=Math.min(e,1),n=Math.min(n,1),e=Math.max(e,0),n=Math.max(n,0);var S=x?new Float32Array(b):new Array(b),k=!1,T=function(t){return k||y(),e===r&&n===o?t:0===t?0:1===t?1:l(d(t),r,o)};T.getControlPoints=function(){return[{x:e,y:r},{x:n,y:o}]};var C="generateBezier("+[e,r,n,o]+")";return T.toString=function(){return C},T}function c(e,t){var r=e;return g.isString(e)?w.Easings[e]||(r=!1):r=g.isArray(e)&&1===e.length?l.apply(null,e):g.isArray(e)&&2===e.length?x.apply(null,e.concat([t])):!(!g.isArray(e)||4!==e.length)&&u.apply(null,e),r===!1&&(r=w.Easings[w.defaults.easing]?w.defaults.easing:b),r}function p(e){if(e){var t=w.timestamp&&e!==!0?e:(new Date).getTime(),r=w.State.calls.length;r>1e4&&(w.State.calls=o(w.State.calls),r=w.State.calls.length);for(var a=0;a4;e--){var t=r.createElement("div");if(t.innerHTML="",t.getElementsByTagName("span").length)return t=null,e}return n}(),m=function(){var e=0;return t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||function(t){var r,n=(new Date).getTime();return r=Math.max(0,16-(n-e)),e=n+r,setTimeout(function(){t(n+r)},r)}}(),g={isNumber:function(e){return"number"==typeof e},isString:function(e){return"string"==typeof e},isArray:Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},isFunction:function(e){return"[object Function]"===Object.prototype.toString.call(e)},isNode:function(e){return e&&e.nodeType},isNodeList:function(e){return"object"===("undefined"==typeof e?"undefined":a(e))&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(e))&&e.length!==n&&(0===e.length||"object"===a(e[0])&&e[0].nodeType>0)},isWrapped:function(e){return e&&(g.isArray(e)||g.isNumber(e.length)&&!g.isString(e)&&!g.isFunction(e))},isSVG:function(e){return t.SVGElement&&e instanceof t.SVGElement},isEmptyObject:function(e){for(var t in e)if(e.hasOwnProperty(t))return!1;return!0}},h=!1;if(e.fn&&e.fn.jquery?(d=e,h=!0):d=t.Velocity.Utilities,y<=8&&!h)throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity.");if(y<=7)return void(jQuery.fn.velocity=jQuery.fn.animate);var v=400,b="swing",w={State:{isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),isAndroid:/Android/i.test(navigator.userAgent),isGingerbread:/Android 2\.3\.[3-7]/i.test(navigator.userAgent),isChrome:t.chrome,isFirefox:/Firefox/i.test(navigator.userAgent),prefixElement:r.createElement("div"),prefixMatches:{},scrollAnchor:null,scrollPropertyLeft:null,scrollPropertyTop:null,isTicking:!1,calls:[]},CSS:{},Utilities:d,Redirects:{},Easings:{},Promise:t.Promise,defaults:{queue:"",duration:v,easing:b,begin:n,complete:n,progress:n,display:n,visibility:n,loop:!1,delay:!1,mobileHA:!0,_cacheValues:!0,promiseRejectEmpty:!0},init:function(e){d.data(e,"velocity",{isSVG:g.isSVG(e),isAnimating:!1,computedStyle:null,tweensContainer:null,rootPropertyValueCache:{},transformCache:{}})},hook:null,mock:!1,version:{major:1,minor:3,patch:2},debug:!1,timestamp:!0};t.pageYOffset!==n?(w.State.scrollAnchor=t,w.State.scrollPropertyLeft="pageXOffset",w.State.scrollPropertyTop="pageYOffset"):(w.State.scrollAnchor=r.documentElement||r.body.parentNode||r.body,w.State.scrollPropertyLeft="scrollLeft",w.State.scrollPropertyTop="scrollTop");var x=function(){function e(e){return-e.tension*e.x-e.friction*e.v}function t(t,r,n){var o={x:t.x+n.dx*r,v:t.v+n.dv*r,tension:t.tension,friction:t.friction};return{dx:o.v,dv:e(o)}}function r(r,n){var o={dx:r.v,dv:e(r)},a=t(r,.5*n,o),i=t(r,.5*n,a),s=t(r,n,i),l=1/6*(o.dx+2*(a.dx+i.dx)+s.dx),u=1/6*(o.dv+2*(a.dv+i.dv)+s.dv);return r.x=r.x+l*n,r.v=r.v+u*n,r}return function e(t,n,o){var a,i,s,l={x:-1,v:0,tension:null,friction:null},u=[0],c=0,p=1e-4,f=.016;for(t=parseFloat(t)||500,n=parseFloat(n)||20,o=o||null,l.tension=t,l.friction=n,a=null!==o,a?(c=e(t,n),i=c/o*f):i=f;;)if(s=r(s||l,i),u.push(1+s.x),c+=16,!(Math.abs(s.x)>p&&Math.abs(s.v)>p))break;return a?function(e){return u[e*(u.length-1)|0]}:c}}();w.Easings={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},spring:function(e){return 1-Math.cos(4.5*e*Math.PI)*Math.exp(6*-e)}},d.each([["ease",[.25,.1,.25,1]],["ease-in",[.42,0,1,1]],["ease-out",[0,0,.58,1]],["ease-in-out",[.42,0,.58,1]],["easeInSine",[.47,0,.745,.715]],["easeOutSine",[.39,.575,.565,1]],["easeInOutSine",[.445,.05,.55,.95]],["easeInQuad",[.55,.085,.68,.53]],["easeOutQuad",[.25,.46,.45,.94]],["easeInOutQuad",[.455,.03,.515,.955]],["easeInCubic",[.55,.055,.675,.19]],["easeOutCubic",[.215,.61,.355,1]],["easeInOutCubic",[.645,.045,.355,1]],["easeInQuart",[.895,.03,.685,.22]],["easeOutQuart",[.165,.84,.44,1]],["easeInOutQuart",[.77,0,.175,1]],["easeInQuint",[.755,.05,.855,.06]],["easeOutQuint",[.23,1,.32,1]],["easeInOutQuint",[.86,0,.07,1]],["easeInExpo",[.95,.05,.795,.035]],["easeOutExpo",[.19,1,.22,1]],["easeInOutExpo",[1,0,0,1]],["easeInCirc",[.6,.04,.98,.335]],["easeOutCirc",[.075,.82,.165,1]],["easeInOutCirc",[.785,.135,.15,.86]]],function(e,t){w.Easings[t[0]]=u.apply(null,t[1])});var P=w.CSS={RegEx:{isHex:/^#([A-f\d]{3}){1,2}$/i,valueUnwrap:/^[A-z]+\((.*)\)$/i,wrappedValueAlreadyExtracted:/[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/,valueSplit:/([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/gi},Lists:{colors:["fill","stroke","stopColor","color","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor"],transformsBase:["translateX","translateY","scale","scaleX","scaleY","skewX","skewY","rotateZ"],transforms3D:["transformPerspective","translateZ","scaleZ","rotateX","rotateY"]},Hooks:{templates:{textShadow:["Color X Y Blur","black 0px 0px 0px"],boxShadow:["Color X Y Blur Spread","black 0px 0px 0px 0px"],clip:["Top Right Bottom Left","0px 0px 0px 0px"],backgroundPosition:["X Y","0% 0%"],transformOrigin:["X Y Z","50% 50% 0px"],perspectiveOrigin:["X Y","50% 50%"]},registered:{},register:function(){for(var e=0;e=1?"":"alpha(opacity="+parseInt(100*parseFloat(r),10)+")"}else switch(e){case"name":return"opacity";case"extract":return r;case"inject":return r}}},register:function(){function e(e,t,r){var n="border-box"===P.getPropertyValue(t,"boxSizing").toString().toLowerCase();if(n===(r||!1)){var o,a,i=0,s="width"===e?["Left","Right"]:["Top","Bottom"],l=["padding"+s[0],"padding"+s[1],"border"+s[0]+"Width","border"+s[1]+"Width"];for(o=0;o9)||w.State.isGingerbread||(P.Lists.transformsBase=P.Lists.transformsBase.concat(P.Lists.transforms3D));for(var r=0;r8)&&3===a.split(" ").length&&(a+=" 1"),a;case"inject":return/^rgb/.test(o)?o:(y<=8?4===o.split(" ").length&&(o=o.split(/\s+/).slice(0,3).join(" ")):3===o.split(" ").length&&(o+=" 1"),(y<=8?"rgb":"rgba")+"("+o.replace(/\s+/g,",").replace(/\.(\d)+(?=,)/g,"")+")")}}}();P.Normalizations.registered.innerWidth=t("width",!0),P.Normalizations.registered.innerHeight=t("height",!0),P.Normalizations.registered.outerWidth=t("width"),P.Normalizations.registered.outerHeight=t("height")}},Names:{camelCase:function(e){return e.replace(/-(\w)/g,function(e,t){return t.toUpperCase()})},SVGAttribute:function(e){var t="width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2";return(y||w.State.isAndroid&&!w.State.isChrome)&&(t+="|transform"),new RegExp("^("+t+")$","i").test(e)},prefixCheck:function(e){if(w.State.prefixMatches[e])return[w.State.prefixMatches[e],!0];for(var t=["","Webkit","Moz","ms","O"],r=0,n=t.length;r=2&&console.log("Get "+r+": "+l),l},setPropertyValue:function(e,r,n,o,a){var i=r;if("scroll"===r)a.container?a.container["scroll"+a.direction]=n:"Left"===a.direction?t.scrollTo(n,a.alternateValue):t.scrollTo(a.alternateValue,n);else if(P.Normalizations.registered[r]&&"transform"===P.Normalizations.registered[r]("name",e))P.Normalizations.registered[r]("inject",e,n),i="transform",n=s(e).transformCache[r];else{if(P.Hooks.registered[r]){var l=r,u=P.Hooks.getRoot(r);o=o||P.getPropertyValue(e,u),n=P.Hooks.injectValue(l,n,o),r=u}if(P.Normalizations.registered[r]&&(n=P.Normalizations.registered[r]("inject",e,n),r=P.Normalizations.registered[r]("name",e)),i=P.Names.prefixCheck(r)[0],y<=8)try{e.style[i]=n}catch(e){w.debug&&console.log("Browser does not support ["+n+"] for ["+i+"]")}else{var c=s(e);c&&c.isSVG&&P.Names.SVGAttribute(r)?e.setAttribute(r,n):e.style[i]=n}w.debug>=2&&console.log("Set "+r+" ("+i+"): "+n)}return[i,n]},flushTransformCache:function(e){var t="",r=s(e);if((y||w.State.isAndroid&&!w.State.isChrome)&&r&&r.isSVG){var n=function(t){return parseFloat(P.getPropertyValue(e,t))},o={translate:[n("translateX"),n("translateY")],skewX:[n("skewX")],skewY:[n("skewY")],scale:1!==n("scale")?[n("scale"),n("scale")]:[n("scaleX"),n("scaleY")],rotate:[n("rotateZ"),0,0]};d.each(s(e).transformCache,function(e){/^translate/i.test(e)?e="translate":/^scale/i.test(e)?e="scale":/^rotate/i.test(e)&&(e="rotate"),o[e]&&(t+=e+"("+o[e].join(" ")+") ",delete o[e])})}else{var a,i;d.each(s(e).transformCache,function(r){return a=s(e).transformCache[r],"transformPerspective"===r?(i=a,!0):(9===y&&"rotateZ"===r&&(r="rotate"),void(t+=r+a+" "))}),i&&(t="perspective"+i+" "+t)}P.setPropertyValue(e,"transform",t)}};P.Hooks.register(),P.Normalizations.register(),w.hook=function(e,t,r){var o;return e=i(e),d.each(e,function(e,a){if(s(a)===n&&w.init(a),r===n)o===n&&(o=P.getPropertyValue(a,t));else{var i=P.setPropertyValue(a,t,r);"transform"===i[0]&&w.CSS.flushTransformCache(a),o=i}}),o};var S=function e(){function o(){return u?k.promise||null:y}function a(e,o){function a(a){var f,y;if(l.begin&&0===C)try{l.begin.call(h,h)}catch(e){setTimeout(function(){throw e},1)}if("scroll"===O){var m,v,S,V=/^x$/i.test(l.axis)?"Left":"Top",E=parseFloat(l.offset)||0;l.container?g.isWrapped(l.container)||g.isNode(l.container)?(l.container=l.container[0]||l.container,m=l.container["scroll"+V],S=m+d(e).position()[V.toLowerCase()]+E):l.container=null:(m=w.State.scrollAnchor[w.State["scrollProperty"+V]],v=w.State.scrollAnchor[w.State["scrollProperty"+("Left"===V?"Top":"Left")]],S=d(e).offset()[V.toLowerCase()]+E),u={scroll:{rootPropertyValue:!1,startValue:m,currentValue:m,endValue:S,unitType:"",easing:l.easing,scrollData:{container:l.container,direction:V,alternateValue:v}},element:e},w.debug&&console.log("tweensContainer (scroll): ",u.scroll,e)}else if("reverse"===O){if(f=s(e),!f)return;if(!f.tweensContainer)return void d.dequeue(e,l.queue);"none"===f.opts.display&&(f.opts.display="auto"),"hidden"===f.opts.visibility&&(f.opts.visibility="visible"),f.opts.loop=!1,f.opts.begin=null,f.opts.complete=null,x.easing||delete l.easing,x.duration||delete l.duration,l=d.extend({},f.opts,l),y=d.extend(!0,{},f?f.tweensContainer:null);for(var A in y)if(y.hasOwnProperty(A)&&"element"!==A){var N=y[A].startValue;y[A].startValue=y[A].currentValue=y[A].endValue,y[A].endValue=N,g.isEmptyObject(x)||(y[A].easing=l.easing),w.debug&&console.log("reverse tweensContainer ("+A+"): "+JSON.stringify(y[A]),e)}u=y}else if("start"===O){f=s(e),f&&f.tweensContainer&&f.isAnimating===!0&&(y=f.tweensContainer);var F=function(t,r){var n,a,i;return g.isFunction(t)&&(t=t.call(e,o,T)),g.isArray(t)?(n=t[0],!g.isArray(t[1])&&/^[\d-]/.test(t[1])||g.isFunction(t[1])||P.RegEx.isHex.test(t[1])?i=t[1]:g.isString(t[1])&&!P.RegEx.isHex.test(t[1])&&w.Easings[t[1]]||g.isArray(t[1])?(a=r?t[1]:c(t[1],l.duration),i=t[2]):i=t[1]||t[2]):n=t,r||(a=a||l.easing),g.isFunction(n)&&(n=n.call(e,o,T)),g.isFunction(i)&&(i=i.call(e,o,T)),[n||0,a,i]},j=function(o,a){var s,c=P.Hooks.getRoot(o),p=!1,m=a[0],h=a[1],v=a[2];if(!(f&&f.isSVG||"tween"===c||P.Names.prefixCheck(c)[1]!==!1||P.Normalizations.registered[c]!==n))return void(w.debug&&console.log("Skipping ["+c+"] due to a lack of browser support."));(l.display!==n&&null!==l.display&&"none"!==l.display||l.visibility!==n&&"hidden"!==l.visibility)&&/opacity|filter/.test(o)&&!v&&0!==m&&(v=0),l._cacheValues&&y&&y[o]?(v===n&&(v=y[o].endValue+y[o].unitType),p=f.rootPropertyValueCache[c]):P.Hooks.registered[o]?v===n?(p=P.getPropertyValue(e,c),v=P.getPropertyValue(e,o,p)):p=P.Hooks.templates[c][1]:v===n&&(v=P.getPropertyValue(e,o));var b,x,S,k=!1,T=function(e,t){var r,n;return n=(t||"0").toString().toLowerCase().replace(/[%A-z]+$/,function(e){return r=e,""}),r||(r=P.Values.getUnitType(e)),[n,r]};if(g.isString(v)&&g.isString(m)){s="";for(var C=0,V=0,E=[],O=[];C ',E,O,v,m),v=E,m=O,x=S=""):s=n)}s||(b=T(o,v),v=b[0],S=b[1],b=T(o,m),m=b[0].replace(/^([+-\/*])=/,function(e,t){return k=t,""}),x=b[1],v=parseFloat(v)||0,m=parseFloat(m)||0,"%"===x&&(/^(fontSize|lineHeight)$/.test(o)?(m/=100,x="em"):/^scale/.test(o)?(m/=100,x=""):/(Red|Green|Blue)$/i.test(o)&&(m=m/100*255,x="")));var R=function(){var n={myParent:e.parentNode||r.body,position:P.getPropertyValue(e,"position"),fontSize:P.getPropertyValue(e,"fontSize")},o=n.position===L.lastPosition&&n.myParent===L.lastParent,a=n.fontSize===L.lastFontSize;L.lastParent=n.myParent,L.lastPosition=n.position,L.lastFontSize=n.fontSize;var i=100,s={};if(a&&o)s.emToPx=L.lastEmToPx,s.percentToPxWidth=L.lastPercentToPxWidth,s.percentToPxHeight=L.lastPercentToPxHeight;else{var l=f&&f.isSVG?r.createElementNS("http://www.w3.org/2000/svg","rect"):r.createElement("div");w.init(l),n.myParent.appendChild(l),d.each(["overflow","overflowX","overflowY"],function(e,t){w.CSS.setPropertyValue(l,t,"hidden")}),w.CSS.setPropertyValue(l,"position",n.position),w.CSS.setPropertyValue(l,"fontSize",n.fontSize),w.CSS.setPropertyValue(l,"boxSizing","content-box"),d.each(["minWidth","maxWidth","width","minHeight","maxHeight","height"],function(e,t){w.CSS.setPropertyValue(l,t,i+"%")}),w.CSS.setPropertyValue(l,"paddingLeft",i+"em"),s.percentToPxWidth=L.lastPercentToPxWidth=(parseFloat(P.getPropertyValue(l,"width",null,!0))||1)/i,s.percentToPxHeight=L.lastPercentToPxHeight=(parseFloat(P.getPropertyValue(l,"height",null,!0))||1)/i,s.emToPx=L.lastEmToPx=(parseFloat(P.getPropertyValue(l,"paddingLeft"))||1)/i,n.myParent.removeChild(l)}return null===L.remToPx&&(L.remToPx=parseFloat(P.getPropertyValue(r.body,"fontSize"))||16),null===L.vwToPx&&(L.vwToPx=parseFloat(t.innerWidth)/100,L.vhToPx=parseFloat(t.innerHeight)/100),s.remToPx=L.remToPx,s.vwToPx=L.vwToPx,s.vhToPx=L.vhToPx,w.debug>=1&&console.log("Unit ratios: "+JSON.stringify(s),e),s};if(/[\/*]/.test(k))x=S;else if(S!==x&&0!==v)if(0===m)x=S;else{i=i||R();var H=/margin|padding|left|right|width|text|word|letter/i.test(o)||/X$/.test(o)||"x"===o?"x":"y";switch(S){case"%":v*="x"===H?i.percentToPxWidth:i.percentToPxHeight;break;case"px":break;default:v*=i[S+"ToPx"]}switch(x){case"%":v*=1/("x"===H?i.percentToPxWidth:i.percentToPxHeight);break;case"px":break;default:v*=1/i[x+"ToPx"]}}switch(k){case"+":m=v+m;break;case"-":m=v-m;break;case"*":m*=v;break;case"/":m=v/m}u[o]={rootPropertyValue:p,startValue:v,currentValue:v,endValue:m,unitType:x,easing:h},s&&(u[o].pattern=s),w.debug&&console.log("tweensContainer ("+o+"): "+JSON.stringify(u[o]),e)};for(var I in b)if(b.hasOwnProperty(I)){var R=P.Names.camelCase(I),H=F(b[I]);if(P.Lists.colors.indexOf(R)>=0){var z=H[0],q=H[1],B=H[2];if(P.RegEx.isHex.test(z)){for(var _=["Red","Green","Blue"],$=P.Values.hexToRgb(z),W=B?P.Values.hexToRgb(B):n,D=0;D<_.length;D++){var X=[$[D]];q&&X.push(q),W!==n&&X.push(W[D]),j(R+_[D],X)}continue}}j(R,H)}u.element=e}u.element&&(P.Values.addClass(e,"velocity-animating"),M.push(u),f=s(e),f&&(""===l.queue&&(f.tweensContainer=u,f.opts=l),f.isAnimating=!0),C===T-1?(w.State.calls.push([M,h,l,null,k.resolver]),w.State.isTicking===!1&&(w.State.isTicking=!0,p())):C++)}var i,l=d.extend({},w.defaults,x),u={};switch(s(e)===n&&w.init(e),parseFloat(l.delay)&&l.queue!==!1&&d.queue(e,l.queue,function(t){w.velocityQueueEntryFlag=!0,s(e).delayTimer={setTimeout:setTimeout(t,parseFloat(l.delay)),next:t}}),l.duration.toString().toLowerCase()){case"fast":l.duration=200;break;case"normal":l.duration=v;break;case"slow":l.duration=600;break;default:l.duration=parseFloat(l.duration)||1}w.mock!==!1&&(w.mock===!0?l.duration=l.delay=1:(l.duration*=parseFloat(w.mock)||1,l.delay*=parseFloat(w.mock)||1)),l.easing=c(l.easing,l.duration),l.begin&&!g.isFunction(l.begin)&&(l.begin=null),l.progress&&!g.isFunction(l.progress)&&(l.progress=null),l.complete&&!g.isFunction(l.complete)&&(l.complete=null),l.display!==n&&null!==l.display&&(l.display=l.display.toString().toLowerCase(),"auto"===l.display&&(l.display=w.CSS.Values.getDisplayType(e))),l.visibility!==n&&null!==l.visibility&&(l.visibility=l.visibility.toString().toLowerCase()),l.mobileHA=l.mobileHA&&w.State.isMobile&&!w.State.isGingerbread,l.queue===!1?l.delay?setTimeout(a,l.delay):a():d.queue(e,l.queue,function(e,t){return t===!0?(k.promise&&k.resolver(h),!0):(w.velocityQueueEntryFlag=!0,void a(e))}),""!==l.queue&&"fx"!==l.queue||"inprogress"===d.queue(e)[0]||d.dequeue(e)}var l,u,y,m,h,b,x,S=arguments[0]&&(arguments[0].p||d.isPlainObject(arguments[0].properties)&&!arguments[0].properties.names||g.isString(arguments[0].properties));g.isWrapped(this)?(u=!1,m=0,h=this,y=this):(u=!0,m=1,h=S?arguments[0].elements||arguments[0].e:arguments[0]);var k={promise:null,resolver:null,rejecter:null};if(u&&w.Promise&&(k.promise=new w.Promise(function(e,t){k.resolver=e,k.rejecter=t})),S?(b=arguments[0].properties||arguments[0].p,x=arguments[0].options||arguments[0].o):(b=arguments[m],x=arguments[m+1]),h=i(h),!h)return void(k.promise&&(b&&x&&x.promiseRejectEmpty===!1?k.resolver():k.rejecter()));var T=h.length,C=0;if(!/^(stop|finish|finishAll)$/i.test(b)&&!d.isPlainObject(x)){var V=m+1;x={};for(var E=V;E