commit: 0634e8dee5026b06c95b7efe161a0930c7431d9b
parent: 29e79f770f3388a1d2d0e169da9fec31467c77c9
Author: Eugen Rochko <eugen@zeonfederated.com>
Date: Sun, 9 Oct 2016 22:19:15 +0200
Improved how in-UI profiles look
Diffstat:
7 files changed, 94 insertions(+), 64 deletions(-)
diff --git a/app/assets/javascripts/components/components/dropdown_menu.jsx b/app/assets/javascripts/components/components/dropdown_menu.jsx
@@ -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;
diff --git a/app/assets/javascripts/components/components/status_action_bar.jsx b/app/assets/javascripts/components/components/status_action_bar.jsx
@@ -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>
);
diff --git a/app/assets/javascripts/components/features/account/components/action_bar.jsx b/app/assets/javascripts/components/features/account/components/action_bar.jsx
@@ -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 {
- 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} />;
+ } 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 {
+ 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>
);
},
diff --git a/app/assets/javascripts/components/features/account/components/header.jsx b/app/assets/javascripts/components/features/account/components/header.jsx
@@ -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>
);
diff --git a/app/assets/javascripts/components/features/account/index.jsx b/app/assets/javascripts/components/features/account/index.jsx
@@ -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} />
diff --git a/app/assets/javascripts/components/features/status/components/action_bar.jsx b/app/assets/javascripts/components/features/status/components/action_bar.jsx
@@ -1,26 +1,36 @@
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({
-
+
propTypes: {
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>
);
}
diff --git a/app/assets/javascripts/components/features/status/index.jsx b/app/assets/javascripts/components/features/status/index.jsx
@@ -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>