icons for dropdown

This commit is contained in:
Baptiste Lemoine 2020-11-01 12:10:34 +01:00
parent 32dbed3864
commit 6497665819
9 changed files with 424 additions and 194 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -128,11 +128,13 @@ class DropdownMenu extends React.PureComponent {
return <li key={`sep-${i}`} className='dropdown-menu__separator' />;
}
const { text, href = '#', target = '_blank', method } = option;
const { text, href = '#', target = '_blank', method, iconName } = option;
return (
<li className='dropdown-menu__item' key={`${text}-${i}`}>
<a href={href} target={target} data-method={method} rel='noopener noreferrer' role='button' tabIndex='0' ref={i === 0 ? this.setFocusRef : null} onClick={this.handleClick} onKeyPress={this.handleItemKeyPress} data-index={i}>
<i className={'fa fa-'+iconName} />
{text}
</a>
</li>

View File

@ -120,7 +120,7 @@ export default class IconButton extends React.PureComponent {
});
if (typeof counter !== 'undefined') {
style.width = 'auto';
style.width = '100%';
}
return (

View File

@ -6,41 +6,41 @@ import IconButton from './icon_button';
import DropdownMenuContainer from '../containers/dropdown_menu_container';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { me, isStaff } from '../initial_state';
import { isStaff, me } from '../initial_state';
import classNames from 'classnames';
const messages = defineMessages({
delete: { id: 'status.delete', defaultMessage: 'Delete' },
redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' },
direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' },
mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
reply: { id: 'status.reply', defaultMessage: 'Reply' },
share: { id: 'status.share', defaultMessage: 'Share' },
more: { id: 'status.more', defaultMessage: 'More' },
replyAll: { id: 'status.replyAll', defaultMessage: 'Reply to thread' },
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost with original visibility' },
delete : { id: 'status.delete', defaultMessage: 'Delete' },
redraft : { id: 'status.redraft', defaultMessage: 'Delete & re-draft' },
direct : { id: 'status.direct', defaultMessage: 'Direct message @{name}' },
mention : { id: 'status.mention', defaultMessage: 'Mention @{name}' },
mute : { id: 'account.mute', defaultMessage: 'Mute @{name}' },
block : { id: 'account.block', defaultMessage: 'Block @{name}' },
reply : { id: 'status.reply', defaultMessage: 'Reply' },
share : { id: 'status.share', defaultMessage: 'Share' },
more : { id: 'status.more', defaultMessage: 'More' },
replyAll : { id: 'status.replyAll', defaultMessage: 'Reply to thread' },
reblog : { id: 'status.reblog', defaultMessage: 'Boost' },
reblog_private : { id: 'status.reblog_private', defaultMessage: 'Boost with original visibility' },
cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },
bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' },
removeBookmark: { id: 'status.remove_bookmark', defaultMessage: 'Remove bookmark' },
open: { id: 'status.open', defaultMessage: 'Expand this status' },
report: { id: 'status.report', defaultMessage: 'Report @{name}' },
muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' },
unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
embed: { id: 'status.embed', defaultMessage: 'Embed' },
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this status in the moderation interface' },
copy: { id: 'status.copy', defaultMessage: 'Copy link to status' },
blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' },
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
cannot_reblog : { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
favourite : { id: 'status.favourite', defaultMessage: 'Favourite' },
bookmark : { id: 'status.bookmark', defaultMessage: 'Bookmark' },
removeBookmark : { id: 'status.remove_bookmark', defaultMessage: 'Remove bookmark' },
open : { id: 'status.open', defaultMessage: 'Expand this status' },
report : { id: 'status.report', defaultMessage: 'Report @{name}' },
muteConversation : { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' },
unmuteConversation : { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
pin : { id: 'status.pin', defaultMessage: 'Pin on profile' },
unpin : { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
embed : { id: 'status.embed', defaultMessage: 'Embed' },
admin_account : { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
admin_status : { id: 'status.admin_status', defaultMessage: 'Open this status in the moderation interface' },
copy : { id: 'status.copy', defaultMessage: 'Copy link to status' },
blockDomain : { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' },
unblockDomain : { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
unmute : { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
unblock : { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
});
const mapStateToProps = (state, { status }) => ({
@ -56,28 +56,28 @@ class StatusActionBar extends ImmutablePureComponent {
};
static propTypes = {
status: ImmutablePropTypes.map.isRequired,
relationship: ImmutablePropTypes.map,
onReply: PropTypes.func,
onFavourite: PropTypes.func,
onReblog: PropTypes.func,
onDelete: PropTypes.func,
onDirect: PropTypes.func,
onMention: PropTypes.func,
onMute: PropTypes.func,
onUnmute: PropTypes.func,
onBlock: PropTypes.func,
onUnblock: PropTypes.func,
onBlockDomain: PropTypes.func,
onUnblockDomain: PropTypes.func,
onReport: PropTypes.func,
onEmbed: PropTypes.func,
status : ImmutablePropTypes.map.isRequired,
relationship : ImmutablePropTypes.map,
onReply : PropTypes.func,
onFavourite : PropTypes.func,
onReblog : PropTypes.func,
onDelete : PropTypes.func,
onDirect : PropTypes.func,
onMention : PropTypes.func,
onMute : PropTypes.func,
onUnmute : PropTypes.func,
onBlock : PropTypes.func,
onUnblock : PropTypes.func,
onBlockDomain : PropTypes.func,
onUnblockDomain : PropTypes.func,
onReport : PropTypes.func,
onEmbed : PropTypes.func,
onMuteConversation: PropTypes.func,
onPin: PropTypes.func,
onBookmark: PropTypes.func,
withDismiss: PropTypes.bool,
scrollKey: PropTypes.string,
intl: PropTypes.object.isRequired,
onPin : PropTypes.func,
onBookmark : PropTypes.func,
withDismiss : PropTypes.bool,
scrollKey : PropTypes.string,
intl : PropTypes.object.isRequired,
};
// Avoid checking props that are functions (and whose equality will always
@ -86,7 +86,7 @@ class StatusActionBar extends ImmutablePureComponent {
'status',
'relationship',
'withDismiss',
]
];
handleReplyClick = () => {
if (me) {
@ -94,16 +94,16 @@ class StatusActionBar extends ImmutablePureComponent {
} else {
this._openInteractionDialog('reply');
}
}
};
handleShareClick = () => {
navigator.share({
text: this.props.status.get('search_index'),
url: this.props.status.get('url'),
url : this.props.status.get('url'),
}).catch((e) => {
if (e.name !== 'AbortError') console.error(e);
});
}
};
handleFavouriteClick = () => {
if (me) {
@ -111,7 +111,7 @@ class StatusActionBar extends ImmutablePureComponent {
} else {
this._openInteractionDialog('favourite');
}
}
};
handleReblogClick = e => {
if (me) {
@ -119,35 +119,35 @@ class StatusActionBar extends ImmutablePureComponent {
} else {
this._openInteractionDialog('reblog');
}
}
};
_openInteractionDialog = type => {
window.open(`/interact/${this.props.status.get('id')}?type=${type}`, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
}
};
handleBookmarkClick = () => {
this.props.onBookmark(this.props.status);
}
};
handleDeleteClick = () => {
this.props.onDelete(this.props.status, this.context.router.history);
}
};
handleRedraftClick = () => {
this.props.onDelete(this.props.status, this.context.router.history, true);
}
};
handlePinClick = () => {
this.props.onPin(this.props.status);
}
};
handleMentionClick = () => {
this.props.onMention(this.props.status.get('account'), this.context.router.history);
}
};
handleDirectClick = () => {
this.props.onDirect(this.props.status.get('account'), this.context.router.history);
}
};
handleMuteClick = () => {
const { status, relationship, onMute, onUnmute } = this.props;
@ -158,7 +158,7 @@ class StatusActionBar extends ImmutablePureComponent {
} else {
onMute(account);
}
}
};
handleBlockClick = () => {
const { status, relationship, onBlock, onUnblock } = this.props;
@ -169,43 +169,43 @@ class StatusActionBar extends ImmutablePureComponent {
} else {
onBlock(status);
}
}
};
handleBlockDomain = () => {
const { status, onBlockDomain } = this.props;
const account = status.get('account');
onBlockDomain(account.get('acct').split('@')[1]);
}
};
handleUnblockDomain = () => {
const { status, onUnblockDomain } = this.props;
const account = status.get('account');
onUnblockDomain(account.get('acct').split('@')[1]);
}
};
handleOpen = () => {
this.context.router.history.push(`/statuses/${this.props.status.get('id')}`);
}
};
handleEmbed = () => {
this.props.onEmbed(this.props.status);
}
};
handleReport = () => {
this.props.onReport(this.props.status);
}
};
handleConversationMuteClick = () => {
this.props.onMuteConversation(this.props.status);
}
};
handleCopy = () => {
const url = this.props.status.get('url');
const url = this.props.status.get('url');
const textarea = document.createElement('textarea');
textarea.textContent = url;
textarea.textContent = url;
textarea.style.position = 'fixed';
document.body.appendChild(textarea);
@ -218,58 +218,97 @@ class StatusActionBar extends ImmutablePureComponent {
} finally {
document.body.removeChild(textarea);
}
}
};
render () {
render() {
const { status, relationship, intl, withDismiss, scrollKey } = this.props;
const mutingConversation = status.get('muted');
const anonymousAccess = !me;
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
const account = status.get('account');
const anonymousAccess = !me;
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
const account = status.get('account');
let menu = [];
menu.push({ text: intl.formatMessage(messages.open), action: this.handleOpen });
menu.push({ text: intl.formatMessage(messages.open), action: this.handleOpen , iconName: 'arrow-right' });
if (publicStatus) {
menu.push({ text: intl.formatMessage(messages.copy), action: this.handleCopy });
menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
menu.push({ text: intl.formatMessage(messages.copy), action: this.handleCopy, iconName: 'copy' });
menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed, iconName: 'screen' });
}
menu.push({ text: intl.formatMessage(status.get('bookmarked') ? messages.removeBookmark : messages.bookmark), action: this.handleBookmarkClick });
menu.push({
text : intl.formatMessage(status.get('bookmarked') ? messages.removeBookmark : messages.bookmark),
action: this.handleBookmarkClick,
iconName: 'bookmark',
});
menu.push(null);
if (status.getIn(['account', 'id']) === me || withDismiss) {
menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick });
menu.push({
text : intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation),
action: this.handleConversationMuteClick, iconName: 'hide',
});
menu.push(null);
}
if (status.getIn(['account', 'id']) === me) {
if (publicStatus) {
menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
menu.push({
text : intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin),
action: this.handlePinClick,
iconName: 'gears',
});
}
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });
menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick });
} else {
menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.handleMentionClick });
menu.push({ text: intl.formatMessage(messages.direct, { name: account.get('username') }), action: this.handleDirectClick });
menu.push({
text : intl.formatMessage(messages.mention, { name: account.get('username') }),
action: this.handleMentionClick,
iconName: 'plane',
});
menu.push({
text : intl.formatMessage(messages.direct, { name: account.get('username') }),
action: this.handleDirectClick,
iconName: 'enveloppe-o',
});
menu.push(null);
if (relationship && relationship.get('muting')) {
menu.push({ text: intl.formatMessage(messages.unmute, { name: account.get('username') }), action: this.handleMuteClick });
menu.push({
text : intl.formatMessage(messages.unmute, { name: account.get('username') }),
action: this.handleMuteClick,
iconName: 'times',
});
} else {
menu.push({ text: intl.formatMessage(messages.mute, { name: account.get('username') }), action: this.handleMuteClick });
menu.push({
text : intl.formatMessage(messages.mute, { name: account.get('username') }),
action: this.handleMuteClick,
iconName: 'times',
});
}
if (relationship && relationship.get('blocking')) {
menu.push({ text: intl.formatMessage(messages.unblock, { name: account.get('username') }), action: this.handleBlockClick });
menu.push({
text : intl.formatMessage(messages.unblock, { name: account.get('username') }),
action: this.handleBlockClick,
iconName: 'plus',
});
} else {
menu.push({ text: intl.formatMessage(messages.block, { name: account.get('username') }), action: this.handleBlockClick });
menu.push({
text : intl.formatMessage(messages.block, { name: account.get('username') }),
action: this.handleBlockClick,
iconName: 'times',
});
}
menu.push({ text: intl.formatMessage(messages.report, { name: account.get('username') }), action: this.handleReport });
menu.push({
text : intl.formatMessage(messages.report, { name: account.get('username') }),
action: this.handleReport,
iconName: 'flag',
});
if (account.get('acct') !== account.get('username')) {
const domain = account.get('acct').split('@')[1];
@ -285,8 +324,18 @@ class StatusActionBar extends ImmutablePureComponent {
if (isStaff) {
menu.push(null);
menu.push({ text: intl.formatMessage(messages.admin_account, { name: account.get('username') }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });
menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` });
menu.push({
text: intl.formatMessage(messages.admin_account,
{ name: account.get('username') }),
href: `/admin/accounts/${status.getIn(['account', 'id'])}`,
iconName: 'gears',
});
menu.push({
text: intl.formatMessage(messages.admin_status),
href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}`,
iconName: 'menu',
});
}
}
@ -314,14 +363,42 @@ class StatusActionBar extends ImmutablePureComponent {
}
const shareButton = ('share' in navigator) && publicStatus && (
<IconButton className='status__action-bar-button' title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShareClick} />
<IconButton
className='status__action-bar-button'
title={intl.formatMessage(messages.share)}
icon='share-alt'
onClick={this.handleShareClick}
/>
);
return (
<div className='status__action-bar'>
<IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} counter={status.get('replies_count')} obfuscateCount />
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} pressed={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} />
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} />
<IconButton
className='status__action-bar-button'
title={replyTitle}
icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon}
onClick={this.handleReplyClick}
counter={status.get('replies_count')}
obfuscateCount
/>
<IconButton
className={classNames('status__action-bar-button', { reblogPrivate })}
disabled={!publicStatus && !reblogPrivate}
active={status.get('reblogged')}
pressed={status.get('reblogged')}
title={reblogTitle}
icon='retweet'
onClick={this.handleReblogClick}
/>
<IconButton
className='status__action-bar-button star-icon'
animate
active={status.get('favourited')}
pressed={status.get('favourited')}
title={intl.formatMessage(messages.favourite)}
icon='star'
onClick={this.handleFavouriteClick}
/>
{shareButton}
@ -336,8 +413,8 @@ class StatusActionBar extends ImmutablePureComponent {
direction='right'
title={intl.formatMessage(messages.more)}
/>
</div>
</div>
</div >
</div >
);
}

View File

@ -6,7 +6,6 @@ import { FormattedMessage } from 'react-intl';
import Permalink from './permalink';
import classnames from 'classnames';
import PollContainer from 'mastodon/containers/poll_container';
import Icon from 'mastodon/components/icon';
import { autoPlayGif } from 'mastodon/initial_state';
const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)
@ -31,7 +30,7 @@ export default class StatusContent extends React.PureComponent {
hidden: true,
};
_updateStatusLinks () {
_updateStatusLinks() {
const node = this.node;
if (!node) {
@ -65,18 +64,18 @@ export default class StatusContent extends React.PureComponent {
if (this.props.status.get('collapsed', null) === null) {
let collapsed =
this.props.collapsable
&& this.props.onClick
&& node.clientHeight > MAX_HEIGHT
&& this.props.status.get('spoiler_text').length === 0;
this.props.collapsable
&& this.props.onClick
&& node.clientHeight > MAX_HEIGHT
&& this.props.status.get('spoiler_text').length === 0;
if(this.props.onCollapsedToggle) this.props.onCollapsedToggle(collapsed);
if (this.props.onCollapsedToggle) this.props.onCollapsedToggle(collapsed);
this.props.status.set('collapsed', collapsed);
}
}
_updateStatusEmojis () {
_updateStatusEmojis() {
const node = this.node;
if (!node || autoPlayGif) {
@ -97,12 +96,12 @@ export default class StatusContent extends React.PureComponent {
}
}
componentDidMount () {
componentDidMount() {
this._updateStatusLinks();
this._updateStatusEmojis();
}
componentDidUpdate () {
componentDidUpdate() {
this._updateStatusLinks();
this._updateStatusEmojis();
}
@ -140,8 +139,8 @@ export default class StatusContent extends React.PureComponent {
return;
}
const [ startX, startY ] = this.startXY;
const [ deltaX, deltaY ] = [Math.abs(e.clientX - startX), Math.abs(e.clientY - startY)];
const [startX, startY] = this.startXY;
const [deltaX, deltaY] = [Math.abs(e.clientX - startX), Math.abs(e.clientY - startY)];
let element = e.target;
while (element) {
@ -173,7 +172,7 @@ export default class StatusContent extends React.PureComponent {
this.node = c;
};
render () {
render() {
const { status } = this.props;
if (status.get('content').length === 0) {
@ -202,10 +201,13 @@ export default class StatusContent extends React.PureComponent {
className='status__content__read-more-button'
onClick={this.props.onClick}
>
<FormattedMessage
id='status.show_thread'
defaultMessage='Show thread'
/> <i className='fa fa-comment' />
<i className='fa fa-arrow-right' />
<span className='see-more'>
<FormattedMessage
id='status.show_thread'
defaultMessage='Show thread'
/>
</span >
</button >
);
@ -215,10 +217,14 @@ export default class StatusContent extends React.PureComponent {
onClick={this.props.onClick}
key='read-more'
>
<FormattedMessage
id='status.read_more'
defaultMessage='Read more'
/> <i className='fa fa-comment' />
<i className='fa fa-comment' />
<span className='see-more'>
<FormattedMessage
id='status.read_more'
defaultMessage='Read more'
/>
</span >
</button >
);
@ -226,19 +232,37 @@ export default class StatusContent extends React.PureComponent {
let mentionsPlaceholder = '';
const mentionLinks = status.get('mentions').map(item => (
<Permalink to={`/accounts/${item.get('id')}`} href={item.get('url')} key={item.get('id')} className='mention'>
@<span>{item.get('username')}</span>
</Permalink>
<Permalink
to={`/accounts/${item.get('id')}`}
href={item.get('url')}
key={item.get('id')}
className='mention'
>
@<span >{item.get('username')}</span >
</Permalink >
)).reduce((aggregate, item) => [...aggregate, item, ' '], []);
const toggleText = hidden ? <FormattedMessage id='status.show_more' defaultMessage='Show more' /> : <FormattedMessage id='status.show_less' defaultMessage='Show less' />;
const toggleText = hidden ? (<FormattedMessage
id='status.show_more'
defaultMessage='Show more'
/>) : (<FormattedMessage
id='status.show_less'
defaultMessage='Show less'
/>);
if (hidden) {
mentionsPlaceholder = <div>{mentionLinks}</div>;
mentionsPlaceholder = <div >{mentionLinks}</div >;
}
return (
<div className={classNames} ref={this.setRef} tabIndex='0' style={directionStyle} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp}>
<div
className={classNames}
ref={this.setRef}
tabIndex='0'
style={directionStyle}
onMouseDown={this.handleMouseDown}
onMouseUp={this.handleMouseUp}
>
<p style={{ marginBottom: hidden && status.get('mentions').isEmpty() ? '0px' : null }}>
<span dangerouslySetInnerHTML={spoilerContent} />
{' '}

View File

@ -21,6 +21,10 @@ import { length } from 'stringz';
import { countableText } from '../util/counter';
import Icon from 'mastodon/components/icon';
// import elephantUIPlane from '../../../images/elephant_ui_plane.svg';
// import { mascot } from '../../initial_state';
const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
const messages = defineMessages({

View File

@ -4,35 +4,34 @@ import NavigationContainer from './containers/navigation_container';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { mountCompose, unmountCompose } from '../../actions/compose';
import { changeComposing, mountCompose, unmountCompose } from '../../actions/compose';
import { Link } from 'react-router-dom';
import { injectIntl, defineMessages } from 'react-intl';
import { defineMessages, injectIntl } from 'react-intl';
import SearchContainer from './containers/search_container';
import Motion from '../ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import SearchResultsContainer from './containers/search_results_container';
import { changeComposing } from '../../actions/compose';
import { openModal } from 'mastodon/actions/modal';
import elephantUIPlane from '../../../images/elephant_ui_plane.svg';
import cipherblissLogo from '../../../images/logo_cipherbliss.png';
import { mascot } from '../../initial_state';
import Icon from 'mastodon/components/icon';
import { logOut } from 'mastodon/utils/log_out';
const messages = defineMessages({
start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
start : { id: 'getting_started.heading', defaultMessage: 'Getting started' },
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
public: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new toot' },
public : { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
community : { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
preferences : { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
logout : { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
compose : { id: 'navigation_bar.compose', defaultMessage: 'Compose new toot' },
logoutMessage: { id: 'confirmations.logout.message', defaultMessage: 'Are you sure you want to log out?' },
logoutConfirm: { id: 'confirmations.logout.confirm', defaultMessage: 'Log out' },
});
const mapStateToProps = (state, ownProps) => ({
columns: state.getIn(['settings', 'columns']),
columns : state.getIn(['settings', 'columns']),
showSearch: ownProps.multiColumn ? state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']) : ownProps.isSearchPage,
});
@ -41,15 +40,15 @@ export default @connect(mapStateToProps)
class Compose extends React.PureComponent {
static propTypes = {
dispatch: PropTypes.func.isRequired,
columns: ImmutablePropTypes.list.isRequired,
multiColumn: PropTypes.bool,
showSearch: PropTypes.bool,
dispatch : PropTypes.func.isRequired,
columns : ImmutablePropTypes.list.isRequired,
multiColumn : PropTypes.bool,
showSearch : PropTypes.bool,
isSearchPage: PropTypes.bool,
intl: PropTypes.object.isRequired,
intl : PropTypes.object.isRequired,
};
componentDidMount () {
componentDidMount() {
const { isSearchPage } = this.props;
if (!isSearchPage) {
@ -57,7 +56,7 @@ class Compose extends React.PureComponent {
}
}
componentWillUnmount () {
componentWillUnmount() {
const { isSearchPage } = this.props;
if (!isSearchPage) {
@ -72,23 +71,23 @@ class Compose extends React.PureComponent {
e.stopPropagation();
dispatch(openModal('CONFIRM', {
message: intl.formatMessage(messages.logoutMessage),
confirm: intl.formatMessage(messages.logoutConfirm),
message : intl.formatMessage(messages.logoutMessage),
confirm : intl.formatMessage(messages.logoutConfirm),
onConfirm: () => logOut(),
}));
return false;
}
};
onFocus = () => {
this.props.dispatch(changeComposing(true));
}
};
onBlur = () => {
this.props.dispatch(changeComposing(false));
}
};
render () {
render() {
const { multiColumn, showSearch, isSearchPage, intl } = this.props;
let header = '';
@ -97,51 +96,126 @@ class Compose extends React.PureComponent {
const { columns } = this.props;
header = (
<nav className='drawer__header'>
<Link to='/getting-started' className='drawer__tab' title={intl.formatMessage(messages.start)} aria-label={intl.formatMessage(messages.start)}><Icon id='bars' fixedWidth /></Link>
<Link
to='/getting-started'
className='drawer__tab'
title={intl.formatMessage(messages.start)}
aria-label={intl.formatMessage(messages.start)}
><Icon
id='bars'
fixedWidth
/></Link >
{!columns.some(column => column.get('id') === 'HOME') && (
<Link to='/timelines/home' className='drawer__tab' title={intl.formatMessage(messages.home_timeline)} aria-label={intl.formatMessage(messages.home_timeline)}><Icon id='home' fixedWidth /></Link>
<Link
to='/timelines/home'
className='drawer__tab'
title={intl.formatMessage(messages.home_timeline)}
aria-label={intl.formatMessage(messages.home_timeline)}
><Icon
id='home'
fixedWidth
/></Link >
)}
{!columns.some(column => column.get('id') === 'NOTIFICATIONS') && (
<Link to='/notifications' className='drawer__tab' title={intl.formatMessage(messages.notifications)} aria-label={intl.formatMessage(messages.notifications)}><Icon id='bell' fixedWidth /></Link>
<Link
to='/notifications'
className='drawer__tab'
title={intl.formatMessage(messages.notifications)}
aria-label={intl.formatMessage(messages.notifications)}
><Icon
id='bell'
fixedWidth
/></Link >
)}
{!columns.some(column => column.get('id') === 'COMMUNITY') && (
<Link to='/timelines/public/local' className='drawer__tab' title={intl.formatMessage(messages.community)} aria-label={intl.formatMessage(messages.community)}><Icon id='users' fixedWidth /></Link>
<Link
to='/timelines/public/local'
className='drawer__tab'
title={intl.formatMessage(messages.community)}
aria-label={intl.formatMessage(messages.community)}
><Icon
id='users'
fixedWidth
/></Link >
)}
{!columns.some(column => column.get('id') === 'PUBLIC') && (
<Link to='/timelines/public' className='drawer__tab' title={intl.formatMessage(messages.public)} aria-label={intl.formatMessage(messages.public)}><Icon id='globe' fixedWidth /></Link>
<Link
to='/timelines/public'
className='drawer__tab'
title={intl.formatMessage(messages.public)}
aria-label={intl.formatMessage(messages.public)}
><Icon
id='globe'
fixedWidth
/></Link >
)}
<a href='/settings/preferences' className='drawer__tab' title={intl.formatMessage(messages.preferences)} aria-label={intl.formatMessage(messages.preferences)}><Icon id='cog' fixedWidth /></a>
<a href='/auth/sign_out' className='drawer__tab' title={intl.formatMessage(messages.logout)} aria-label={intl.formatMessage(messages.logout)} onClick={this.handleLogoutClick}><Icon id='sign-out' fixedWidth /></a>
</nav>
<a
href='/settings/preferences'
className='drawer__tab'
title={intl.formatMessage(messages.preferences)}
aria-label={intl.formatMessage(messages.preferences)}
><Icon
id='cog'
fixedWidth
/></a >
<a
href='/auth/sign_out'
className='drawer__tab'
title={intl.formatMessage(messages.logout)}
aria-label={intl.formatMessage(messages.logout)}
onClick={this.handleLogoutClick}
><Icon
id='sign-out'
fixedWidth
/></a >
</nav >
);
}
return (
<div className='drawer' role='region' aria-label={intl.formatMessage(messages.compose)}>
<div
className='drawer'
role='region'
aria-label={intl.formatMessage(messages.compose)}
>
{header}
{(multiColumn || isSearchPage) && <SearchContainer /> }
{(multiColumn || isSearchPage) && <SearchContainer />}
<div className='drawer__pager'>
{!isSearchPage && <div className='drawer__inner' onFocus={this.onFocus}>
{!isSearchPage && <div
className='drawer__inner'
onFocus={this.onFocus}
>
<NavigationContainer onClose={this.onBlur} />
<ComposeFormContainer />
<div className='drawer__inner__mastodon'>
<img alt='' draggable='false' src={mascot || elephantUIPlane} />
</div>
</div>}
<img
className='cipherbliss_logo'
src={mascot || cipherblissLogo}
alt='logo'
/>
{/*<img alt='' draggable='false' src={mascot || elephantUIPlane} />*/}
</div >
</div >}
<Motion defaultStyle={{ x: isSearchPage ? 0 : -100 }} style={{ x: spring(showSearch || isSearchPage ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
<Motion
defaultStyle={{ x: isSearchPage ? 0 : -100 }}
style={{ x: spring(showSearch || isSearchPage ? 0 : -100, { stiffness: 210, damping: 20 }) }}
>
{({ x }) => (
<div className='drawer__inner darker' style={{ transform: `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}>
<div
className='drawer__inner darker'
style={{ transform: `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}
>
<SearchResultsContainer />
</div>
</div >
)}
</Motion>
</div>
</div>
</Motion >
</div >
</div >
);
}

View File

@ -28,8 +28,7 @@ class AccountAuthorize extends ImmutablePureComponent {
const { intl, account, onAuthorize, onReject } = this.props;
const content = { __html: account.get('note_emojified') };
const fields = account.get('fields');
const fields = account.get('fields');
return (
<div className='account-authorize__wrapper'>
<div className='account-authorize'>
@ -46,7 +45,7 @@ class AccountAuthorize extends ImmutablePureComponent {
</Permalink >
<div className='more'>
{account.get('remote_url')}
</div>
</div >
<div
className='account__header__content'
@ -85,7 +84,8 @@ class AccountAuthorize extends ImmutablePureComponent {
to={`/accounts/${account.get('id')}/followers`}
title={intl.formatNumber(account.get('followers_count'))}
>
<strong >{(account.get('followers_count'))}</strong > <FormattedMessage
<strong >{(account.get('followers_count'))}</strong >
<FormattedMessage
id='account.followers'
defaultMessage='Followers'
/>
@ -94,16 +94,21 @@ class AccountAuthorize extends ImmutablePureComponent {
</span >
<div className='account--panel'>
<div className='account--panel__button'><IconButton
title={intl.formatMessage(messages.authorize)}
icon='check'
onClick={onAuthorize}
/></div >
<div className='account--panel__button'><IconButton
title={intl.formatMessage(messages.reject)}
icon='times'
onClick={onReject}
/></div >
<div className='account--panel__button text-center'>
<IconButton
title={intl.formatMessage(messages.authorize)}
size='50'
icon='check'
onClick={onAuthorize}
/>
</div >
<div className='account--panel__button text-center'>
<IconButton
title={intl.formatMessage(messages.reject)}
size='50'
icon='times'
onClick={onReject}
/></div >
</div >
</div >
);

View File

@ -1,3 +1,8 @@
.columns-area__panels {
background: url('../images/elephant_ui_plane.svg') no-repeat left bottom fixed, url('../images/logo_cipherbliss.png') no-repeat right bottom fixed;
}
.status__content {
min-height: 5em;
}
@ -21,11 +26,12 @@
display: inline-block;
}
.fa{
&:hover{
.fa {
&:hover {
color: $gold-star;
}
}
a {
display: inline-block;
padding: .5em;
@ -38,7 +44,8 @@
&:visited {
color: #528dc8;
}
&:hover{
&:hover {
color: $gold-star;
}
@ -61,10 +68,14 @@
.compose-form {
.reply-indicator {
display: none;
display: block;
}
}
.autosuggest-textarea__textarea{
color: #528dc8;
}
.account-authorize--more-data {
padding: 1em;
color: white;
@ -77,18 +88,51 @@
}
}
.account__relationship{
button{
.account__relationship {
button {
width: 10em;
height: 3em;
}
}
.account--panel {
margin-top: 1em;
}
.account--panel__button {
padding: 1em;
button {
display: block;
}
}
.status__content__read-more-button {
.fa{
float:left;
}
.see-more {
opacity: 0;
transition: opacity ease 0.2s;
float:left;
margin-left: 1em;
}
&:hover .see-more{
display: block;
opacity: 1;
}
}
.dropdown-menu__item{
.fa{
margin-right:1em;
}
}
@media all and (max-width: 600px) {
.columns-area__panels {
background: none;
}
}