about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/components/features/account/components/header.jsx51
1 files changed, 44 insertions, 7 deletions
diff --git a/app/assets/javascripts/components/features/account/components/header.jsx b/app/assets/javascripts/components/features/account/components/header.jsx
index e1aae3c77..a359963c4 100644
--- a/app/assets/javascripts/components/features/account/components/header.jsx
+++ b/app/assets/javascripts/components/features/account/components/header.jsx
@@ -4,6 +4,7 @@ import emojify from '../../../emoji';
 import escapeTextContentForBrowser from 'escape-html';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import IconButton from '../../../components/icon_button';
+import { Motion, spring } from 'react-motion';
 
 const messages = defineMessages({
   unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
@@ -11,6 +12,47 @@ const messages = defineMessages({
   requested: { id: 'account.requested', defaultMessage: 'Awaiting approval' }
 });
 
+const Avatar = React.createClass({
+
+  propTypes: {
+    account: ImmutablePropTypes.map.isRequired
+  },
+
+  getInitialState () {
+    return {
+      isHovered: false
+    };
+  },
+
+  mixins: [PureRenderMixin],
+
+  handleMouseOver () {
+    if (this.state.isHovered) return;
+    this.setState({ isHovered: true });
+  },
+
+  handleMouseOut () {
+    if (!this.state.isHovered) return;
+    this.setState({ isHovered: false });
+  },
+
+  render () {
+    const { account }   = this.props;
+    const { isHovered } = this.state;
+
+    return (
+      <Motion defaultStyle={{ radius: 90 }} style={{ radius: spring(isHovered ? 30 : 90, { stiffness: 180, damping: 12 }) }}>
+        {({ radius }) =>
+          <a href={account.get('url')} className='account__header__avatar' target='_blank' rel='noopener' style={{ display: 'block', width: '90px', height: '90px', margin: '0 auto', marginBottom: '10px', borderRadius: `${radius}px`, overflow: 'hidden' }} onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}>
+            <img src={account.get('avatar')} alt={account.get('acct')} style={{ display: 'block', width: '90px', height: '90px' }} />
+          </a>
+        }
+      </Motion>
+    );
+  }
+
+});
+
 const Header = React.createClass({
 
   propTypes: {
@@ -68,14 +110,9 @@ const Header = React.createClass({
     return (
       <div className='account__header' style={{ backgroundImage: `url(${account.get('header')})` }}>
         <div style={{ padding: '20px 10px' }}>
-          <a href={account.get('url')} target='_blank' rel='noopener' style={{ display: 'block', color: 'inherit', textDecoration: 'none' }}>
-            <div className='account__header__avatar' style={{ width: '90px', margin: '0 auto', marginBottom: '10px' }}>
-              <img src={account.get('avatar')} alt='' style={{ display: 'block', width: '90px', height: '90px', borderRadius: '90px' }} />
-            </div>
-
-            <span style={{ display: 'inline-block', fontSize: '20px', lineHeight: '27px', fontWeight: '500' }} className='account__header__display-name' dangerouslySetInnerHTML={displayNameHTML} />
-          </a>
+          <Avatar account={account} />
 
+          <span style={{ display: 'inline-block', fontSize: '20px', lineHeight: '27px', fontWeight: '500' }} className='account__header__display-name' dangerouslySetInnerHTML={displayNameHTML} />
           <span className='account__header__username' style={{ fontSize: '14px', fontWeight: '400', display: 'block', marginBottom: '10px' }}>@{account.get('acct')} {lockedIcon}</span>
           <div style={{ fontSize: '14px' }} className='account__header__content' dangerouslySetInnerHTML={content} />