Styling and autosuggest fixes for #293

This commit is contained in:
kibigo! 2018-01-05 20:04:13 -08:00
parent 8bf9d9362a
commit ad10a80a99
10 changed files with 128 additions and 133 deletions

View File

@ -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'>

View File

@ -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,
};

View File

@ -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 : ''}`}>

View File

@ -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,

View File

@ -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,
}; };

View File

@ -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);

View File

@ -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'
> >

View File

@ -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 {

View File

@ -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,