Improved how in-UI profiles look
This commit is contained in:
		
							parent
							
								
									29e79f770f
								
							
						
					
					
						commit
						0634e8dee5
					
				
					 7 changed files with 94 additions and 64 deletions
				
			
		| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown';
 | 
			
		||||
 | 
			
		||||
const DropdownMenu = ({ icon, items, size }) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <Dropdown>
 | 
			
		||||
      <DropdownTrigger className='icon-button' style={{ fontSize: `${size}px`, width: `${size}px`, lineHeight: `${size}px` }}>
 | 
			
		||||
        <i className={`fa fa-fw fa-${icon}`} style={{ verticalAlign: 'middle' }} />
 | 
			
		||||
      </DropdownTrigger>
 | 
			
		||||
 | 
			
		||||
      <DropdownContent style={{ lineHeight: '18px' }}>
 | 
			
		||||
        <ul>
 | 
			
		||||
          {items.map(({ text, action }, i) => <li key={i}><a href='#' onClick={e => { e.preventDefault(); action(); }}>{text}</a></li>)}
 | 
			
		||||
        </ul>
 | 
			
		||||
      </DropdownContent>
 | 
			
		||||
    </Dropdown>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DropdownMenu.propTypes = {
 | 
			
		||||
  icon: React.PropTypes.string.isRequired,
 | 
			
		||||
  items: React.PropTypes.array.isRequired,
 | 
			
		||||
  size: React.PropTypes.number.isRequired
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default DropdownMenu;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
			
		||||
import PureRenderMixin    from 'react-addons-pure-render-mixin';
 | 
			
		||||
import IconButton         from './icon_button';
 | 
			
		||||
import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown';
 | 
			
		||||
import DropdownMenu       from './dropdown_menu';
 | 
			
		||||
 | 
			
		||||
const StatusActionBar = React.createClass({
 | 
			
		||||
  propTypes: {
 | 
			
		||||
| 
						 | 
				
			
			@ -26,23 +26,16 @@ const StatusActionBar = React.createClass({
 | 
			
		|||
    this.props.onReblog(this.props.status);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleDeleteClick(e) {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
  handleDeleteClick () {
 | 
			
		||||
    this.props.onDelete(this.props.status);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  render () {
 | 
			
		||||
    const { status, me } = this.props;
 | 
			
		||||
    let menu = '';
 | 
			
		||||
    let menu = [];
 | 
			
		||||
 | 
			
		||||
    if (status.getIn(['account', 'id']) === me) {
 | 
			
		||||
      menu = (
 | 
			
		||||
        <ul>
 | 
			
		||||
          <li><a href='#' onClick={this.handleDeleteClick}>Delete</a></li>
 | 
			
		||||
        </ul>
 | 
			
		||||
      );
 | 
			
		||||
    } else {
 | 
			
		||||
      menu = <ul />;
 | 
			
		||||
      menu.push({ text: 'Delete', action: this.handleDeleteClick });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
| 
						 | 
				
			
			@ -52,13 +45,7 @@ const StatusActionBar = React.createClass({
 | 
			
		|||
        <div style={{ float: 'left', marginRight: '18px'}}><IconButton active={status.get('favourited')} title='Favourite' icon='star' onClick={this.handleFavouriteClick} /></div>
 | 
			
		||||
 | 
			
		||||
        <div onClick={e => e.stopPropagation()} style={{ width: '18px', height: '18px', float: 'left' }}>
 | 
			
		||||
          <Dropdown>
 | 
			
		||||
            <DropdownTrigger className='icon-button' style={{ fontSize: '18px', lineHeight: '18px', width: '18px', height: '18px' }}>
 | 
			
		||||
              <i className='fa fa-fw fa-ellipsis-h' />
 | 
			
		||||
            </DropdownTrigger>
 | 
			
		||||
 | 
			
		||||
            <DropdownContent>{menu}</DropdownContent>
 | 
			
		||||
          </Dropdown>
 | 
			
		||||
          <DropdownMenu items={menu} icon='ellipsis-h' size={18} />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
import PureRenderMixin    from 'react-addons-pure-render-mixin';
 | 
			
		||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
			
		||||
import Button             from '../../../components/button';
 | 
			
		||||
import DropdownMenu       from '../../../components/dropdown_menu';
 | 
			
		||||
 | 
			
		||||
const ActionBar = React.createClass({
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -16,47 +16,42 @@ const ActionBar = React.createClass({
 | 
			
		|||
  render () {
 | 
			
		||||
    const { account, me } = this.props;
 | 
			
		||||
 | 
			
		||||
    let infoText     = '';
 | 
			
		||||
    let follow       = '';
 | 
			
		||||
    let buttonText   = '';
 | 
			
		||||
    let block        = '';
 | 
			
		||||
    let disabled     = false;
 | 
			
		||||
    let menu = [];
 | 
			
		||||
 | 
			
		||||
    if (account.get('id') === me) {
 | 
			
		||||
      buttonText = 'This is you!';
 | 
			
		||||
      disabled   = true;
 | 
			
		||||
 | 
			
		||||
    } else if (account.getIn(['relationship', 'blocking'])) {
 | 
			
		||||
      menu.push({ text: 'Unblock', action: this.props.onBlock });
 | 
			
		||||
    } else if (account.getIn(['relationship', 'following'])) {
 | 
			
		||||
      menu.push({ text: 'Unfollow', action: this.props.onFollow });
 | 
			
		||||
      menu.push({ text: 'Block', action: this.props.onBlock });
 | 
			
		||||
    } else {
 | 
			
		||||
      let blockText = '';
 | 
			
		||||
 | 
			
		||||
      if (account.getIn(['relationship', 'blocking'])) {
 | 
			
		||||
        buttonText = 'Blocked';
 | 
			
		||||
        disabled   = true;
 | 
			
		||||
        blockText  = 'Unblock';
 | 
			
		||||
      } else {
 | 
			
		||||
        if (account.getIn(['relationship', 'following'])) {
 | 
			
		||||
          buttonText = 'Unfollow';
 | 
			
		||||
        } else {
 | 
			
		||||
          buttonText = 'Follow';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (account.getIn(['relationship', 'followed_by'])) {
 | 
			
		||||
          infoText = 'Follows you!';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        blockText = 'Block';
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      block = <Button text={blockText} onClick={this.props.onBlock} />;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!account.getIn(['relationship', 'blocking'])) {
 | 
			
		||||
      follow = <Button text={buttonText} onClick={this.props.onFollow} disabled={disabled} />;
 | 
			
		||||
      menu.push({ text: 'Follow', action: this.props.onFollow });
 | 
			
		||||
      menu.push({ text: 'Block', action: this.props.onBlock });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div style={{ borderTop: '1px solid #363c4b', borderBottom: '1px solid #363c4b', padding: '10px', lineHeight: '36px', overflow: 'hidden', flex: '0 0 auto' }}>
 | 
			
		||||
        {follow} {block}
 | 
			
		||||
        <span style={{ color: '#616b86', fontWeight: '500', textTransform: 'uppercase', float: 'right', display: 'block' }}>{infoText}</span>
 | 
			
		||||
      <div style={{ borderTop: '1px solid #363c4b', borderBottom: '1px solid #363c4b', lineHeight: '36px', overflow: 'hidden', flex: '0 0 auto', display: 'flex' }}>
 | 
			
		||||
        <div style={{ flex: '1 1 auto', display: 'flex', lineHeight: '18px' }}>
 | 
			
		||||
          <div style={{ overflow: 'hidden', width: '80px', borderRight: '1px solid #363c4b', padding: '10px', paddingRight: '5px' }}>
 | 
			
		||||
            <span style={{ display: 'block', textTransform: 'uppercase', fontSize: '11px', color: '#616b86' }}>Posts</span>
 | 
			
		||||
            <span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}>{account.get('statuses_count')}</span>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div style={{ overflow: 'hidden', width: '80px', borderRight: '1px solid #363c4b', padding: '10px 5px' }}>
 | 
			
		||||
            <span style={{ display: 'block', textTransform: 'uppercase', fontSize: '11px', color: '#616b86' }}>Follows</span>
 | 
			
		||||
            <span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}>{account.get('following_count')}</span>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div style={{ overflow: 'hidden', width: '80px', padding: '10px 5px', borderRight: '1px solid #363c4b' }}>
 | 
			
		||||
            <span style={{ display: 'block', textTransform: 'uppercase', fontSize: '11px', color: '#616b86' }}>Followers</span>
 | 
			
		||||
            <span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}>{account.get('followers_count')}</span>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div style={{ padding: '10px', flex: '1 1 auto' }}>
 | 
			
		||||
          <DropdownMenu items={menu} icon='bars' size={24} />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,33 +4,41 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
			
		|||
const Header = React.createClass({
 | 
			
		||||
 | 
			
		||||
  propTypes: {
 | 
			
		||||
    account: ImmutablePropTypes.map.isRequired
 | 
			
		||||
    account: ImmutablePropTypes.map.isRequired,
 | 
			
		||||
    me: React.PropTypes.number.isRequired
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  mixins: [PureRenderMixin],
 | 
			
		||||
 | 
			
		||||
  render () {
 | 
			
		||||
    const { account } = this.props;
 | 
			
		||||
    const { account, me } = this.props;
 | 
			
		||||
 | 
			
		||||
    let displayName = account.get('display_name');
 | 
			
		||||
    let info = '';
 | 
			
		||||
 | 
			
		||||
    if (displayName.length === 0) {
 | 
			
		||||
      displayName = account.get('username');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (me !== account.get('id') && account.getIn(['relationship', 'followed_by'])) {
 | 
			
		||||
      info = <span style={{ position: 'absolute', top: '10px', right: '10px', opacity: '0.7', display: 'inline-block', verticalAlign: 'top', background: 'rgba(0, 0, 0, 0.4)', color: '#fff', textTransform: 'uppercase', fontSize: '11px', fontWeight: '500', padding: '4px', borderRadius: '4px' }}>Follows you</span>
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div style={{ flex: '0 0 auto', background: '#2f3441', textAlign: 'center', backgroundImage: `url(${account.get('header')})`, backgroundSize: 'cover' }}>
 | 
			
		||||
      <div style={{ flex: '0 0 auto', background: '#2f3441', textAlign: 'center', backgroundImage: `url(${account.get('header')})`, backgroundSize: 'cover', position: 'relative' }}>
 | 
			
		||||
        <div style={{ background: 'rgba(47, 52, 65, 0.8)', padding: '30px 10px' }}>
 | 
			
		||||
          <a href={account.get('url')} target='_blank' rel='noopener' style={{ display: 'block', color: 'inherit', textDecoration: 'none' }}>
 | 
			
		||||
            <div style={{ width: '90px', margin: '0 auto', marginBottom: '15px' }}>
 | 
			
		||||
              <img src={account.get('avatar')} alt='' style={{ display: 'block', width: '90px', height: '90px', borderRadius: '90px' }} />
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <span style={{ color: '#fff', fontSize: '20px', lineHeight: '27px', fontWeight: '500', display: 'block' }}>{displayName}</span>
 | 
			
		||||
            <span style={{ display: 'inline-block', color: '#fff', fontSize: '20px', lineHeight: '27px', fontWeight: '500' }}>{displayName}</span>
 | 
			
		||||
          </a>
 | 
			
		||||
 | 
			
		||||
          <span style={{ fontSize: '14px', fontWeight: '400', display: 'block', color: '#2b90d9', marginBottom: '15px' }}>@{account.get('acct')}</span>
 | 
			
		||||
          <p style={{ color: '#616b86', fontSize: '14px' }}>{account.get('note')}</p>
 | 
			
		||||
 | 
			
		||||
          {info}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -75,7 +75,7 @@ const Account = React.createClass({
 | 
			
		|||
    return (
 | 
			
		||||
      <Column>
 | 
			
		||||
        <div style={{ display: 'flex', flexDirection: 'column', 'flex': '0 0 auto', height: '100%' }}>
 | 
			
		||||
          <Header account={account} />
 | 
			
		||||
          <Header account={account} me={me} />
 | 
			
		||||
 | 
			
		||||
          <ActionBar account={account} me={me} onFollow={this.handleFollow} onBlock={this.handleBlock} />
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
import PureRenderMixin    from 'react-addons-pure-render-mixin';
 | 
			
		||||
import IconButton         from '../../../components/icon_button';
 | 
			
		||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
			
		||||
import DropdownMenu       from '../../../components/dropdown_menu';
 | 
			
		||||
 | 
			
		||||
const ActionBar = React.createClass({
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8,19 +9,28 @@ const ActionBar = React.createClass({
 | 
			
		|||
    status: ImmutablePropTypes.map.isRequired,
 | 
			
		||||
    onReply: React.PropTypes.func.isRequired,
 | 
			
		||||
    onReblog: React.PropTypes.func.isRequired,
 | 
			
		||||
    onFavourite: React.PropTypes.func.isRequired
 | 
			
		||||
    onFavourite: React.PropTypes.func.isRequired,
 | 
			
		||||
    onDelete: React.PropTypes.func.isRequired,
 | 
			
		||||
    me: React.PropTypes.number.isRequired
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  mixins: [PureRenderMixin],
 | 
			
		||||
 | 
			
		||||
  render () {
 | 
			
		||||
    const { status } = this.props;
 | 
			
		||||
    const { status, me } = this.props;
 | 
			
		||||
 | 
			
		||||
    let menu = [];
 | 
			
		||||
 | 
			
		||||
    if (me === status.getIn(['account', 'id'])) {
 | 
			
		||||
      menu.push({ text: 'Delete', action: () => this.props.onDelete(status) });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div style={{ background: '#2f3441', display: 'flex', flexDirection: 'row', borderTop: '1px solid #363c4b', borderBottom: '1px solid #363c4b', padding: '10px 0' }}>
 | 
			
		||||
        <div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton title='Reply' icon='reply' onClick={() => this.props.onReply(status)} /></div>
 | 
			
		||||
        <div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton active={status.get('reblogged')} title='Reblog' icon='retweet' onClick={() => this.props.onReblog(status)} /></div>
 | 
			
		||||
        <div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton active={status.get('favourited')} title='Favourite' icon='star' onClick={() => this.props.onFavourite(status)} /></div>
 | 
			
		||||
        <div style={{ flex: '1 1 auto', textAlign: 'center' }}><DropdownMenu size={18} icon='ellipsis-h' items={menu} /></div>
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ import ActionBar             from './components/action_bar';
 | 
			
		|||
import Column                from '../ui/components/column';
 | 
			
		||||
import { favourite, reblog } from '../../actions/interactions';
 | 
			
		||||
import { replyCompose }      from '../../actions/compose';
 | 
			
		||||
import { deleteStatus }      from '../../actions/statuses';
 | 
			
		||||
import {
 | 
			
		||||
  getStatus,
 | 
			
		||||
  getStatusAncestors,
 | 
			
		||||
| 
						 | 
				
			
			@ -57,8 +58,12 @@ const Status = React.createClass({
 | 
			
		|||
    this.props.dispatch(reblog(status));
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleDeleteClick (status) {
 | 
			
		||||
    this.props.dispatch(deleteStatus(status.get('id')));
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  renderChildren (list) {
 | 
			
		||||
    return list.map(s => <EmbeddedStatus status={s} me={this.props.me} key={s.get('id')} onReply={this.handleReplyClick} onFavourite={this.handleFavouriteClick} onReblog={this.handleReblogClick} />);
 | 
			
		||||
    return list.map(s => <EmbeddedStatus status={s} me={this.props.me} key={s.get('id')} onReply={this.handleReplyClick} onFavourite={this.handleFavouriteClick} onReblog={this.handleReblogClick} onDelete={this.handleDeleteClick} />);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  render () {
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +85,7 @@ const Status = React.createClass({
 | 
			
		|||
          <div>{this.renderChildren(ancestors)}</div>
 | 
			
		||||
 | 
			
		||||
          <DetailedStatus status={status} me={me} />
 | 
			
		||||
          <ActionBar status={status} onReply={this.handleReplyClick} onFavourite={this.handleFavouriteClick} onReblog={this.handleReblogClick} />
 | 
			
		||||
          <ActionBar status={status} me={me} onReply={this.handleReplyClick} onFavourite={this.handleFavouriteClick} onReblog={this.handleReblogClick} onDelete={this.handleDeleteClick} />
 | 
			
		||||
 | 
			
		||||
          <div>{this.renderChildren(descendants)}</div>
 | 
			
		||||
        </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue