ソースを参照

Merge branch 'master' of Hepper/comment into master

AdamFu 5 年 前
コミット
f234f159ee

+ 5
- 2
.babelrc ファイルの表示

@@ -2,6 +2,9 @@
2 2
   "presets": ["env", "react"],
3 3
   "plugins": [
4 4
     "transform-object-rest-spread",
5
-    ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
5
+    [
6
+      "import",
7
+      { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }
8
+    ]
6 9
   ]
7
-}
10
+}

+ 5
- 1
lib/components/CommentBox/index.js ファイルの表示

@@ -114,6 +114,7 @@ var CommentBox = function (_Component) {
114 114
                 replyId: item.id,
115 115
                 key: item.id,
116 116
                 content: item,
117
+                user_id: item.user_id,
117 118
                 action: "replyToReply" // 回复的回复
118 119
               }), _react2.default.createElement(
119 120
                 "div",
@@ -155,7 +156,9 @@ var CommentBox = function (_Component) {
155 156
   }, {
156 157
     key: "render",
157 158
     value: function render() {
158
-      var content = this.props.content;
159
+      var _props = this.props,
160
+          content = _props.content,
161
+          user_id = _props.user_id;
159 162
       var showReply = this.state.showReply;
160 163
 
161 164
       return _react2.default.createElement(
@@ -166,6 +169,7 @@ var CommentBox = function (_Component) {
166 169
           onShowReply: this.handleToggleReply,
167 170
           showReply: showReply,
168 171
           commentId: content.id,
172
+          user_id: user_id,
169 173
           action: "reply" // 评论的回复
170 174
         }),
171 175
         this.renderReplies(content.replies, content.reply_count, content.isNoMoreReply)

+ 1
- 1
lib/components/CommentBox/index.js.map
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 6
- 1
lib/components/CommentList/index.js ファイルの表示

@@ -144,7 +144,12 @@ var CommentList = function (_Component) {
144 144
             _reactIntlUniversal2.default.get("comment.totalComment", { total: total })
145 145
           ),
146 146
           list.map(function (item) {
147
-            return _react2.default.createElement(_CommentBox2.default, { content: item, key: item.id, commentId: item.id });
147
+            return _react2.default.createElement(_CommentBox2.default, {
148
+              content: item,
149
+              user_id: item.user_id,
150
+              key: item.id,
151
+              commentId: item.id
152
+            });
148 153
           }),
149 154
           this.renderPagination()
150 155
         )

+ 1
- 1
lib/components/CommentList/index.js.map ファイルの表示

@@ -1 +1 @@
1
-{"version":3,"sources":["../../../src/components/CommentList/index.js"],"names":["CommentList","props","state","app","sGetComment","page","list","total","pageType","limit","isNoMoreComment","onPageChange","onGetMoreBtnClick","length","intl","get","p","loading","spinning","Boolean","sCommentFavor","sReplyFavor","map","item","id","renderPagination","Component","propTypes"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;IAEMA,W;;;AACJ,uBAAYC,KAAZ,EAAmB;AAAA;;AAAA,0HACXA,KADW;;AAEjB,UAAKC,KAAL,GAAa,EAAb;AAFiB;AAGlB;;;;yCAEoB;AACnB,WAAKD,KAAL,CAAWE,GAAX,CAAeC,WAAf,CAA2B,EAAEC,MAAM,KAAKJ,KAAL,CAAWE,GAAX,CAAeE,IAAvB,EAA3B;AACD;;;uCAEkB;AAAA,uBAWb,KAAKJ,KAAL,CAAWE,GAXE;AAAA,UAEfG,IAFe,cAEfA,IAFe;AAAA,UAGfC,KAHe,cAGfA,KAHe;AAAA,UAIfF,IAJe,cAIfA,IAJe;AAAA,UAKfG,QALe,cAKfA,QALe;AAAA,UAMfC,KANe,cAMfA,KANe;AAAA,UAOfC,eAPe,cAOfA,eAPe;AAAA,UAQfN,WARe,cAQfA,WARe;AAAA,UASfO,YATe,cASfA,YATe;AAAA,UAUfC,iBAVe,cAUfA,iBAVe;;AAYjB,UAAIJ,aAAa,OAAjB,EAA0B;AACxB;AACA,eACE;AAAA;AAAA,YAAK,WAAU,wBAAf,EAAwC,SAASI,iBAAjD;AACE;AAAA;AAAA;AAAA;AAAA;AADF,SADF;AAKD,OAPD,MAOO,IAAIJ,aAAa,MAAjB,EAAyB;AAC9B,YAAI,CAACE,eAAD,IAAoBJ,KAAKO,MAAL,KAAgBN,KAAxC,EAA+C;AAC7C,iBACE;AAAA;AAAA;AACE,yBAAU,wBADZ;AAEE,uBAAS,mBAAM;AACbH,4BAAY,EAAEC,MAAMA,OAAO,CAAf,EAAZ;AACAM,6BAAaN,OAAO,CAApB;AACD;AALH;AAOE;AAAA;AAAA;AAAOS,2CAAKC,GAAL,CAAS,qBAAT;AAAP;AAPF,WADF;AAWD,SAZD,MAYO;AACL,iBAAO,IAAP;AACD;AACF,OAhBM,MAgBA,IAAIP,aAAa,YAAjB,EAA+B;AACpC,eACE;AAAA;AAAA,YAAK,WAAU,yBAAf;AACE;AACE,sBAAUC,KADZ;AAEE,qBAASJ,IAFX;AAGE,mBAAOE,KAHT;AAIE,sBAAU,qBAAK;AACbH,0BAAY,EAAEC,MAAMW,CAAR,EAAZ;AACAL,2BAAaK,CAAb;AACD;AAPH;AADF,SADF;AAaD;AACF;;;6BAEQ;AAAA,wBAC0B,KAAKf,KAAL,CAAWE,GADrC;AAAA,UACCG,IADD,eACCA,IADD;AAAA,UACOC,KADP,eACOA,KADP;AAAA,UACcU,OADd,eACcA,OADd;;;AAGP,UAAMC,WAAWC,QACfF,QAAQb,WAAR,IAAuBa,QAAQG,aAA/B,IAAgDH,QAAQI,WADzC,CAAjB;AAGA,aACE;AAAA;AAAA;AACE;AAAA;AAAA,YAAM,UAAUH,QAAhB;AAEE;AAAA;AAAA;AAAMJ,yCAAKC,GAAL,CAAS,sBAAT,EAAiC,EAAER,YAAF,EAAjC;AAAN,WAFF;AAGGD,eAAKgB,GAAL,CAAS;AAAA,mBACR,8BAAC,oBAAD,IAAY,SAASC,IAArB,EAA2B,KAAKA,KAAKC,EAArC,EAAyC,WAAWD,KAAKC,EAAzD,GADQ;AAAA,WAAT,CAHH;AAMG,eAAKC,gBAAL;AANH;AADF,OADF;AAYD;;;;EAhFuBC,gB;;AAmF1B1B,YAAY2B,SAAZ,GAAwB,EAAxB;;kBAEe,uBAAQ3B,WAAR,C","file":"index.js","sourcesContent":["import React, { Component } from \"react\";\nimport { Spin, Pagination } from \"antd\";\nimport intl from \"react-intl-universal\";\nimport Comment from \"../../Comment\";\nimport CommentBox from \"../CommentBox\";\nimport \"./index.css\";\n\nclass CommentList extends Component {\n  constructor(props) {\n    super(props);\n    this.state = {};\n  }\n\n  componentWillMount() {\n    this.props.app.sGetComment({ page: this.props.app.page });\n  }\n\n  renderPagination() {\n    const {\n      list,\n      total,\n      page,\n      pageType,\n      limit,\n      isNoMoreComment,\n      sGetComment,\n      onPageChange,\n      onGetMoreBtnClick\n    } = this.props.app;\n    if (pageType === \"slice\") {\n      // 截断多余评论,通过点击查看更多跳转\n      return (\n        <div className=\"comment-list-show-more\" onClick={onGetMoreBtnClick}>\n          <span>查看更多</span>\n        </div>\n      );\n    } else if (pageType === \"more\") {\n      if (!isNoMoreComment && list.length !== total) {\n        return (\n          <div\n            className=\"comment-list-show-more\"\n            onClick={() => {\n              sGetComment({ page: page + 1 });\n              onPageChange(page + 1);\n            }}\n          >\n            <span>{intl.get(\"comment.moreComment\")}</span>\n          </div>\n        );\n      } else {\n        return null;\n      }\n    } else if (pageType === \"pagination\") {\n      return (\n        <div className=\"comment-list-pagination\">\n          <Pagination\n            pageSize={limit}\n            current={page}\n            total={total}\n            onChange={p => {\n              sGetComment({ page: p });\n              onPageChange(p);\n            }}\n          />\n        </div>\n      );\n    }\n  }\n\n  render() {\n    const { list, total, loading } = this.props.app;\n\n    const spinning = Boolean(\n      loading.sGetComment || loading.sCommentFavor || loading.sReplyFavor\n    );\n    return (\n      <div>\n        <Spin spinning={spinning}>\n          {/* <div>共 {total} 条评论</div> */}\n          <div>{intl.get(\"comment.totalComment\", { total })}</div>\n          {list.map(item => (\n            <CommentBox content={item} key={item.id} commentId={item.id} />\n          ))}\n          {this.renderPagination()}\n        </Spin>\n      </div>\n    );\n  }\n}\n\nCommentList.propTypes = {};\n\nexport default Comment(CommentList);\n"]}
1
+{"version":3,"sources":["../../../src/components/CommentList/index.js"],"names":["CommentList","props","state","app","sGetComment","page","list","total","pageType","limit","isNoMoreComment","onPageChange","onGetMoreBtnClick","length","intl","get","p","loading","spinning","Boolean","sCommentFavor","sReplyFavor","map","item","user_id","id","renderPagination","Component","propTypes"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;IAEMA,W;;;AACJ,uBAAYC,KAAZ,EAAmB;AAAA;;AAAA,0HACXA,KADW;;AAEjB,UAAKC,KAAL,GAAa,EAAb;AAFiB;AAGlB;;;;yCAEoB;AACnB,WAAKD,KAAL,CAAWE,GAAX,CAAeC,WAAf,CAA2B,EAAEC,MAAM,KAAKJ,KAAL,CAAWE,GAAX,CAAeE,IAAvB,EAA3B;AACD;;;uCAEkB;AAAA,uBAWb,KAAKJ,KAAL,CAAWE,GAXE;AAAA,UAEfG,IAFe,cAEfA,IAFe;AAAA,UAGfC,KAHe,cAGfA,KAHe;AAAA,UAIfF,IAJe,cAIfA,IAJe;AAAA,UAKfG,QALe,cAKfA,QALe;AAAA,UAMfC,KANe,cAMfA,KANe;AAAA,UAOfC,eAPe,cAOfA,eAPe;AAAA,UAQfN,WARe,cAQfA,WARe;AAAA,UASfO,YATe,cASfA,YATe;AAAA,UAUfC,iBAVe,cAUfA,iBAVe;;AAYjB,UAAIJ,aAAa,OAAjB,EAA0B;AACxB;AACA,eACE;AAAA;AAAA,YAAK,WAAU,wBAAf,EAAwC,SAASI,iBAAjD;AACE;AAAA;AAAA;AAAA;AAAA;AADF,SADF;AAKD,OAPD,MAOO,IAAIJ,aAAa,MAAjB,EAAyB;AAC9B,YAAI,CAACE,eAAD,IAAoBJ,KAAKO,MAAL,KAAgBN,KAAxC,EAA+C;AAC7C,iBACE;AAAA;AAAA;AACE,yBAAU,wBADZ;AAEE,uBAAS,mBAAM;AACbH,4BAAY,EAAEC,MAAMA,OAAO,CAAf,EAAZ;AACAM,6BAAaN,OAAO,CAApB;AACD;AALH;AAOE;AAAA;AAAA;AAAOS,2CAAKC,GAAL,CAAS,qBAAT;AAAP;AAPF,WADF;AAWD,SAZD,MAYO;AACL,iBAAO,IAAP;AACD;AACF,OAhBM,MAgBA,IAAIP,aAAa,YAAjB,EAA+B;AACpC,eACE;AAAA;AAAA,YAAK,WAAU,yBAAf;AACE;AACE,sBAAUC,KADZ;AAEE,qBAASJ,IAFX;AAGE,mBAAOE,KAHT;AAIE,sBAAU,qBAAK;AACbH,0BAAY,EAAEC,MAAMW,CAAR,EAAZ;AACAL,2BAAaK,CAAb;AACD;AAPH;AADF,SADF;AAaD;AACF;;;6BAEQ;AAAA,wBAC0B,KAAKf,KAAL,CAAWE,GADrC;AAAA,UACCG,IADD,eACCA,IADD;AAAA,UACOC,KADP,eACOA,KADP;AAAA,UACcU,OADd,eACcA,OADd;;;AAGP,UAAMC,WAAWC,QACfF,QAAQb,WAAR,IAAuBa,QAAQG,aAA/B,IAAgDH,QAAQI,WADzC,CAAjB;AAGA,aACE;AAAA;AAAA;AACE;AAAA;AAAA,YAAM,UAAUH,QAAhB;AAEE;AAAA;AAAA;AAAMJ,yCAAKC,GAAL,CAAS,sBAAT,EAAiC,EAAER,YAAF,EAAjC;AAAN,WAFF;AAGGD,eAAKgB,GAAL,CAAS;AAAA,mBACR,8BAAC,oBAAD;AACE,uBAASC,IADX;AAEE,uBAASA,KAAKC,OAFhB;AAGE,mBAAKD,KAAKE,EAHZ;AAIE,yBAAWF,KAAKE;AAJlB,cADQ;AAAA,WAAT,CAHH;AAWG,eAAKC,gBAAL;AAXH;AADF,OADF;AAiBD;;;;EArFuBC,gB;;AAwF1B3B,YAAY4B,SAAZ,GAAwB,EAAxB;;kBAEe,uBAAQ5B,WAAR,C","file":"index.js","sourcesContent":["import React, { Component } from \"react\";\nimport { Spin, Pagination } from \"antd\";\nimport intl from \"react-intl-universal\";\nimport Comment from \"../../Comment\";\nimport CommentBox from \"../CommentBox\";\nimport \"./index.css\";\n\nclass CommentList extends Component {\n  constructor(props) {\n    super(props);\n    this.state = {};\n  }\n\n  componentWillMount() {\n    this.props.app.sGetComment({ page: this.props.app.page });\n  }\n\n  renderPagination() {\n    const {\n      list,\n      total,\n      page,\n      pageType,\n      limit,\n      isNoMoreComment,\n      sGetComment,\n      onPageChange,\n      onGetMoreBtnClick\n    } = this.props.app;\n    if (pageType === \"slice\") {\n      // 截断多余评论,通过点击查看更多跳转\n      return (\n        <div className=\"comment-list-show-more\" onClick={onGetMoreBtnClick}>\n          <span>查看更多</span>\n        </div>\n      );\n    } else if (pageType === \"more\") {\n      if (!isNoMoreComment && list.length !== total) {\n        return (\n          <div\n            className=\"comment-list-show-more\"\n            onClick={() => {\n              sGetComment({ page: page + 1 });\n              onPageChange(page + 1);\n            }}\n          >\n            <span>{intl.get(\"comment.moreComment\")}</span>\n          </div>\n        );\n      } else {\n        return null;\n      }\n    } else if (pageType === \"pagination\") {\n      return (\n        <div className=\"comment-list-pagination\">\n          <Pagination\n            pageSize={limit}\n            current={page}\n            total={total}\n            onChange={p => {\n              sGetComment({ page: p });\n              onPageChange(p);\n            }}\n          />\n        </div>\n      );\n    }\n  }\n\n  render() {\n    const { list, total, loading } = this.props.app;\n\n    const spinning = Boolean(\n      loading.sGetComment || loading.sCommentFavor || loading.sReplyFavor\n    );\n    return (\n      <div>\n        <Spin spinning={spinning}>\n          {/* <div>共 {total} 条评论</div> */}\n          <div>{intl.get(\"comment.totalComment\", { total })}</div>\n          {list.map(item => (\n            <CommentBox\n              content={item}\n              user_id={item.user_id}\n              key={item.id}\n              commentId={item.id}\n            />\n          ))}\n          {this.renderPagination()}\n        </Spin>\n      </div>\n    );\n  }\n}\n\nCommentList.propTypes = {};\n\nexport default Comment(CommentList);\n"]}

+ 178
- 0
lib/components/ContentItem/AvatarHoverCard.js ファイルの表示

@@ -0,0 +1,178 @@
1
+"use strict";
2
+
3
+Object.defineProperty(exports, "__esModule", {
4
+  value: true
5
+});
6
+
7
+var _col = require("antd/es/col");
8
+
9
+var _col2 = _interopRequireDefault(_col);
10
+
11
+var _row = require("antd/es/row");
12
+
13
+var _row2 = _interopRequireDefault(_row);
14
+
15
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
16
+
17
+require("antd/es/col/style/css");
18
+
19
+require("antd/es/row/style/css");
20
+
21
+var _react = require("react");
22
+
23
+var _react2 = _interopRequireDefault(_react);
24
+
25
+var _reactIntlUniversal = require("react-intl-universal");
26
+
27
+var _reactIntlUniversal2 = _interopRequireDefault(_reactIntlUniversal);
28
+
29
+require("./AvatarHoverCard.less");
30
+
31
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
32
+
33
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
34
+
35
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
36
+
37
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
38
+
39
+var AvatarHoverCard = function (_Component) {
40
+  _inherits(AvatarHoverCard, _Component);
41
+
42
+  function AvatarHoverCard(props) {
43
+    _classCallCheck(this, AvatarHoverCard);
44
+
45
+    var _this = _possibleConstructorReturn(this, (AvatarHoverCard.__proto__ || Object.getPrototypeOf(AvatarHoverCard)).call(this, props));
46
+
47
+    _this.state = {
48
+      showModal: false
49
+    };
50
+    return _this;
51
+  }
52
+
53
+  _createClass(AvatarHoverCard, [{
54
+    key: "componentDidMount",
55
+    value: function componentDidMount() {
56
+      this.props.getUserInfo({
57
+        id: this.props.user_id
58
+      });
59
+    }
60
+  }, {
61
+    key: "render",
62
+    value: function render() {
63
+      var _this2 = this;
64
+
65
+      var _props = this.props,
66
+          image = _props.image,
67
+          user_id = _props.user_id,
68
+          currentUser = _props.currentUser,
69
+          userAvaHoverData = _props.userAvaHoverData;
70
+
71
+      var followed = userAvaHoverData[user_id] && userAvaHoverData[user_id].isFollowed;
72
+
73
+      return _react2.default.createElement(
74
+        "div",
75
+        { className: "AvatarHoverCard", onClick: function onClick(e) {
76
+            return e.stopPropagation();
77
+          } },
78
+        _react2.default.createElement(
79
+          "div",
80
+          { onClick: this.props.userAvaClick },
81
+          _react2.default.createElement(
82
+            _row2.default,
83
+            { type: "flex", className: "rowUser" },
84
+            _react2.default.createElement("div", {
85
+              className: "avatar",
86
+              style: {
87
+                backgroundImage: "url(" + image + ")"
88
+              }
89
+            }),
90
+            _react2.default.createElement(
91
+              "div",
92
+              { className: "nickname" },
93
+              userAvaHoverData[user_id] && userAvaHoverData[user_id].nickname
94
+            )
95
+          )
96
+        ),
97
+        _react2.default.createElement("div", { className: "divider" }),
98
+        _react2.default.createElement(
99
+          _row2.default,
100
+          { type: "flex", className: "rowNum" },
101
+          _react2.default.createElement(
102
+            _col2.default,
103
+            { className: "colFans" },
104
+            _react2.default.createElement(
105
+              "div",
106
+              { className: "count" },
107
+              userAvaHoverData[user_id] && userAvaHoverData[user_id].fans
108
+            ),
109
+            _react2.default.createElement(
110
+              "div",
111
+              { className: "text" },
112
+              _reactIntlUniversal2.default.get("bilingually.fan", {
113
+                ext: userAvaHoverData[user_id] && userAvaHoverData[user_id].fans > 1 ? "s" : ""
114
+              })
115
+            )
116
+          ),
117
+          _react2.default.createElement(_col2.default, { className: "hdivider" }),
118
+          _react2.default.createElement(
119
+            _col2.default,
120
+            { className: "colFollow" },
121
+            _react2.default.createElement(
122
+              "div",
123
+              { className: "count" },
124
+              userAvaHoverData[user_id] && userAvaHoverData[user_id].followers
125
+            ),
126
+            _react2.default.createElement(
127
+              "div",
128
+              { className: "text" },
129
+              _reactIntlUniversal2.default.get("bilingually.follow", {
130
+                ext: userAvaHoverData[user_id] && userAvaHoverData[user_id].followers > 1 ? "s" : ""
131
+              })
132
+            )
133
+          )
134
+        ),
135
+        currentUser.user_id !== user_id && _react2.default.createElement(
136
+          _row2.default,
137
+          { type: "flex", className: "rowBtn" },
138
+          followed ? _react2.default.createElement(
139
+            "div",
140
+            {
141
+              className: "unFollowBtn",
142
+              onClick: function onClick(e) {
143
+                e.stopPropagation();
144
+                _this2.props.unFocus({
145
+                  id: user_id
146
+                }).then(function () {
147
+                  _this2.props.getUserInfo({
148
+                    id: user_id
149
+                  });
150
+                });
151
+              }
152
+            },
153
+            _reactIntlUniversal2.default.get("bilingually.cancel_follow")
154
+          ) : _react2.default.createElement(
155
+            "div",
156
+            {
157
+              className: "followBtn",
158
+              onClick: function onClick(e) {
159
+                e.stopPropagation();
160
+                _this2.props.focus({ id: user_id }).then(function () {
161
+                  _this2.props.getUserInfo({
162
+                    id: user_id
163
+                  });
164
+                });
165
+              }
166
+            },
167
+            _reactIntlUniversal2.default.get("bilingually.follow", { ext: "" })
168
+          )
169
+        )
170
+      );
171
+    }
172
+  }]);
173
+
174
+  return AvatarHoverCard;
175
+}(_react.Component);
176
+
177
+exports.default = AvatarHoverCard;
178
+//# sourceMappingURL=AvatarHoverCard.js.map

+ 1
- 0
lib/components/ContentItem/AvatarHoverCard.js.map
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 146
- 0
lib/components/ContentItem/AvatarHoverCard.less ファイルの表示

@@ -0,0 +1,146 @@
1
+.AvatarHoverCard {
2
+  width: 260px;
3
+  padding: 14px 18px;
4
+}
5
+
6
+.rowUser {
7
+  align-items: center;
8
+}
9
+.avatar {
10
+  width: 48px;
11
+  height: 48px;
12
+  border-radius: 24px;
13
+  background-position: center;
14
+  background-size: cover;
15
+}
16
+.nickname {
17
+  font-size: 16px;
18
+  color: rgba(58, 58, 58, 1);
19
+  margin-left: 14px;
20
+}
21
+.divider {
22
+  height: 1px;
23
+  background: #e2e2e2;
24
+  margin: 12px 0;
25
+}
26
+.rowNum {
27
+  height: 45px;
28
+  align-items: center;
29
+}
30
+.colFans,
31
+.colFollow {
32
+  flex: 1;
33
+  text-align: center;
34
+  .count {
35
+    font-size: 17px;
36
+    font-weight: 500;
37
+    color: rgba(5, 18, 11, 1);
38
+  }
39
+  .text {
40
+    font-size: 14px;
41
+    font-weight: 400;
42
+    color: rgba(140, 140, 140, 1);
43
+  }
44
+}
45
+.hdivider {
46
+  width: 1px;
47
+  height: 25px;
48
+  background: #e2e2e2;
49
+}
50
+.rowBtn {
51
+  margin-top: 14px;
52
+  margin-bottom: 10px;
53
+  justify-content: space-around;
54
+}
55
+.followBtn,
56
+.unFollowBtn,
57
+.privateMessageBtn {
58
+  width: 77px;
59
+  height: 31px;
60
+  line-height: 31px;
61
+  background: rgba(113, 193, 53, 1);
62
+  border-radius: 4px;
63
+  color: #fff;
64
+  font-size: 12px;
65
+  font-weight: 500;
66
+  text-align: center;
67
+  cursor: pointer;
68
+  margin: 0 5px;
69
+}
70
+
71
+.followBtn {
72
+  border: 1px solid rgba(113, 193, 53, 1);
73
+  color: rgba(113, 193, 53, 1);
74
+  background: #fff;
75
+}
76
+.unFollowBtn {
77
+  color: #fff;
78
+  background: rgba(113, 193, 53, 1);
79
+  border: 1px solid rgba(113, 193, 53, 1);
80
+}
81
+
82
+.modalContainer {
83
+  background: #fff;
84
+  padding: 20px;
85
+}
86
+
87
+.modalTitle {
88
+  color: #3a3a3a;
89
+  margin-left: 8px;
90
+  margin-bottom: 12px;
91
+  font-weight: 500;
92
+}
93
+
94
+.modalClose {
95
+  position: absolute;
96
+  top: 15px;
97
+  right: 15px;
98
+  font-size: 12px;
99
+}
100
+
101
+.nextComment {
102
+  width: 510px;
103
+  padding: 0;
104
+}
105
+.expressionBtnWrap,
106
+.pictureBtnWrap {
107
+  float: left;
108
+  width: 70px;
109
+  margin-top: 5px;
110
+  cursor: pointer;
111
+  .icon {
112
+    float: left;
113
+    color: #ffa405;
114
+    font-size: 18px !important;
115
+    margin: 0 !important;
116
+  }
117
+  .text {
118
+    float: left;
119
+    font-size: 12px;
120
+    color: #393939;
121
+    margin-left: 6px;
122
+  }
123
+}
124
+
125
+.btnGroup {
126
+  display: flex;
127
+}
128
+
129
+.cancelBtn,
130
+.submitBtn {
131
+  width: 77px;
132
+  height: 31px;
133
+  line-height: 31px;
134
+  background: rgba(113, 193, 53, 1);
135
+  border-radius: 4px;
136
+  color: #fff;
137
+  font-size: 12px;
138
+  font-weight: 500;
139
+  text-align: center;
140
+  cursor: pointer;
141
+}
142
+.cancelBtn {
143
+  background: #e9e9e9;
144
+  color: #6d6d6d;
145
+  margin-right: 12px;
146
+}

+ 11
- 0
lib/components/ContentItem/index.css ファイルの表示

@@ -22,6 +22,7 @@
22 22
   border-radius: 20px;
23 23
   background-position: center;
24 24
   background-size: cover;
25
+  cursor: pointer;
25 26
 }
26 27
 .comment-item-content {
27 28
   margin: 10px 0;
@@ -87,6 +88,16 @@
87 88
   margin-right: 10px;
88 89
 }
89 90
 
91
+.avatar-hover-card-overlay {
92
+  padding-top: 0;
93
+}
94
+.avatar-hover-card-overlay .ant-popover-inner-content {
95
+  padding: 0;
96
+}
97
+.avatar-hover-card-overlay .ant-popover-arrow {
98
+  display: none;
99
+}
100
+
90 101
 @media screen and (max-width: 616px) and (min-width: 449px) {
91 102
   .comment-item-right {
92 103
     display: inline-block;

+ 61
- 5
lib/components/ContentItem/index.js ファイルの表示

@@ -16,6 +16,12 @@ var _tooltip = require("antd/es/tooltip");
16 16
 
17 17
 var _tooltip2 = _interopRequireDefault(_tooltip);
18 18
 
19
+var _popover = require("antd/es/popover");
20
+
21
+var _popover2 = _interopRequireDefault(_popover);
22
+
23
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
24
+
19 25
 var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
20 26
 
21 27
 require("antd/es/popconfirm/style/css");
@@ -24,6 +30,8 @@ require("antd/es/icon/style/css");
24 30
 
25 31
 require("antd/es/tooltip/style/css");
26 32
 
33
+require("antd/es/popover/style/css");
34
+
27 35
 var _react = require("react");
28 36
 
29 37
 var _react2 = _interopRequireDefault(_react);
@@ -46,6 +54,10 @@ var _reactIntlUniversal = require("react-intl-universal");
46 54
 
47 55
 var _reactIntlUniversal2 = _interopRequireDefault(_reactIntlUniversal);
48 56
 
57
+var _AvatarHoverCard = require("./AvatarHoverCard");
58
+
59
+var _AvatarHoverCard2 = _interopRequireDefault(_AvatarHoverCard);
60
+
49 61
 var _Comment = require("../../Comment");
50 62
 
51 63
 var _Comment2 = _interopRequireDefault(_Comment);
@@ -98,12 +110,14 @@ var CommentItem = function (_Component) {
98 110
     _this.state = {
99 111
       showInput: false,
100 112
       showPreviewer: false,
101
-      previewerIndex: 0
113
+      previewerIndex: 0,
114
+      popoverVisible: false
102 115
     };
103 116
     _this.handleToggleInput = _this.handleToggleInput.bind(_this);
104 117
     _this.renderTextWithReply = _this.renderTextWithReply.bind(_this);
105 118
     _this.showPreviewer = _this.showPreviewer.bind(_this);
106 119
     _this.hidePreviewer = _this.hidePreviewer.bind(_this);
120
+    _this.handleVisibleChange = _this.handleVisibleChange.bind(_this);
107 121
     return _this;
108 122
   }
109 123
 
@@ -127,6 +141,13 @@ var CommentItem = function (_Component) {
127 141
     value: function handleToggleInput() {
128 142
       this.setState({ showInput: !this.state.showInput });
129 143
     }
144
+  }, {
145
+    key: "handleVisibleChange",
146
+    value: function handleVisibleChange(visible) {
147
+      this.setState({
148
+        popoverVisible: visible
149
+      });
150
+    }
130 151
   }, {
131 152
     key: "renderTextWithReply",
132 153
     value: function renderTextWithReply(text, content) {
@@ -162,8 +183,12 @@ var CommentItem = function (_Component) {
162 183
           action = _props.action,
163 184
           showReply = _props.showReply,
164 185
           onShowReply = _props.onShowReply,
165
-          app = _props.app;
166
-      var locale = this.props.app.locale;
186
+          app = _props.app,
187
+          user_id = _props.user_id;
188
+      var _props$app = this.props.app,
189
+          locale = _props$app.locale,
190
+          userAvaClick = _props$app.userAvaClick,
191
+          showHoverCard = _props$app.showHoverCard;
167 192
       var showInput = this.state.showInput;
168 193
 
169 194
 
@@ -196,10 +221,36 @@ var CommentItem = function (_Component) {
196 221
         _react2.default.createElement(
197 222
           "div",
198 223
           { className: "comment-item-left" },
199
-          _react2.default.createElement("div", {
224
+          showHoverCard ? _react2.default.createElement(
225
+            _popover2.default,
226
+            {
227
+              content: _react2.default.createElement(_AvatarHoverCard2.default, _extends({}, this.props.app, {
228
+                user_id: user_id,
229
+                handleVisibleChange: this.handleVisibleChange,
230
+                image: content.user_avatar || _avatar2.default
231
+              }))
232
+              // placement={this.props.placement}
233
+              // trigger="click"
234
+              , visible: this.state.popoverVisible,
235
+              onVisibleChange: this.handleVisibleChange,
236
+              overlayClassName: "avatar-hover-card-overlay"
237
+            },
238
+            _react2.default.createElement("div", {
239
+              className: "comment-item-avatar",
240
+              style: {
241
+                backgroundImage: "url(" + (content.user_avatar || _avatar2.default) + ")"
242
+              },
243
+              onClick: function onClick() {
244
+                return userAvaClick(user_id);
245
+              }
246
+            })
247
+          ) : _react2.default.createElement("div", {
200 248
             className: "comment-item-avatar",
201 249
             style: {
202 250
               backgroundImage: "url(" + (content.user_avatar || _avatar2.default) + ")"
251
+            },
252
+            onClick: function onClick() {
253
+              userAvaClick(user_id);
203 254
             }
204 255
           })
205 256
         ),
@@ -211,7 +262,12 @@ var CommentItem = function (_Component) {
211 262
             null,
212 263
             _react2.default.createElement(
213 264
               "strong",
214
-              null,
265
+              {
266
+                onClick: function onClick() {
267
+                  return userAvaClick(user_id);
268
+                },
269
+                style: { cursor: "pointer" }
270
+              },
215 271
               content.user_name || _reactIntlUniversal2.default.get("comment.tourist")
216 272
             ),
217 273
             _react2.default.createElement(

+ 1
- 1
lib/components/ContentItem/index.js.map
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 43
- 0
lib/index.js ファイルの表示

@@ -112,6 +112,49 @@ if (process.env.NODE_ENV !== "production") {
112 112
     businessId: "test",
113 113
     businessUserId: 4,
114 114
     userId: 71299,
115
+    currentUser: {
116
+      user_id: 71748
117
+    },
118
+    userAvaHoverData: {
119
+      71763: {
120
+        nickname: "aaa",
121
+        followers: 20,
122
+        fans: 2,
123
+        isFollowed: true
124
+      },
125
+      71748: {
126
+        nickname: "L0",
127
+        followers: 10,
128
+        fans: 11,
129
+        isFollowed: false
130
+      },
131
+      71299: {
132
+        nickname: "narro",
133
+        followers: 10,
134
+        fans: 11,
135
+        isFollowed: false
136
+      }
137
+    },
138
+    showHoverCard: true,
139
+    userAvaClick: function userAvaClick(id) {
140
+      console.log("userAvaClick", id);
141
+    },
142
+    getUserInfo: function getUserInfo(id) {
143
+      console.log("getinfo:", id);
144
+    },
145
+    focus: function focus(id) {
146
+      return new Promise(function (resolve, reject) {
147
+        console.log("focus:", id);
148
+        resolve();
149
+      });
150
+    },
151
+    unFocus: function unFocus(id) {
152
+      return new Promise(function (resolve, reject) {
153
+        console.log("unFocus:", id);
154
+        resolve();
155
+      });
156
+    },
157
+
115 158
     onCountChange: function onCountChange(c) {
116 159
       console.log(c);
117 160
     },

+ 1
- 1
lib/index.js.map
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 3
- 3
lib/version.json ファイルの表示

@@ -1,8 +1,8 @@
1 1
 {
2 2
     "name":       "comment",
3
-    "buildDate":  1561545661645,
3
+    "buildDate":  1562073871881,
4 4
     "version":    "1.0.4",
5
-    "numCommits": 156,
6
-    "hash":       "b06e101",
5
+    "numCommits": 158,
6
+    "hash":       "1b15efb",
7 7
     "dirty":      true
8 8
 }

+ 1
- 0
package.json ファイルの表示

@@ -46,6 +46,7 @@
46 46
     "babel-plugin-import": "^1.8.0",
47 47
     "babel-plugin-transform-object-rest-spread": "^6.26.0",
48 48
     "babel-preset-env": "^1.7.0",
49
+    "babel-preset-es2015": "^6.24.1",
49 50
     "babel-preset-react": "^6.24.1",
50 51
     "husky": "^0.14.3",
51 52
     "lint-staged": "^7.2.0",

+ 3
- 1
src/components/CommentBox/index.js ファイルの表示

@@ -58,6 +58,7 @@ class CommentBox extends Component {
58 58
                   replyId={item.id}
59 59
                   key={item.id}
60 60
                   content={item}
61
+                  user_id={item.user_id}
61 62
                   action="replyToReply" // 回复的回复
62 63
                 />,
63 64
                 <div className="comment-more-box" key="show_more_button">
@@ -96,7 +97,7 @@ class CommentBox extends Component {
96 97
   }
97 98
 
98 99
   render() {
99
-    const { content } = this.props;
100
+    const { content, user_id } = this.props;
100 101
     const { showReply } = this.state;
101 102
     return (
102 103
       <div>
@@ -105,6 +106,7 @@ class CommentBox extends Component {
105 106
           onShowReply={this.handleToggleReply}
106 107
           showReply={showReply}
107 108
           commentId={content.id}
109
+          user_id={user_id}
108 110
           action="reply" // 评论的回复
109 111
         />
110 112
         {this.renderReplies(

+ 6
- 1
src/components/CommentList/index.js ファイルの表示

@@ -79,7 +79,12 @@ class CommentList extends Component {
79 79
           {/* <div>共 {total} 条评论</div> */}
80 80
           <div>{intl.get("comment.totalComment", { total })}</div>
81 81
           {list.map(item => (
82
-            <CommentBox content={item} key={item.id} commentId={item.id} />
82
+            <CommentBox
83
+              content={item}
84
+              user_id={item.user_id}
85
+              key={item.id}
86
+              commentId={item.id}
87
+            />
83 88
           ))}
84 89
           {this.renderPagination()}
85 90
         </Spin>

+ 124
- 0
src/components/ContentItem/AvatarHoverCard.js ファイルの表示

@@ -0,0 +1,124 @@
1
+import React, { Component } from "react";
2
+import { Row, Col } from "antd";
3
+import intl from "react-intl-universal";
4
+import "./AvatarHoverCard.less";
5
+
6
+class AvatarHoverCard extends Component {
7
+  constructor(props) {
8
+    super(props);
9
+    this.state = {
10
+      showModal: false
11
+    };
12
+  }
13
+
14
+  componentDidMount() {
15
+    this.props.getUserInfo({
16
+      id: this.props.user_id
17
+    });
18
+  }
19
+
20
+  render() {
21
+    const { image, user_id, currentUser, userAvaHoverData } = this.props;
22
+    const followed =
23
+      userAvaHoverData[user_id] && userAvaHoverData[user_id].isFollowed;
24
+
25
+    return (
26
+      <div className="AvatarHoverCard" onClick={e => e.stopPropagation()}>
27
+        {/* <Link to={`/bilingual/user/${user_id}`}> */}
28
+        <div onClick={this.props.userAvaClick}>
29
+          <Row type="flex" className="rowUser">
30
+            <div
31
+              className="avatar"
32
+              style={{
33
+                backgroundImage: `url(${image})`
34
+              }}
35
+            />
36
+            <div className="nickname">
37
+              {userAvaHoverData[user_id] && userAvaHoverData[user_id].nickname}
38
+            </div>
39
+          </Row>
40
+        </div>
41
+        {/* </Link> */}
42
+        <div className="divider" />
43
+        <Row type="flex" className="rowNum">
44
+          <Col className="colFans">
45
+            <div className="count">
46
+              {userAvaHoverData[user_id] && userAvaHoverData[user_id].fans}
47
+            </div>
48
+            <div className="text">
49
+              {intl.get("bilingually.fan", {
50
+                ext:
51
+                  userAvaHoverData[user_id] &&
52
+                  userAvaHoverData[user_id].fans > 1
53
+                    ? "s"
54
+                    : ""
55
+              })}
56
+            </div>
57
+          </Col>
58
+          <Col className="hdivider" />
59
+          <Col className="colFollow">
60
+            <div className="count">
61
+              {userAvaHoverData[user_id] && userAvaHoverData[user_id].followers}
62
+            </div>
63
+            <div className="text">
64
+              {intl.get("bilingually.follow", {
65
+                ext:
66
+                  userAvaHoverData[user_id] &&
67
+                  userAvaHoverData[user_id].followers > 1
68
+                    ? "s"
69
+                    : ""
70
+              })}
71
+            </div>
72
+          </Col>
73
+        </Row>
74
+        {currentUser.user_id !== user_id && (
75
+          <Row type="flex" className="rowBtn">
76
+            {followed ? (
77
+              <div
78
+                className="unFollowBtn"
79
+                onClick={e => {
80
+                  e.stopPropagation();
81
+                  this.props
82
+                    .unFocus({
83
+                      id: user_id
84
+                    })
85
+                    .then(() => {
86
+                      this.props.getUserInfo({
87
+                        id: user_id
88
+                      });
89
+                    });
90
+                }}
91
+              >
92
+                {intl.get("bilingually.cancel_follow")}
93
+              </div>
94
+            ) : (
95
+              <div
96
+                className="followBtn"
97
+                onClick={e => {
98
+                  e.stopPropagation();
99
+                  this.props.focus({ id: user_id }).then(() => {
100
+                    this.props.getUserInfo({
101
+                      id: user_id
102
+                    });
103
+                  });
104
+                }}
105
+              >
106
+                {intl.get("bilingually.follow", { ext: "" })}
107
+              </div>
108
+            )}
109
+
110
+            {/* 发私信按钮,暂时隐藏 */}
111
+            {/* <div
112
+            className={styles.privateMessageBtn}
113
+            onClick={this.toggleShowModal}
114
+          >
115
+            发私信
116
+          </div> */}
117
+          </Row>
118
+        )}
119
+      </div>
120
+    );
121
+  }
122
+}
123
+
124
+export default AvatarHoverCard;

+ 146
- 0
src/components/ContentItem/AvatarHoverCard.less ファイルの表示

@@ -0,0 +1,146 @@
1
+.AvatarHoverCard {
2
+  width: 260px;
3
+  padding: 14px 18px;
4
+}
5
+
6
+.rowUser {
7
+  align-items: center;
8
+}
9
+.avatar {
10
+  width: 48px;
11
+  height: 48px;
12
+  border-radius: 24px;
13
+  background-position: center;
14
+  background-size: cover;
15
+}
16
+.nickname {
17
+  font-size: 16px;
18
+  color: rgba(58, 58, 58, 1);
19
+  margin-left: 14px;
20
+}
21
+.divider {
22
+  height: 1px;
23
+  background: #e2e2e2;
24
+  margin: 12px 0;
25
+}
26
+.rowNum {
27
+  height: 45px;
28
+  align-items: center;
29
+}
30
+.colFans,
31
+.colFollow {
32
+  flex: 1;
33
+  text-align: center;
34
+  .count {
35
+    font-size: 17px;
36
+    font-weight: 500;
37
+    color: rgba(5, 18, 11, 1);
38
+  }
39
+  .text {
40
+    font-size: 14px;
41
+    font-weight: 400;
42
+    color: rgba(140, 140, 140, 1);
43
+  }
44
+}
45
+.hdivider {
46
+  width: 1px;
47
+  height: 25px;
48
+  background: #e2e2e2;
49
+}
50
+.rowBtn {
51
+  margin-top: 14px;
52
+  margin-bottom: 10px;
53
+  justify-content: space-around;
54
+}
55
+.followBtn,
56
+.unFollowBtn,
57
+.privateMessageBtn {
58
+  width: 77px;
59
+  height: 31px;
60
+  line-height: 31px;
61
+  background: rgba(113, 193, 53, 1);
62
+  border-radius: 4px;
63
+  color: #fff;
64
+  font-size: 12px;
65
+  font-weight: 500;
66
+  text-align: center;
67
+  cursor: pointer;
68
+  margin: 0 5px;
69
+}
70
+
71
+.followBtn {
72
+  border: 1px solid rgba(113, 193, 53, 1);
73
+  color: rgba(113, 193, 53, 1);
74
+  background: #fff;
75
+}
76
+.unFollowBtn {
77
+  color: #fff;
78
+  background: rgba(113, 193, 53, 1);
79
+  border: 1px solid rgba(113, 193, 53, 1);
80
+}
81
+
82
+.modalContainer {
83
+  background: #fff;
84
+  padding: 20px;
85
+}
86
+
87
+.modalTitle {
88
+  color: #3a3a3a;
89
+  margin-left: 8px;
90
+  margin-bottom: 12px;
91
+  font-weight: 500;
92
+}
93
+
94
+.modalClose {
95
+  position: absolute;
96
+  top: 15px;
97
+  right: 15px;
98
+  font-size: 12px;
99
+}
100
+
101
+.nextComment {
102
+  width: 510px;
103
+  padding: 0;
104
+}
105
+.expressionBtnWrap,
106
+.pictureBtnWrap {
107
+  float: left;
108
+  width: 70px;
109
+  margin-top: 5px;
110
+  cursor: pointer;
111
+  .icon {
112
+    float: left;
113
+    color: #ffa405;
114
+    font-size: 18px !important;
115
+    margin: 0 !important;
116
+  }
117
+  .text {
118
+    float: left;
119
+    font-size: 12px;
120
+    color: #393939;
121
+    margin-left: 6px;
122
+  }
123
+}
124
+
125
+.btnGroup {
126
+  display: flex;
127
+}
128
+
129
+.cancelBtn,
130
+.submitBtn {
131
+  width: 77px;
132
+  height: 31px;
133
+  line-height: 31px;
134
+  background: rgba(113, 193, 53, 1);
135
+  border-radius: 4px;
136
+  color: #fff;
137
+  font-size: 12px;
138
+  font-weight: 500;
139
+  text-align: center;
140
+  cursor: pointer;
141
+}
142
+.cancelBtn {
143
+  background: #e9e9e9;
144
+  color: #6d6d6d;
145
+  margin-right: 12px;
146
+}

+ 11
- 0
src/components/ContentItem/index.css ファイルの表示

@@ -22,6 +22,7 @@
22 22
   border-radius: 20px;
23 23
   background-position: center;
24 24
   background-size: cover;
25
+  cursor: pointer;
25 26
 }
26 27
 .comment-item-content {
27 28
   margin: 10px 0;
@@ -87,6 +88,16 @@
87 88
   margin-right: 10px;
88 89
 }
89 90
 
91
+.avatar-hover-card-overlay {
92
+  padding-top: 0;
93
+}
94
+.avatar-hover-card-overlay .ant-popover-inner-content {
95
+  padding: 0;
96
+}
97
+.avatar-hover-card-overlay .ant-popover-arrow {
98
+  display: none;
99
+}
100
+
90 101
 @media screen and (max-width: 616px) and (min-width: 449px) {
91 102
   .comment-item-right {
92 103
     display: inline-block;

+ 55
- 12
src/components/ContentItem/index.js ファイルの表示

@@ -1,11 +1,12 @@
1 1
 import React, { Component } from "react";
2 2
 import PropTypes from "prop-types";
3
-import { Avatar, Icon, Tooltip, Popconfirm } from "antd";
3
+import { Icon, Tooltip, Popconfirm, Popover } from "antd";
4 4
 import dayjs from "dayjs";
5 5
 import "dayjs/locale/zh-cn";
6 6
 // import 'dayjs/locale/es';
7 7
 import relativeTime from "dayjs/plugin/relativeTime";
8 8
 import intl from "react-intl-universal";
9
+import AvatarHoverCard from "./AvatarHoverCard";
9 10
 import Comment from "../../Comment";
10 11
 import CommentInput from "../CommentInput";
11 12
 import avatar from "../../avatar";
@@ -27,12 +28,14 @@ class CommentItem extends Component {
27 28
     this.state = {
28 29
       showInput: false,
29 30
       showPreviewer: false,
30
-      previewerIndex: 0
31
+      previewerIndex: 0,
32
+      popoverVisible: false
31 33
     };
32 34
     this.handleToggleInput = this.handleToggleInput.bind(this);
33 35
     this.renderTextWithReply = this.renderTextWithReply.bind(this);
34 36
     this.showPreviewer = this.showPreviewer.bind(this);
35 37
     this.hidePreviewer = this.hidePreviewer.bind(this);
38
+    this.handleVisibleChange = this.handleVisibleChange.bind(this);
36 39
   }
37 40
 
38 41
   showPreviewer(index) {
@@ -52,6 +55,12 @@ class CommentItem extends Component {
52 55
     this.setState({ showInput: !this.state.showInput });
53 56
   }
54 57
 
58
+  handleVisibleChange(visible) {
59
+    this.setState({
60
+      popoverVisible: visible
61
+    });
62
+  }
63
+
55 64
   renderTextWithReply(text, content) {
56 65
     let newText = text;
57 66
     const { reply } = content;
@@ -81,10 +90,11 @@ class CommentItem extends Component {
81 90
       action,
82 91
       showReply,
83 92
       onShowReply,
84
-      app
93
+      app,
94
+      user_id
85 95
     } = this.props;
86 96
 
87
-    const { locale } = this.props.app;
97
+    const { locale, userAvaClick, showHoverCard } = this.props.app;
88 98
     const { showInput } = this.state;
89 99
 
90 100
     let newContent = content.content;
@@ -116,20 +126,53 @@ class CommentItem extends Component {
116 126
     return (
117 127
       <div className="comment-item-box">
118 128
         <div className="comment-item-left">
119
-          {/* <Avatar src={content.user_avatar || avatar} size="large" /> */}
120
-          <div
121
-            className="comment-item-avatar"
122
-            style={{
123
-              backgroundImage: `url(${content.user_avatar || avatar})`
124
-            }}
125
-          />
129
+          {showHoverCard ? (
130
+            <Popover
131
+              content={
132
+                <AvatarHoverCard
133
+                  {...this.props.app}
134
+                  user_id={user_id}
135
+                  handleVisibleChange={this.handleVisibleChange}
136
+                  image={content.user_avatar || avatar}
137
+                />
138
+              }
139
+              // placement={this.props.placement}
140
+              // trigger="click"
141
+              visible={this.state.popoverVisible}
142
+              onVisibleChange={this.handleVisibleChange}
143
+              overlayClassName="avatar-hover-card-overlay"
144
+            >
145
+              <div
146
+                className="comment-item-avatar"
147
+                style={{
148
+                  backgroundImage: `url(${content.user_avatar || avatar})`
149
+                }}
150
+                onClick={() => userAvaClick(user_id)}
151
+              />
152
+            </Popover>
153
+          ) : (
154
+            <div
155
+              className="comment-item-avatar"
156
+              style={{
157
+                backgroundImage: `url(${content.user_avatar || avatar})`
158
+              }}
159
+              onClick={() => {
160
+                userAvaClick(user_id);
161
+              }}
162
+            />
163
+          )}
126 164
         </div>
127 165
         <div className="comment-item-right">
128 166
           <div>
129 167
             {/* <a href={`/${content.user_id}`}>
130 168
               {content.user_name || "暂无昵称"}
131 169
             </a> */}
132
-            <strong>{content.user_name || intl.get("comment.tourist")}</strong>
170
+            <strong
171
+              onClick={() => userAvaClick(user_id)}
172
+              style={{ cursor: "pointer" }}
173
+            >
174
+              {content.user_name || intl.get("comment.tourist")}
175
+            </strong>
133 176
             <span style={{ marginLeft: 10 }}>
134 177
               <Tooltip
135 178
                 placement="top"

+ 43
- 0
src/index.js ファイルの表示

@@ -77,6 +77,49 @@ if (process.env.NODE_ENV !== "production") {
77 77
     businessId: "test",
78 78
     businessUserId: 4,
79 79
     userId: 71299,
80
+    currentUser: {
81
+      user_id: 71748
82
+    },
83
+    userAvaHoverData: {
84
+      71763: {
85
+        nickname: "aaa",
86
+        followers: 20,
87
+        fans: 2,
88
+        isFollowed: true
89
+      },
90
+      71748: {
91
+        nickname: "L0",
92
+        followers: 10,
93
+        fans: 11,
94
+        isFollowed: false
95
+      },
96
+      71299: {
97
+        nickname: "narro",
98
+        followers: 10,
99
+        fans: 11,
100
+        isFollowed: false
101
+      }
102
+    },
103
+    showHoverCard: true,
104
+    userAvaClick: id => {
105
+      console.log("userAvaClick", id);
106
+    },
107
+    getUserInfo: id => {
108
+      console.log("getinfo:", id);
109
+    },
110
+    focus: id => {
111
+      return new Promise(function(resolve, reject) {
112
+        console.log("focus:", id);
113
+        resolve();
114
+      });
115
+    },
116
+    unFocus: id => {
117
+      return new Promise(function(resolve, reject) {
118
+        console.log("unFocus:", id);
119
+        resolve();
120
+      });
121
+    },
122
+
80 123
     onCountChange: c => {
81 124
       console.log(c);
82 125
     },