forked from treehouse/mastodon
Styling and autosuggest fixes for #293
parent
8bf9d9362a
commit
ad10a80a99
|
@ -105,10 +105,22 @@ export default class Account extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return small ? (
|
return small ? (
|
||||||
<div className='account small'>
|
<Permalink
|
||||||
<div className='account__avatar-wrapper'><Avatar account={account} size={18} /></div>
|
className='account small'
|
||||||
<DisplayName account={account} />
|
href={account.get('url')}
|
||||||
|
to={`/accounts/${account.get('id')}`}
|
||||||
|
>
|
||||||
|
<div className='account__avatar-wrapper'>
|
||||||
|
<Avatar
|
||||||
|
account={account}
|
||||||
|
size={24}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<DisplayName
|
||||||
|
account={account}
|
||||||
|
inline
|
||||||
|
/>
|
||||||
|
</Permalink>
|
||||||
) : (
|
) : (
|
||||||
<div className='account'>
|
<div className='account'>
|
||||||
<div className='account__wrapper'>
|
<div className='account__wrapper'>
|
||||||
|
|
|
@ -1,28 +1,30 @@
|
||||||
|
// Package imports.
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
|
||||||
export default class DisplayName extends React.PureComponent {
|
// The component.
|
||||||
|
export default function DisplayName ({
|
||||||
static propTypes = {
|
|
||||||
account: ImmutablePropTypes.map.isRequired,
|
|
||||||
className: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const {
|
|
||||||
account,
|
account,
|
||||||
className,
|
className,
|
||||||
} = this.props;
|
inline,
|
||||||
const computedClass = classNames('display-name', className);
|
}) {
|
||||||
const displayNameHtml = { __html: account.get('display_name_html') };
|
const computedClass = classNames('display-name', { inline }, className);
|
||||||
|
|
||||||
return (
|
// The result.
|
||||||
|
return account ? (
|
||||||
<span className={computedClass}>
|
<span className={computedClass}>
|
||||||
<strong className='display-name__html' dangerouslySetInnerHTML={displayNameHtml} /> <span className='display-name__account'>@{this.props.account.get('acct')}</span>
|
<strong className='display-name__html' dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} />
|
||||||
|
{inline ? ' ' : null}
|
||||||
|
<span className='display-name__account'>@{account.get('acct')}</span>
|
||||||
</span>
|
</span>
|
||||||
);
|
) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
// Props.
|
||||||
|
DisplayName.propTypes = {
|
||||||
|
account: ImmutablePropTypes.map,
|
||||||
|
className: PropTypes.string,
|
||||||
|
inline: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
|
@ -22,7 +22,13 @@ export default class Permalink extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { href, children, className, ...other } = this.props;
|
const {
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
href,
|
||||||
|
to,
|
||||||
|
...other
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a target='_blank' href={href} onClick={this.handleClick} {...other} className={`permalink${className ? ' ' + className : ''}`}>
|
<a target='_blank' href={href} onClick={this.handleClick} {...other} className={`permalink${className ? ' ' + className : ''}`}>
|
||||||
|
|
|
@ -59,7 +59,7 @@ function mapStateToProps (state) {
|
||||||
preselectDate: state.getIn(['compose', 'preselectDate']),
|
preselectDate: state.getIn(['compose', 'preselectDate']),
|
||||||
privacy: state.getIn(['compose', 'privacy']),
|
privacy: state.getIn(['compose', 'privacy']),
|
||||||
progress: state.getIn(['compose', 'progress']),
|
progress: state.getIn(['compose', 'progress']),
|
||||||
replyAccount: inReplyTo ? state.getIn(['accounts', state.getIn(['statuses', inReplyTo, 'account'])]) : null,
|
replyAccount: inReplyTo ? state.getIn(['statuses', inReplyTo, 'account']) : null,
|
||||||
replyContent: inReplyTo ? state.getIn(['statuses', inReplyTo, 'contentHtml']) : null,
|
replyContent: inReplyTo ? state.getIn(['statuses', inReplyTo, 'contentHtml']) : null,
|
||||||
resetFileKey: state.getIn(['compose', 'resetFileKey']),
|
resetFileKey: state.getIn(['compose', 'resetFileKey']),
|
||||||
sideArm: state.getIn(['local_settings', 'side_arm']),
|
sideArm: state.getIn(['local_settings', 'side_arm']),
|
||||||
|
@ -265,7 +265,6 @@ class Composer extends React.Component {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
handleRefTextarea,
|
handleRefTextarea,
|
||||||
} = this.handlers;
|
} = this.handlers;
|
||||||
const { history } = this.context;
|
|
||||||
const {
|
const {
|
||||||
acceptContentTypes,
|
acceptContentTypes,
|
||||||
amUnlocked,
|
amUnlocked,
|
||||||
|
@ -317,7 +316,6 @@ class Composer extends React.Component {
|
||||||
<ComposerReply
|
<ComposerReply
|
||||||
account={replyAccount}
|
account={replyAccount}
|
||||||
content={replyContent}
|
content={replyContent}
|
||||||
history={history}
|
|
||||||
intl={intl}
|
intl={intl}
|
||||||
onCancel={onCancelReply}
|
onCancel={onCancelReply}
|
||||||
/>
|
/>
|
||||||
|
@ -384,11 +382,6 @@ class Composer extends React.Component {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context
|
|
||||||
Composer.contextTypes = {
|
|
||||||
history: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Props.
|
// Props.
|
||||||
Composer.propTypes = {
|
Composer.propTypes = {
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
|
@ -405,7 +398,7 @@ Composer.propTypes = {
|
||||||
preselectDate: PropTypes.instanceOf(Date),
|
preselectDate: PropTypes.instanceOf(Date),
|
||||||
privacy: PropTypes.string,
|
privacy: PropTypes.string,
|
||||||
progress: PropTypes.number,
|
progress: PropTypes.number,
|
||||||
replyAccount: ImmutablePropTypes.map,
|
replyAccount: PropTypes.string,
|
||||||
replyContent: PropTypes.string,
|
replyContent: PropTypes.string,
|
||||||
resetFileKey: PropTypes.number,
|
resetFileKey: PropTypes.number,
|
||||||
sideArm: PropTypes.string,
|
sideArm: PropTypes.string,
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
// Package imports.
|
// Package imports.
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import { defineMessages } from 'react-intl';
|
import { defineMessages } from 'react-intl';
|
||||||
|
|
||||||
// Components.
|
// Components.
|
||||||
import Avatar from 'flavours/glitch/components/avatar';
|
import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||||
import DisplayName from 'flavours/glitch/components/display_name';
|
|
||||||
import IconButton from 'flavours/glitch/components/icon_button';
|
import IconButton from 'flavours/glitch/components/icon_button';
|
||||||
|
|
||||||
// Utils.
|
// Utils.
|
||||||
|
@ -31,17 +29,6 @@ const handlers = {
|
||||||
onCancel();
|
onCancel();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Handles a click on the status's account.
|
|
||||||
handleClickAccount () {
|
|
||||||
const {
|
|
||||||
account,
|
|
||||||
history,
|
|
||||||
} = this.props;
|
|
||||||
if (history) {
|
|
||||||
history.push(`/accounts/${account.get('id')}`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// The component.
|
// The component.
|
||||||
|
@ -55,10 +42,7 @@ export default class ComposerReply extends React.PureComponent {
|
||||||
|
|
||||||
// Rendering.
|
// Rendering.
|
||||||
render () {
|
render () {
|
||||||
const {
|
const { handleClick } = this.handlers;
|
||||||
handleClick,
|
|
||||||
handleClickAccount,
|
|
||||||
} = this.handlers;
|
|
||||||
const {
|
const {
|
||||||
account,
|
account,
|
||||||
content,
|
content,
|
||||||
|
@ -76,21 +60,10 @@ export default class ComposerReply extends React.PureComponent {
|
||||||
title={intl.formatMessage(messages.cancel)}
|
title={intl.formatMessage(messages.cancel)}
|
||||||
/>
|
/>
|
||||||
{account ? (
|
{account ? (
|
||||||
<a
|
<AccountContainer
|
||||||
className='account'
|
id={account}
|
||||||
href={account.get('url')}
|
small
|
||||||
onClick={handleClickAccount}
|
|
||||||
>
|
|
||||||
<Avatar
|
|
||||||
account={account}
|
|
||||||
className='avatar'
|
|
||||||
size={24}
|
|
||||||
/>
|
/>
|
||||||
<DisplayName
|
|
||||||
account={account}
|
|
||||||
className='display_name'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
) : null}
|
) : null}
|
||||||
</header>
|
</header>
|
||||||
<div
|
<div
|
||||||
|
@ -105,9 +78,8 @@ export default class ComposerReply extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
ComposerReply.propTypes = {
|
ComposerReply.propTypes = {
|
||||||
account: ImmutablePropTypes.map,
|
account: PropTypes.string,
|
||||||
content: PropTypes.string,
|
content: PropTypes.string,
|
||||||
history: PropTypes.object,
|
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
onCancel: PropTypes.func,
|
onCancel: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,7 +32,7 @@ const handlers = {
|
||||||
|
|
||||||
// When blurring the textarea, suggestions are hidden.
|
// When blurring the textarea, suggestions are hidden.
|
||||||
handleBlur () {
|
handleBlur () {
|
||||||
//this.setState({ suggestionsHidden: true });
|
this.setState({ suggestionsHidden: true });
|
||||||
},
|
},
|
||||||
|
|
||||||
// When the contents of the textarea change, we have to pull up new
|
// When the contents of the textarea change, we have to pull up new
|
||||||
|
@ -57,7 +57,7 @@ const handlers = {
|
||||||
const right = value.slice(selectionStart).search(/[\s\u200B]/);
|
const right = value.slice(selectionStart).search(/[\s\u200B]/);
|
||||||
const token = function () {
|
const token = function () {
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case left < 0 || /[@:]/.test(!value[left]):
|
case left < 0 || !/[@:]/.test(value[left]):
|
||||||
return null;
|
return null;
|
||||||
case right < 0:
|
case right < 0:
|
||||||
return value.slice(left);
|
return value.slice(left);
|
||||||
|
|
|
@ -24,9 +24,16 @@ const handlers = {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (onClick) {
|
if (onClick) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
e.stopPropagation(); // Prevents following account links
|
||||||
onClick(index);
|
onClick(index);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// This prevents the focus from changing, which would mess with
|
||||||
|
// our suggestion code.
|
||||||
|
handleMouseDown (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// The component.
|
// The component.
|
||||||
|
@ -40,7 +47,10 @@ export default class ComposerTextareaSuggestionsItem extends React.Component {
|
||||||
|
|
||||||
// Rendering.
|
// Rendering.
|
||||||
render () {
|
render () {
|
||||||
const { handleClick } = this.handlers;
|
const {
|
||||||
|
handleMouseDown,
|
||||||
|
handleClick,
|
||||||
|
} = this.handlers;
|
||||||
const {
|
const {
|
||||||
selected,
|
selected,
|
||||||
suggestion,
|
suggestion,
|
||||||
|
@ -51,7 +61,8 @@ export default class ComposerTextareaSuggestionsItem extends React.Component {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={computedClass}
|
className={computedClass}
|
||||||
onMouseDown={handleClick}
|
onMouseDown={handleMouseDown}
|
||||||
|
onClickCapture={handleClick} // Jumps in front of contents
|
||||||
role='button'
|
role='button'
|
||||||
tabIndex='0'
|
tabIndex='0'
|
||||||
>
|
>
|
||||||
|
|
|
@ -52,22 +52,7 @@
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
& > .account {
|
& > .account.small { color: $ui-base-color }
|
||||||
& > .avatar {
|
|
||||||
float: left;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .display_name {
|
|
||||||
color: $ui-base-color;
|
|
||||||
display: block;
|
|
||||||
padding-right: 25px;
|
|
||||||
max-width: 100%;
|
|
||||||
line-height: 24px;
|
|
||||||
text-decoration: none;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .cancel {
|
& > .cancel {
|
||||||
float: right;
|
float: right;
|
||||||
|
@ -87,13 +72,6 @@
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
}
|
|
||||||
|
|
||||||
.emojione {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin: -5px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
@ -117,6 +95,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.emojione {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin: -5px 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.composer--textarea {
|
.composer--textarea {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
@ -175,6 +160,7 @@
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
|
overflow: hidden;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
|
@ -191,6 +177,12 @@
|
||||||
height: 18px;
|
height: 18px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& > .account.small {
|
||||||
|
.display-name {
|
||||||
|
& > span { color: lighten($ui-base-color, 36%) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.composer--upload_form {
|
.composer--upload_form {
|
||||||
|
|
|
@ -745,6 +745,8 @@
|
||||||
.account {
|
.account {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
.account__display-name {
|
.account__display-name {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
@ -762,27 +764,8 @@
|
||||||
& > .account__avatar-wrapper { margin: 0 8px 0 0 }
|
& > .account__avatar-wrapper { margin: 0 8px 0 0 }
|
||||||
|
|
||||||
& > .display-name {
|
& > .display-name {
|
||||||
display: block;
|
height: 24px;
|
||||||
padding: 0;
|
line-height: 24px;
|
||||||
height: auto;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
& > strong {
|
|
||||||
display: inline;
|
|
||||||
font-size: inherit;
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
display: inline;
|
|
||||||
color: lighten($ui-base-color, 36%);
|
|
||||||
font-size: inherit;
|
|
||||||
line-height: inherit;
|
|
||||||
|
|
||||||
&::before { content: " " }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1243,6 +1226,30 @@
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.inline {
|
||||||
|
padding: 0;
|
||||||
|
height: 18px;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 18px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
display: inline;
|
||||||
|
height: auto;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: inline;
|
||||||
|
height: auto;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status__relative-time,
|
.status__relative-time,
|
||||||
|
|
Loading…
Reference in New Issue